diff -u --recursive --new-file v2.4.7/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.4.7/linux/Documentation/Configure.help Wed Jul 25 17:10:16 2001 +++ linux/Documentation/Configure.help Tue Jul 31 14:43:29 2001 @@ -3245,6 +3245,18 @@ module will be called atyfb.o. If you want to compile it as a module, say M here and read Documentation/modules.txt. +ATI Mach64 GX display support (EXPERIMENTAL) +CONFIG_FB_ATY_GX + This options adds support for the first generation ATI Mach64 + graphics chips, i.e. the Mach64 GX and CX. Note that this support is + limited. + +ATI Mach64 CT/VT/GT/LT display support (EXPERIMENTAL) +CONFIG_FB_ATY_CT + This option adss support for ATI Mach64 graphics chips starting + with the Mach64 CT family. This includes the Mach64 VT (limited + support), GT (3D RAGE family), and LT. + ATI Rage128 display support (EXPERIMENTAL) CONFIG_FB_ATY128 This driver supports graphics boards with the ATI Rage128 chips. @@ -12471,6 +12483,33 @@ Say Y here if you would like to use hard disks under Linux which were partitioned on a Macintosh. +Windows' Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL) +CONFIG_LDM_PARTITION + Say Y here if you would like to use hard disks under Linux which + were partitioned using Windows 2000's or XP's Logical Disk Manager. + They are also known as "Dynamic Disks". + + Windows 2000 introduced the concept of Dynamic Disks to get around + the limitations of the PC's partitioning scheme. The Logical Disk + Manager allows the user to repartion a disk and create spanned, + mirrored, striped or RAID volumes, all without the need for + rebooting. + + Normal partitions are now called Basic Disks under Windows 2000 and XP. + + Technical documentation to accompany this driver is available from: + + + If unsure, say N. + +Windows' LDM extra logging +CONFIG_LDM_DEBUG + Say Y here if you would like LDM to log verbosely. This could be + helpful if the driver doesn't work as expected and you'd like to + report a bug. + + If unsure, say N. + PC BIOS (MSDOS partition tables) support CONFIG_MSDOS_PARTITION Say Y here if you would like to use hard disks under Linux which @@ -14201,6 +14240,19 @@ If unsure, say N. +Sony Vaio Programmable I/O Control Device support +CONFIG_SONYPI + This driver enables access to the Sony Programmable I/O Control Device + which can be found in many (all ?) Sony Vaio laptops. + + If you have one of those laptops, read Documentation/sonypi.txt, + and say Y or M here. + + If you want to compile the driver as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read . The module will be + called sonypi.o. + Intel Random Number Generator support CONFIG_INTEL_RNG This driver provides kernel-side support for the Random Number @@ -17493,6 +17545,19 @@ module called pms.o ( = code which can be inserted in and removed from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. + +CONFIG_VIDEO_MEYE + This is the video4linux driver for the Motion Eye camera found + in the Vaio Picturebook laptops. Please read the material in + for more information. + + If you say Y or M here, you need to say Y or M to "Sony Programmable + I/O Control Device" in the character device section. + + This driver is available as a module called meye.o ( = code + which can be inserted in and removed from the running kernel + whenever you want). If you want to compile it as a module, say M + here and read . IBM's S/390 architecture CONFIG_ARCH_S390 diff -u --recursive --new-file v2.4.7/linux/Documentation/DocBook/parportbook.tmpl linux/Documentation/DocBook/parportbook.tmpl --- v2.4.7/linux/Documentation/DocBook/parportbook.tmpl Thu Apr 12 12:05:50 2001 +++ linux/Documentation/DocBook/parportbook.tmpl Thu Aug 9 17:29:32 2001 @@ -771,6 +771,7 @@ struct pardevice *parport_open int devnum + const char *name int (*pf) void * int (*kf) diff -u --recursive --new-file v2.4.7/linux/Documentation/isdn/HiSax.cert linux/Documentation/isdn/HiSax.cert --- v2.4.7/linux/Documentation/isdn/HiSax.cert Tue Feb 15 11:40:42 2000 +++ linux/Documentation/isdn/HiSax.cert Sat Jul 28 12:12:37 2001 @@ -20,6 +20,23 @@ version and the tested hardware. Any changes to the HiSax source code may therefore affect the certification. +Additional ITU approval tests have been carried out for all generic cards +using Colognechip single chip solutions HFC-S PCI A for PCI cards as well +as HFC-S USB based USB ISDN ta adapters. +These tests included all layers 1-3 and as well all functional tests for +the layer 1. Because all hardware based on these chips are complete ISDN +solutions in one chip all cards and USB-TAs using these chips are to be +regarded as approved for those tests. Some additional electrical tests +of the layer 1 which are independant of the driver and related to a +special hardware used will be regarded as approved if at least one +solution has been tested including those electrical tests. So if cards +or tas have been completely approved for any other os, the approval +for those electrical tests is valid for linux, too. +Please send any questions regarding this drivers or approval abouts to +werner@isdn-development.de +Additional information and the type approval documents will be found +shortly on the Colognechip website www.colognechip.com + If you change the main files of the HiSax ISDN stack, the certification will become invalid. Because in most countries it is illegal to connect unapproved ISDN equipment to the public network, I have to guarantee that @@ -50,6 +67,7 @@ drivers/isdn/hisax/cert.c drivers/isdn/hisax/elsa.c drivers/isdn/hisax/diva.c +drivers/isdn/hisax/hfc_pci.c Please send any changes, bugfixes and patches to me rather than implementing them directly into the HiSax sources. diff -u --recursive --new-file v2.4.7/linux/Documentation/pci.txt linux/Documentation/pci.txt --- v2.4.7/linux/Documentation/pci.txt Tue Jul 3 17:08:18 2001 +++ linux/Documentation/pci.txt Sun Aug 5 13:12:40 2001 @@ -80,7 +80,7 @@ class_mask of the class are honored during the comparison. driver_data Data private to the driver. -When the driver exits, it just calls pci_deregister_driver() and the PCI layer +When the driver exits, it just calls pci_unregister_driver() and the PCI layer automatically calls the remove hook for all devices handled by the driver. Please mark the initialization and cleanup functions where appropriate diff -u --recursive --new-file v2.4.7/linux/Documentation/s390/CommonIO linux/Documentation/s390/CommonIO --- v2.4.7/linux/Documentation/s390/CommonIO Wed Dec 31 16:00:00 1969 +++ linux/Documentation/s390/CommonIO Wed Jul 25 14:12:01 2001 @@ -0,0 +1,124 @@ +S/390 common I/O-Layer - command line parameters and /proc entries +================================================================== + +Command line parameters +----------------------- + +* cio_msg = yes | no + + Determines whether information on found devices and sensed device + characteristics should be shown during startup, i. e. messages of the types + "Detected device 4711 on subchannel 42" and "SenseID: Device 4711 reports: ...". + + Default is off. + + +* cio_notoper_msg = yes | no + + Determines whether messages of the type "Device 4711 became 'not operational'" + should be shown during startup; after startup, they will always be shown. + + Default is on. + + +* cio_ignore = , , ... + + The given device numbers will be ignored by the common I/O-layer; no detection + and device sensing will be done on any of those devices. The subchannel to + which the device in question is attached will be treated as if no device was + attached. + + An ignored device can be un-ignored later; see the "/proc entries"-section for + details. + + The device numbers must be given hexadecimal. + + For example, + cio_ignore=0x23-0x42,0x4711 + will ignore all devices with device numbers ranging from 23 to 42 and the + device with device number 4711, if detected. + + By default, no devices are ignored. + + +* cio_proc_devinfo = yes | no + + Determines whether the entries under /proc/deviceinfo/ (see below) should be + created. Since there are problems with systems with many devices attached, I + made it configurable. + + Until the problems are dealt with, default is off. + + +/proc entries +------------- + +* /proc/subchannels + + Shows for each subchannel + - device number + - device type/model and if applicable control unit type/model + - whether the device is in use + - path installed mask, path available mask, path operational mask and last + path used mask + - the channel path IDs (chpids) + + +* /proc/deviceinfo/ + + Shows in subdirectories for each device some characteristics: + - /proc/deviceinfo//chpids: + the channel path IDs + - /proc/deviceinfo//in_use: + whether the device is in use + - /proc/deviceinfo//sensedata: + the device type/model and if applicable control unit type/model of the + device + + NOTE: Since the number of inodes which can be dynamically allocated by procfs + is limited, device entries will only be created up to a magic number of + devices. The kernel will utter a warning that not all entries can be + created. In this case, you shouldn't use "cio_proc_devinfo=yes" (see + above). + +* /proc/cio_ignore + + Lists the ranges of device numbers which are ignored by common I/O. + + You can un-ignore certain or all devices by piping to /proc/cio_ignore. + "free all" will un-ignore all ignored devices, + "free , , ..." will un-ignore the specified devices. + + For example, if devices 23 to 42 and 4711 are ignored, + - echo free 0x30-0x32 > /proc/cio_ignore + will un-ignore devices 30 to 32 and will leave devices 23 to 2F, 33 to 42 + and 4711 ignored; + - echo free 0x41 > /proc/cio_ignore will furthermore un-ignore device 41; + - echo free all > /proc/cio_ignore will un-ignore all remaining ignored + devices. + + When a device is un-ignored, device recognition and sensing is performed and + the device driver will be notified if possible, so the device will become + available to the system. + + +* /proc/s390dbf/cio_*/ (S/390 debug feature) + + Some views generated by the debug feature to hold various debug outputs. + + - /proc/s390dbf/cio_crw/sprintf + Messages from the processing of pending channel report words (machine check + handling), which will also show when CONFIG_DEBUG_CRW is defined. + + - /proc/s390dbf/cio_msg/sprintf + Various debug messages from the common I/O-layer; generally, messages which + will also show when CONFIG_DEBUG_IO is defined. + + - /proc/s390dbf/cio_trace/hex_ascii + Logs the calling of functions in the common I/O-layer and, if applicable, + which subchannel they were called for. + + The level of logging can be changed to be more or less verbose by piping to + /proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on + the S/390 debug feature (Documentation/s390/s390dbf.txt) for details. + diff -u --recursive --new-file v2.4.7/linux/Documentation/s390/Debugging390.txt linux/Documentation/s390/Debugging390.txt --- v2.4.7/linux/Documentation/s390/Debugging390.txt Sun May 20 12:11:38 2001 +++ linux/Documentation/s390/Debugging390.txt Wed Jul 25 14:12:01 2001 @@ -1,5 +1,5 @@ - Debugging on Linux for s/390 & zSeries + Debugging on Linux for s/390 & z/Architecture by Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation @@ -8,7 +8,7 @@ Overview of Document: ===================== This document is intended to give an good overview of how to debug -Linux for s/390 & zSeries it isn't intended as a complete reference & not a +Linux for s/390 & z/Architecture it isn't intended as a complete reference & not a tutorial on the fundamentals of C & assembly, it dosen't go into 390 IO in any detail. It is intended to compliment the documents in the reference section below & any other worthwhile references you get. @@ -21,46 +21,46 @@ ======== Register Set Address Spaces on Intel Linux -Address Spaces on Linux for s/390 & zSeries -The Linux for s/390 & zSeries Kernel Task Structure -Register Usage & Stackframes on Linux for s/390 & zSeries +Address Spaces on Linux for s/390 & z/Architecture +The Linux for s/390 & z/Architecture Kernel Task Structure +Register Usage & Stackframes on Linux for s/390 & z/Architecture A sample program with comments -Compiling programs for debugging on Linux for s/390 & zSeries +Compiling programs for debugging on Linux for s/390 & z/Architecture Figuring out gcc compile errors Debugging Tools objdump strace Performance Debugging Debugging under VM -s/390 & zSeries IO Overview -Debugging IO on s/390 & zSeries under VM -GDB on s/390 & zSeries +s/390 & z/Architecture IO Overview +Debugging IO on s/390 & z/Architecture under VM +GDB on s/390 & z/Architecture Stack chaining in gdb by hand Examining core dumps ldd Debugging modules The proc file system Starting points for debugging scripting languages etc. -Tools soon to be available SysRq References +Special Thanks Register Set ============ The current architectures have the following registers. -16 General propose registers, 32 bit on s/390 64 bit on zSeries, r0-r15 or gpr0-gpr15 used for arithmetic & addressing. +16 General propose registers, 32 bit on s/390 64 bit on z/Architecture, r0-r15 or gpr0-gpr15 used for arithmetic & addressing. -16 Control registers, 32 bit on s/390 64 bit on zSeries, ( cr0-cr15 kernel usage only ) used for memory managment, +16 Control registers, 32 bit on s/390 64 bit on z/Architecture, ( cr0-cr15 kernel usage only ) used for memory managment, interrupt control,debugging control etc. -16 Access registers ( ar0-ar15 ) 32 bit on s/390 & zSeries +16 Access registers ( ar0-ar15 ) 32 bit on s/390 & z/Architecture not used by normal programs but potentially could be used as temporary storage. Their main purpose is their 1 to 1 association with general purpose registers and are used in the kernel for copying data between kernel & user address spaces. -Access register 0 ( & access register 1 on z/Series ( needs 64 bit pointer ) ) -is currently used by the pthread library as a pointer to +Access register 0 ( & access register 1 on z/Architecture ( needs 64 bit +pointer ) ) is currently used by the pthread library as a pointer to the current running threads private area. 16 64 bit floating point registers (fp0-fp15 ) IEEE & HFP floating @@ -72,7 +72,7 @@ The PSW is the most important register on the machine it -is 64 bit on s/390 & 128 bit on zSeries & serves the roles of +is 64 bit on s/390 & 128 bit on z/Architecture & serves the roles of a program counter (pc), condition code register,memory space designator. In IBM standard notation I am counting bit 0 as the MSB. It has several advantages over a normal program counter @@ -83,7 +83,7 @@ currently running at. Bit Value -s/390 zSeries +s/390 z/Architecture 0 0 Reserved ( must be 0 ) otherwise specification exception occurs. 1 1 Program Event Recording 1 PER enabled, @@ -100,7 +100,7 @@ 8-11 8-11 PSW Key used for complex memory protection mechanism not used under linux -12 12 1 on s/390 0 on zSeries +12 12 1 on s/390 0 on z/Architecture 13 13 Machine Check Mask 1=enable machine check interrupts @@ -175,15 +175,19 @@ compatible. -Prefix Page ------------ +Prefix Page(s) +-------------- This per cpu memory area is too intimately tied to the processor not to mention. -It exists between the real addresses 0-4096 on the processor & is exchanged -with a page in absolute storage by the set prefix instruction in linux'es startup. -This page different on each processor. -Bytes 0-512 ( 200 hex ) are used by the processor itself for holding such -information as exception indications & entry points for exceptions. -Bytes after 0xc00 hex are used by linux for per processor globals. +It exists between the real addresses 0-4096 on s/390 & 0-8192 z/Architecture & is exchanged +with a 1 page on s/390 or 2 pages on z/Architecture in absolute storage by the set +prefix instruction in linux'es startup. +This page is mapped to a different prefix for each processor in an SMP configuration +( assuming the os designer is sane of course :-) ). +Bytes 0-512 ( 200 hex ) on s/390 & 0-512,4096-4544,4604-5119 currently on z/Architecture +are used by the processor itself for holding such information as exception indications & +entry points for exceptions. +Bytes after 0xc00 hex are used by linux for per processor globals on s/390 & z/Architecture +( there is a gap on z/Architecure too currently between 0xc00 & 1000 which linux uses ). The closest thing to this on traditional architectures is the interrupt vector table. This is a good thing & does simplify some of the kernel coding however it means that we now cannot catch stray NULL pointers in the @@ -219,9 +223,6 @@ If using the virtual machine ( VM ) as a debugger it is quite difficult to know which user process is running as the address space you are looking at could be from any process in the run queue. -Thankfully you normally get lucky as address spaces don't overlap that & -you can recognise the code at by cross referencing with a dump made by objdump -( more about that later ). The limitation of Intels addressing technique is that the linux kernel uses a very simple real address to virtual addressing technique @@ -240,35 +241,77 @@ of our 32 bit addresses,however, we use entirely separate address spaces for the user & kernel. -This means we can support 2GB of non Extended RAM, & more -with the Extended memory managment swap device & 64 Bit -when it comes along. +This means we can support 2GB of non Extended RAM on s/390, & more +with the Extended memory managment swap device & +currently 4TB of physical memory currently on z/Architecture. -Address Spaces on Linux for S390 -================================ +Address Spaces on Linux for s/390 & z/Architecture +================================================== Our addressing scheme is as follows -Himem 0x7fffffff 2GB on s/390 ***************** **************** -2^64 bytes on zSeries * User Stack * * * - ***************** * * - * Shared Libs * * * - ***************** * * - * * * Kernel * - * User Program * * * - * Data BSS * * * - * Text * * * - * Sections * * * -0x00000000 ***************** **************** +Himem 0x7fffffff 2GB on s/390 ***************** **************** +currently 0x3ffffffffff (2^42)-1 * User Stack * * * +on z/Architecture. ***************** * * + * Shared Libs * * * + ***************** * * + * * * Kernel * + * User Program * * * + * Data BSS * * * + * Text * * * + * Sections * * * +0x00000000 ***************** **************** This also means that we need to look at the PSW problem state bit or the addressing mode to decide whether we are looking at -user or kernel space. +user or kernel space. + +Virtual Addresses on s/390 & z/Architecture +=========================================== + +A virtual address on s/390 is made up of 3 parts +The SX ( segment index, roughly corresponding to the PGD & PMD in linux terminology ) +being bits 1-11. +The PX ( page index, corresponding to the page table entry (pte) in linux terminology ) +being bits 12-19. +The remaining bits BX (the byte index are the offset in the page ) +i.e. bits 20 to 31. + +On z/Architecture in linux we currently make up an address from 4 parts. +The region index bits (RX) 0-32 we currently use bits 22-32 +The segment index (SX) being bits 33-43 +The page index (PX) being bits 44-51 +The byte index (BX) being bits 52-63 + +Notes: +1) s/390 has no PMD so the PMD is really the PGD also. +A lot of this stuff is defined in pgtable.h. + +2) Also seeing as s/390's page indexes are only 1k in size +(bits 12-19 x 4 bytes per pte ) we use 1 ( page 4k ) +to make the best use of memory by updating 4 segment indices +entries each time we mess with a PMD & use offsets +0,1024,2048 & 3072 in this page as for our segment indexes. +On z/Architecture our page indexes are now 2k in size +( bits 12-19 x 8 bytes per pte ) we do a similar trick +but only mess with 2 segment indices each time we mess with +a PMD. + +3) As z/Architecture supports upto a massive 5-level page table lookup we +can only use 3 currently on Linux ( as this is all the generic kernel +currently supports ) however this may change in future +this allows us to access ( according to my sums ) +4TB of virtual storage per process i.e. +4096*512(PTES)*1024(PMDS)*2048(PGD) = 4398046511104 bytes, +enough for another 2 or 3 of years I think :-). +to do this we use a region-third-table designation type in +our address space control registers. + -The Linux for s/390 & zSeries Kernel Task Structure -=================================================== +The Linux for s/390 & z/Architecture Kernel Task Structure +========================================================== Each process/thread under Linux for S390 has its own kernel task_struct defined in linux/include/linux/sched.h The S390 on initialisation & resuming of a process on a cpu sets @@ -287,7 +330,7 @@ * ( 4K ) * 8K aligned ************************ - zSeries + z/Architecture ************************ * 2 page kernel stack * * ( 8K ) * @@ -298,7 +341,7 @@ What this means is that we don't need to dedicate any register or global variable to point to the current running process & can retrieve it with the following -very simple construct for s/390 & one very similar for zSeries. +very simple construct for s/390 & one very similar for z/Architecture. static inline struct task_struct * get_current(void) { @@ -317,8 +360,8 @@ -Register Usage & Stackframes on Linux for s/390 & zSeries -========================================================= +Register Usage & Stackframes on Linux for s/390 & z/Architecture +================================================================= Overview: --------- This is the code that gcc produces at the top & the bottom of @@ -331,7 +374,7 @@ limited knowledge of one assembly language. It should be noted that there are some differences between the -s/390 & zSeries stack layouts as the zSeries stack layout didn't have +s/390 & z/Architecture stack layouts as the z/Architecture stack layout didn't have to maintain compatibility with older linkage formats. Glossary: @@ -367,8 +410,8 @@ The code generated by the compiler to return to the caller. frameless-function -A frameless function in Linux for s390 & zSeries is one which doesn't need -more than the register save area ( 96 bytes on s/390, 160 on zSeries ) +A frameless function in Linux for s390 & z/Architecture is one which doesn't +need more than the register save area ( 96 bytes on s/390, 160 on z/Architecture ) given to it by the caller. A frameless function never: 1) Sets up a back chain. @@ -428,8 +471,8 @@ } -s/390 & zSeries Register usage -============================== +s/390 & z/Architecture Register usage +===================================== r0 used by syscalls/assembly call-clobbered r1 used by syscalls/assembly call-clobbered r2 argument 0 / return value 0 call-clobbered @@ -449,8 +492,8 @@ f0 argument 0 / return value ( float/double ) call-clobbered f2 argument 1 call-clobbered -f4 zSeries argument 2 saved -f6 zSeries argument 3 saved +f4 z/Architecture argument 2 saved +f6 z/Architecture argument 3 saved The remaining floating points f1,f3,f5 f7-f15 are call-clobbered. @@ -479,12 +522,13 @@ area if crossing this boundary. 6) Floating point parameters are mixed with outgoing args on the outgoing args area in the order the are passed in as parameters. -7) Floating point arguments 2 & 3 are saved in the outgoing args area for zSeries +7) Floating point arguments 2 & 3 are saved in the outgoing args area for +z/Architecture Stack Frame Layout ------------------ -s/390 zSeries +s/390 z/Architecture 0 0 back chain ( a 0 here signifies end of back chain ) 4 8 eos ( end of stack, not used on Linux for S390 used in other linkage formats ) 8 16 glue used in other s/390 linkage formats for saved routine descriptors etc. @@ -598,8 +642,8 @@ stack backchain in optimised code as this also causes pipeline stalls, you have been warned. -64 bit zSeries code disassembly -------------------------------- +64 bit z/Architecture code disassembly +-------------------------------------- If you understand the stuff above you'll understand the stuff below too so I'll avoid repeating myself & just say that @@ -637,12 +681,14 @@ -Compiling programs for debugging on Linux for s/390 & zSeries -============================================================= --gdwarf2 now works & normal -g debugging works much better now +Compiling programs for debugging on Linux for s/390 & z/Architecture +==================================================================== +-gdwarf-2 now works it should be considered the default debugging +format for s/390 & z/Architecture as it is more reliable for debugging +shared libraries, normal -g debugging works much better now Thanks to the IBM java compiler developers bug reports. -This is typically done adding/appending the flags -g to the +This is typically done adding/appending the flags -g or -gdwarf-2 to the CFLAGS & LDFLAGS variables Makefile of the program concerned. If using gdb & you would like accurate displays of registers & @@ -1148,7 +1194,7 @@ -------------------------------- D G will display all the gprs Adding a extra G to all the commands is neccessary to access the full 64 bit -content in VM on zSeries obviously this isn't required for access registers +content in VM on z/Architecture obviously this isn't required for access registers as these are still 32 bit. e.g. DGG instead of DG D X will display all the control registers @@ -1251,7 +1297,7 @@ tr i pswa
Start the program, if VM drops to CP on what looks like the entry point of the main function this is most likely the process you wish to debug. -Now do a D X13 or D XG13 on zSeries. +Now do a D X13 or D XG13 on z/Architecture. On 31 bit the STD is bits 1-19 ( the STO segment table origin ) & 25-31 ( the STL segment table length ) of CR13. now type @@ -1260,7 +1306,48 @@ TR I R STD 8F32E1FF 0.7fffffff Another very useful variation is TR STORE INTO STD
+for finding out when a particular variable changes. +An alternative way of finding the STD of a currently running process +is to do the following, ( this method is more complex but +could be quite convient if you aren't updating the kernel much & +so your kernel structures will stay constant for a reasonable period of +time ). + +grep task /proc//status +from this you should see something like +task: 0f160000 ksp: 0f161de8 pt_regs: 0f161f68 +This now gives you a pointer to the task structure. +Now make CC:="s390-gcc -g" kernel/sched.s +To get the task_struct stabinfo. +( task_struct is defined in include/linux/sched.h ). +Now we want to look at +task->active_mm->pgd +on my machine the active_mm in the task structure stab is +active_mm:(4,12),672,32 +its offset is 672/8=84=0x54 +the pgd member in the mm_struct stab is +pgd:(4,6)=*(29,5),96,32 +so its offset is 96/8=12=0xc + +so we'll +hexdump -s 0xf160054 /dev/mem | more +i.e. task_struct+active_mm offset +to look at the active_mm member +f160054 0fee cc60 0019 e334 0000 0000 0000 0011 +hexdump -s 0x0feecc6c /dev/mem | more +i.e. active_mm+pgd offset +feecc6c 0f2c 0000 0000 0001 0000 0001 0000 0010 +we get something like +now do +TR I R STD 0.7fffffff +i.e. the 0x7f is added because the pgd only +gives the page table origin & we need to set the low bits +to the maximum possible segment table length. +TR I R STD 0f2c007f 0.7fffffff +on z/Architecture you'll probably need to do +TR I R STD 0.ffffffffffffffff +to set the TableType to 0x1 & the Table length to 3. @@ -1347,10 +1434,18 @@ Help for displaying ascii textstrings ------------------------------------- -As textstrings are cannot be displayed in ASCII under the VM debugger ( I love EBDIC too ) I have -written this little program which will convert a command line of hex digits to ascii text -which can be compiled under linux & you can copy the hex digits from your x3270 terminal to -your xterm if you are debugging from a linuxbox. +On the very latest VM Nucleus'es VM can now display ascii +( thanks Neale for the hint ) by doing +D TX. +e.g. +D TX0.100 + +Alternatively +============= +Under older VM debuggers ( I love EBDIC too ) you can use this little program I wrote which +will convert a command line of hex digits to ascii text which can be compiled under linux & +you can copy the hex digits from your x3270 terminal to your xterm if you are debugging +from a linuxbox. This is quite useful when looking at a parameter passed in as a text string under VM ( unless you are good at decoding ASCII in your head ). @@ -1532,8 +1627,8 @@ -s/390 & zSeries IO Overview -=========================== +s/390 & z/Architecture IO Overview +================================== I am not going to give a course in 390 IO architecture as this would take me quite a while & I'm no expert. Instead I'll give a 390 IO architecture summary for Dummies if you have @@ -1685,15 +1780,15 @@ between 2 machines. We use 2 cables under linux to do a bi-directional serial link. -Debugging IO on s/390 & zSeries under VM -========================================= +Debugging IO on s/390 & z/Architecture under VM +=============================================== Now we are ready to go on with IO tracing commands under VM A few self explanatory queries: Q OSA Q CTC -Q DISK +Q DISK ( This command is CMS specific ) Q DASD @@ -1998,9 +2093,14 @@ This is done using a the same trick described for VM p/x (*($sp+56))&0x7fffffff get the first backchain. -For zSeries do -p/x *($sp+112) i.e. replace 56 with 112 & ignore the &0x7fffffff -in the macros below. +For z/Architecture +Replace 56 with 112 & ignore the &0x7fffffff +in the macros below & do nasty casts to longs like the following +as gdb unfortunately deals with printed arguments as ints which +messes up everything. +i.e. here is a 3rd backchain dereference +p/x *(long *)(***(long ***)$sp+112) + this outputs $5 = 0x528f18 @@ -2265,6 +2365,21 @@ Some driver debugging techniques ================================ +debug feature +------------- +Some of our drivers now support a "debug feature" in +/proc/s390dbf see s390dbf.txt in the linux/Documentation directory +for more info. +e.g. +to switch on the lcs "debug feature" +echo 5 > /proc/s390dbf/lcs/level +& then after the error occured. +cat /proc/s390dbf/lcs/sprintf >/logfile +the logfile now contains some information which may help +tech support resolve a problem in the field. + + + high level debugging network drivers ------------------------------------ ifconfig is a quite useful command @@ -2339,65 +2454,10 @@ & type ? in the debugger for help. -Debugging Drivers -================= -Some of our drivers now support a debug logging feature in -/proc/s390dbf see s390dbf.txt in the linux/Documentation directory -for more info. -e.g. -to switch on lcs debugging -echo 5 > /proc/s390dbf/lcs/level -& then after the error occured. -cat /proc/s390dbf/lcs/sprintf >/logfile -the logfile now contains some information which may help -tech support resolve a problem in the field. - -If you have VM look at the chapter Debugging IO on S390 under VM. - - - - -Tools soon to be available -========================== - -Dumptool & Lcrash ------------------ -Michael Holzheu & others here at IBM have a fairly mature port of -SGI's lcrash tool which allows one to look at kernel structures in a -running kernel. - -It also complements a tool called dumptool which dumps all the kernels -memory pages & registers to either a tape or a disk. -This can be used by tech support or an ambitous end user do -post mortem debugging of a machine like gdb core dumps. - -Going into how to use this tool in detail will be explained -in other documentation supplied by IBM & the lcrash homepage -http://oss.sgi.com/projects/lkcd/. - -How they work -------------- -Lcrash is a perfectly normal application -however it requires an additional file. -It is built using a patch to the kernel source base. - - -Debugging a live system it uses /dev/mem -alternatively for post mortem debugging it uses the data -collected by dumptool. - - -Ltrace ------- -We also have a tool called ltrace in our CVS repository -no plans on a delivery date yet. -ltrace is a superset of strace in that it also allows -tracing of shared libraries calls as well as system calls, -man ltrace for more info. SysRq ===== -This is now supported by linux for s/390 & zSeries. +This is now supported by linux for s/390 & z/Architecture. To enable it do compile the kernel with Kernel Hacking -> Magic SysRq Key Enabled echo "1" > /proc/sys/kernel/sysrq. @@ -2426,14 +2486,14 @@ Various info & man pages. CMS Help on tracing commands. Linux for s/390 Elf Application Binary Interface -Linux for zSeries Elf Application Binary Interface ( Both Highly Recommended ) +Linux for z/Series Elf Application Binary Interface ( Both Highly Recommended ) z/Architecture Principles of Operation SA22-7832-00 Enterprise Systems Architecture/390 Reference Summary SA22-7209-01 & the Enterprise Systems Architecture/390 Principles of Operation SA22-7201-05 - - - - - +Special Thanks +============== +Special thanks to Neale Ferguson who maintains a much +prettier HTML version of this page at +http://penguinvm.princeton.edu/notes.html#Debug390 diff -u --recursive --new-file v2.4.7/linux/Documentation/s390/TAPE linux/Documentation/s390/TAPE --- v2.4.7/linux/Documentation/s390/TAPE Fri Feb 16 15:53:08 2001 +++ linux/Documentation/s390/TAPE Wed Jul 25 14:12:01 2001 @@ -76,10 +76,9 @@ - ensure the tape is at the beginning mt -f /dev/ntibm0 rewind -- set the blocksize of the character driver. The blocksizes 512, 1024 - and 2048 bytes are supported by ISO9660. 1024 is the default, u - which will be used here. - mt -f /dev/ntibm0 setblk 1024 +- set the blocksize of the character driver. The blocksize 2048 bytes + is commonly used on ISO9660 CD-Roms + mt -f /dev/ntibm0 setblk 2048 - write the filesystem to the character device driver mkisofs -o /dev/ntibm0 somedir @@ -88,18 +87,16 @@ mt -f /dev/ntibm0 rewind - Now you can mount your new filesystem as a block device: - mount -t iso9660 -o ro,block=1024 /dev/btibm0 /mnt + mount -t iso9660 -o ro,block=2048 /dev/btibm0 /mnt TODO List -- The backend code has to be enhanced to support error-recovery actions. - -- The seeking algorithm of the block device has to be improved to speed - things up + - Driver has to be stabelized still BUGS -There are lots of weaknesses still in the code. This is why it is EXPERIMENTAL. +This driver is considered BETA, which means some weaknesses may still +be in it. If an error occurs which cannot be handled by the code you will get a sense-data dump.In that case please do the following: diff -u --recursive --new-file v2.4.7/linux/Documentation/s390/chandev.8 linux/Documentation/s390/chandev.8 --- v2.4.7/linux/Documentation/s390/chandev.8 Wed Apr 11 19:02:27 2001 +++ linux/Documentation/s390/chandev.8 Wed Jul 25 14:12:01 2001 @@ -7,29 +7,37 @@ .SH SYNOPSIS The channel device layer is a layer to provide a consistent interface for configuration & default machine check (devices appearing & disappearing ) -handling Linux for zSeries channel devices. +handling on Linux for s/390 & z/Series channel devices. -These include among others + +s/390 & z/Series channel devices include among others .Bl -item .It lcs ( the most common ethernet/token ring/fddi standard on zSeries ) .It -ctc/escon hi speed like serial link standard on zSeries. +ctc/escon hi speed like serial link standard on s/390 & z/Series. .It claw used to talk to cisco routers. .It qeth gigabit ethernet. -.El - +.It +osad used by osa/sf to configure osa devices, e.g. to share a osa card between 2 or more vm guests. osad is just added to the channel device layer for completeness, there are no plans at the current time to write a driver to exploit this under linux. +.It These devices use two channels one read & one write for configuration & -or communication. -The motivation behind producing this layer was that there is a lot of -duplicate code among the drivers for configuration so the lcs & ctc drivers -tended to fight over 3088/08's & 3088/1F's which could be either 2216/3172 -lcs compatible devices or escons/ctc's & to resolve this fight -both device drivers had to be reconfigured rather than doing the -configuration in a single place. +or communication ( & a third channel the data channel in the case of gigabit ethernet ). +The motivation behind developing this layer was that there was a lot of +duplicate code among the channel device drivers for configuration. +Also the lcs & ctc drivers tended to fight over 3088/08's & 3088/1F's which could +be either 2216/3172 channel attached lcs compatible devices or escon/ctc pipes +between guests & to resolve this fight both device drivers had to be configured +separately, this is now simplified by doing the configuration in a single place +( the channel device layer ). + +This layer isn't invasive & it is quite okay to use channel drivers +which don't use the channel device layer in conjunction with +drivers which do. +.El .SH DESCRIPTION The current setup can be read from /proc/chandev @@ -37,30 +45,65 @@ .Bl -enum .It Piping to /proc/chandev. +e.g. echo reprobe >/proc/chandev +will cause uninitialised channel devices to be probed. .It -Entering them into /etc/chandev.conf comments are prefixed #. +Entering them into /etc/chandev.conf comments are prefixed with #. .It Or from the boot command line using the 'chandev=' keyword +e.g. chandev=noauto,0x0,0x480d;noauto,0x4810,0xffff +will allow only devno's 0x480e & 0x480f to be autodetected. .El .Bl -item .It -Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. The script /bin/chandev will be called automatically on startup or a machine check of a device as follows. -/bin/chandev . -The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script. +Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. To be consistent with other hotpluggable architectures the script pointed to /proc/sys/kernel/hotplug (normally /sbin/hotplug) will be called automatically on startup or a machine check of a device as follows. +/sbin/hotplug chandev . +The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script, here is a sample script which starts devices as they become available. .It #!/bin/bash .It exec >/dev/console 2>&1 0>&1 +.It +# Uncomment line below for debugging. +.It +# echo $* +.It +if [ "$1" = "chandev" ] && [ "$2" = "start" ] +.It +then +.It + shift 2 +.It + while [ "$1" != "" ] && [ "$1" != "machine_check" ] +.It + do +.It + isup=`ifconfig $1 2>/dev/null | grep UP` +.It + if [ "$isup" = "" ] +.It + then +.It + ifup $1 +.It + fi +.It + shift +.It + done +.It +fi +.It +.It +e.g. if tr0 & ctc0 were starting up & eth0 & eth1 devices disappeared & eth2 got a revalidate machine check ( which is normally fully recoverable ) nearly simultainously the parameters would be. +.It +/sbin/hotplug chandev start tr0 ctc0 machine_check eth0 gone gone eth1 gone gone eth2 revalidate good +.It +This can be used for example to call /etc/rc.d/init.d/network start when a device appears & make the ipldelay kernel boot parameter obselete on native machines or recover from bad machine checks where the default machine check handling isn't adequete. The machine checks that can be presented as parameters are good not_operational no_path revalidate device_gone. Normally you wouldn't want to do anything like stop networking when a device disappears as this is hopefully temporary, I just added it to be complete. The chandev layer waits a few seconds for machine checks to settle before running /sbin/hotplug because several machine checks usually happen at once & the forked scripts would possibly race against each other to shutdown & start resources at the same time & behave rather stupidly. .El -e.g. if tr0 & ctc0 were starting up & eth0 & eth1 didn't recover from a gone machine check at the same instant the parameters would be. - - -/bin/chandev start tr0 ctc0 machine_check eth0 gone gone eth1 gone gone -This can be used for example to call /etc/rc.d/init.d/network start when a device appears & make the ipldelay kernel boot parameter obselete on native machines or recover from bad machine checks where the default machine check handling isn't adequete. The machine checks that can be presented as parameters are good not_operational no_path revalidate device_gone. - valid chandev arguments are <> indicate optional parameters, | indicate a choice. .B glossary @@ -77,21 +120,49 @@ .It .Bl -item - .It -.B (ctc|escon|lcs|osad|qeth|claw), -read_devno, write_devno, , , +.B (ctc|escon|lcs|osad|qeth), +read_devno,write_devno, +.It +devif_num of -1 indicates you don't care what device interface number is chosen, omitting it indicates this is a range of devices for which you want to force to be detected as a particular type. +The data_devno field is only valid for qeth devices when not forcing a range of devices. +all parameters after & including memory_usage_in_k can be set optionally if not set they +go to default values. memory_usage_in_k ( 0 the default ) means let the driver choose,checksum_received_ip_pkts & use_hw_stats are set to false +.It +e.g. ctc0,0x7c00,0x7c01 .It -e.g. ctc0,0x7c00,0x7c01,0,0,0 +Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( default 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter. This can be used for instance to force a device if it presents bad sense data to the IO layer & thus autodetection fails. .It -Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( normally 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter. +qeth,0x7c00,0x7d00,-1,4096 +All devices between 0x7c00 & 7d00 should be detected as gigabit ethernet, let the driver use 4096k for each instance, don't care what port relative adapter number is chosen, don't checksum received ip packets & use hw stats . +.It +qeth1,0x7c00,0x7c01,0x7c02 +.It +devif_num=1,read=0x7c00,write=0x7c01,data=0x7c02, don't checksum received ip packets & use hw stats. .El .It - +.Bl -item +.B claw devif_num, +read_devno,write_devno<,memory_usage_in_k,checksum_received_ip_pkts,use_hw_stats,> +host_name,adapter_name,api_type +.It +CLAW currently is not autodetected as the host_name,adapter_name & api_type +need to be set up, possibly some convention for setting these automatically +may be contrived in the future & auto detection may be done but currently there isn't any. +The names host_name,adapter_name,api_type may be 8 upto characters in length, +host_name is the name of this host, adapter_name is the name of the adjacent host, +api_type may be name 1 to 8 chars in length API & TCPIP are common values. +The remainder of the parameters are the same as the description for other ctc escon etc. +.It +A typical setup may be +.It +claw0,0xe00,0xe01,linuxa,rs6k,TCPIP +.It +.El .Bl -item .It .B add_parms -,chan_type, +,chan_type,string .It chan_type bitfield .It @@ -99,22 +170,26 @@ .It This is for device driver specific options passed as a string to the driver not dealt with by the channel device layer it can't contain spaces. +low_devno & hi_devno are optional parameters to specify a range. +The channel device layer doesn't concatenate strings if device ranges overlap, +before passing to a device driver. .El .It .Bl -item .It .B del_parms -<,chan_type,exact_match> +<,chan_type,exact_match,lo_devno> .It This deletes some or all device driver specific options not specifying chan_type causes it to delete all the strings. exact_match=1 specifies only to remove driver parms where chan_type is exactly equal exact_match=0 specifies to remove parms where any bit matches chan_type. +lo_devno is an optional parameter the delete to only happen if lo_devno matches a lo_devno in one of the ranges. .El .It .Bl -item .It .B noauto -,- +<,lo_devno,hi_devno> .It Don't probe a range of device numbers for channel devices. .El @@ -128,7 +203,6 @@ .It e.g. a token ring read channel 0x7c00 would have an interface called tr0x7c00 this avoids name collisions on devices. .El -.El .B power user options @@ -168,7 +242,6 @@ .It .B add_model ,chan_type, cu_type, cu_model, dev_type, dev_model, max_port_no, automatic_machine_check_handling - .It Tells the channel layer to probe for the device described, -1 for any of the parameters other than chan_type & automatic_machine_check_handling is a wildcard. Set max_port_no to 0 for non lcs devices. @@ -180,18 +253,33 @@ chan_type bitfield .It ctc=0x1, escon=0x2, lcs=0x4, osad=0x8, qeth=0x10, claw=0x20 - -.It +.El .Bl -item .It .B del_model ,cu_type,cu_model,dev_type,dev_model .It --1 for any parameter is a wildcard, +-1 for any parameter is a wildcard. .El + +.Bl -item .It .B del_all_models +.It +should be obvious. +.El +.Bl -item +.It +.B non_cautious_auto_detect +.It +Tells the channel device layer to attempt to auto detect devices even if their type/model pairs don't unambigously identify the device, e.g. 3088/1F's can either be escon CTC's or channel attached 3172 lcs compatible devices. If the wrong device driver attempts to probe these channels there may be big delays on startup or even a kernel lockup, use this option with caution. +.El +.Bl -item +.It +.B cautious_auto_detect .It + See non_cautious_auto_detect this is the default. +.El .Bl -item .It .B auto_msck @@ -248,6 +336,19 @@ .It .Bl -item .It +.B unregister_probe +.It +unregisters a single probe function or all of them. +.El +.Bl -item +.It +.B unregister_probe_by_chan_type +.It +unregisters all probe functions which match the chan_type bitfield exactly, +useful if you want a configuration to survice a kernel upgrade. +.El +.Bl -item +.It .B read_conf .It Read instructions from /etc/chandev.conf. @@ -259,6 +360,16 @@ .It Don't automatically read /etc/chandev.conf on boot. .El +.Bl -item +.It +.B persist +,chan_type +.It +Force drivers modules to stay loaded even if no device is found, +this is useful for debugging & one wishes to examine debug entries in +/proc/s390dbf/ to find out why a module failed to load. +.El + .It e.g the following sequence of commands should be roughly equivalent to rebooting for channel devices. @@ -290,8 +401,8 @@ .B /proc/chandev .It cat /proc/chandev to see current options chosen. -.Iy -echo >proc/chandev to enter a new command +.It +echo >/proc/chandev to enter a new command .It .B /etc/chandev.conf .It @@ -302,7 +413,7 @@ .B 'chandev=' keyword. .It -.B /bin/chandev +.B /sbin/hotplug .It A user script/executable which is run when devices come online "appear" or go offline "disappear". diff -u --recursive --new-file v2.4.7/linux/Documentation/sound/btaudio linux/Documentation/sound/btaudio --- v2.4.7/linux/Documentation/sound/btaudio Wed Dec 31 16:00:00 1969 +++ linux/Documentation/sound/btaudio Sun Aug 5 13:15:05 2001 @@ -0,0 +1,81 @@ + +Intro +===== + +people start bugging me about this with questions, looks like I +should write up some documentation for this beast. That way I +don't have to answer that much mails I hope. Yes, I'm lazy... + + +You might have noticed that the bt878 grabber cards have actually +_two_ PCI functions: + +$ lspci +[ ... ] +00:0a.0 Multimedia video controller: Brooktree Corporation Bt878 (rev 02) +00:0a.1 Multimedia controller: Brooktree Corporation Bt878 (rev 02) +[ ... ] + +The first does video, it is backward compatible to the bt848. The second +does audio. btaudio is a driver for the second function. It's a sound +driver which can be used for recording sound (and _only_ recording, no +playback). As most TV cards come with a short cable which can be plugged +into your sound card's line-in you probably don't need this driver if all +you want to do is just watching TV... + + +Driver Status +============= + +Still somewhat experimental. The driver should work stable, i.e. it +should'nt crash your box. It might not work as expected, have bugs, +not being fully OSS API compilant, ... + + +Digital audio mode +================== + +The chip knows different modes. Right now you have to pick the one you +want to use at insmod time. Digital audio mode is the default. The +chip gives you 16 bit stereo sound with ~32 kHz sample rate. According +to the specs it should be possible to get up to 48 kHz, but I havn't +figured out yet how this works. The specs are not very verbose :-( + +Lower sample rates are possible too, but the code isn't written yet. +For now you are limited to the fixed 32 kHz. Mono works throuth, the +driver will do that in software for you. + +With my Hauppauge I get clear sound, but I got also reports saying that +digital audio mode does'nt work. Guess Hauppauge connected the msp34xx +output to the bt878's I2S digital audio input port. + + +analog mode (A/D) +================= + +You can tell the driver to use this mode with the insmod option "analog=1". +The chip has three analog inputs. Consequently you'll get a mixer device +to control these. + +The analog mode supports mono only. Both 8 + 16 bit. Both are _signed_ +int, which is uncommon for the 8 bit case. Sample rate range is 119 kHz +to 448 kHz. Yes, the number of digits is correct. The driver supports +downsampling by powers of two, so you can ask for more usual sample rates +like 44 kHz too. + +With my Hauppauge I get noisy sound on the second input (mapped to line2 +by the mixer device). Others get a useable signal on line1. + + +more hints +========== + +/me uses "sox -w -r 32000 -t ossdsp /dev/dsp2 -t ossdsp /dev/dsp" +to dump audio data from btaudio (dsp2) to es1730 (dsp,dsp1). + +Have fun, + + Gerd + +-- +Gerd Knorr diff -u --recursive --new-file v2.4.7/linux/Documentation/video4linux/bttv/CARDLIST linux/Documentation/video4linux/bttv/CARDLIST --- v2.4.7/linux/Documentation/video4linux/bttv/CARDLIST Mon Feb 19 14:43:36 2001 +++ linux/Documentation/video4linux/bttv/CARDLIST Sun Aug 5 13:15:05 2001 @@ -53,11 +53,19 @@ card=51 - Eagle Wireless Capricorn2 (bt878A) card=52 - Pinnacle PCTV Studio Pro card=53 - Typhoon TView RDS / FM Stereo - card=54 - Livetec 9415 TV + card=54 - Lifetec LT 9415 TV card=55 - BESTBUY Easy TV card=56 - FlyVideo '98/FM card=57 - GrandTec 'Grand Video Capture' card=58 - Phoebe TV Master Only (No FM) + card=59 - TV Capturer + card=60 - MM100PCTV + card=61 - AG Electronics GMV1 + card=62 - BESTBUY Easy TV (bt878) + card=63 - ATI TV-Wonder + card=64 - ATI TV-Wonder VE + card=65 - FlyVideo 2000S + card=66 - Terratec TValueRadio tuner.o type=0 - Temic PAL (4002 FH5) @@ -85,3 +93,9 @@ type=22 - Temic PAL/SECAM multi (4046 FM5) type=23 - Philips PAL_DK type=24 - Philips PAL/SECAM multi (FQ1216ME) + type=25 - LG PAL_I+FM (TAPC-I001D) + type=26 - LG PAL_I (TAPC-I701D) + type=27 - LG NTSC+FM (TPI8NSR01F) + type=28 - LG PAL_BG+FM (TPI8PSB01D) + type=29 - LG PAL_BG (TPI8PSB11D) + type=30 - Temic PAL* auto + FM (4009 FN5) diff -u --recursive --new-file v2.4.7/linux/Documentation/video4linux/bttv/Insmod-options linux/Documentation/video4linux/bttv/Insmod-options --- v2.4.7/linux/Documentation/video4linux/bttv/Insmod-options Mon Feb 19 14:43:36 2001 +++ linux/Documentation/video4linux/bttv/Insmod-options Sun Aug 5 13:15:05 2001 @@ -13,6 +13,9 @@ triton1=0/1 for Triton1 compatibility Triton1 is automatically recognized but this might also help with other chipsets + vsfx=0/1 yet another chipset bug compatibility flag + (bt878 docs mentiones via+sis, but no + specific chipsets with that problem). bigendian=n Set the endianness of the gfx framebuffer. Default is native endian. fieldnr=0/1 Count fields. Some TV descrambling software diff -u --recursive --new-file v2.4.7/linux/Documentation/video4linux/bttv/README linux/Documentation/video4linux/bttv/README --- v2.4.7/linux/Documentation/video4linux/bttv/README Mon Feb 19 14:43:36 2001 +++ linux/Documentation/video4linux/bttv/README Sun Aug 5 13:15:05 2001 @@ -21,8 +21,7 @@ CONFIG_I2C_ALGOBIT=m CONFIG_VIDEO_DEV=m -The latest bttv version is available here: - http://www.strusel007.de/linux/bttv/ +The latest bttv version is available from http://bytesex.org/bttv/ You'll find Ralphs original (mostly outdated) documentation in the ralphs-doc subdirectory. diff -u --recursive --new-file v2.4.7/linux/Documentation/video4linux/bttv/Sound-FAQ linux/Documentation/video4linux/bttv/Sound-FAQ --- v2.4.7/linux/Documentation/video4linux/bttv/Sound-FAQ Mon Feb 19 14:43:36 2001 +++ linux/Documentation/video4linux/bttv/Sound-FAQ Sun Aug 5 13:15:05 2001 @@ -109,6 +109,29 @@ in = _in_put bits of the data register, i.e. BT848_GPIO_DATA & ~BT848_GPIO_OUT_EN + + +Other elements of the tvcards array +=================================== + +If you are trying to make a new card work you might find it useful to +know what the other elements in the tvcards array are good for: + +video_inputs - # of video inputs the card has +audio_inputs - historical cruft, not used any more. +tuner - which input is the tuner +svhs - which input is svhs (all others are labled composite) +muxsel - video mux, input->registervalue mapping +pll - same as pll= insmod option +tuner_type - same as tuner= insmod option +*_modulename - hint whenever some card needs this or that audio + module loaded to work properly. + +If some config item is specified both from the tvcards array and as +insmod option, the insmod option takes precedence. + + + Good luck, Gerd @@ -117,4 +140,4 @@ PS: If you have a new working entry, mail it to me. -- -Gerd Knorr +Gerd Knorr diff -u --recursive --new-file v2.4.7/linux/MAINTAINERS linux/MAINTAINERS --- v2.4.7/linux/MAINTAINERS Wed Jul 25 17:10:17 2001 +++ linux/MAINTAINERS Tue Aug 7 08:30:50 2001 @@ -106,6 +106,13 @@ L: linux-net@vger.kernel.org S: Maintained +A2232 SERIAL BOARD DRIVER +P: Enver Haase +M: ehaase@inf.fu-berlin.de +M: A2232@gmx.net +L: linux-m68k@lists.linux-m68k.org +S: Maintained + ACENIC DRIVER P: Jes Sorensen M: jes@trained-monkey.org @@ -479,7 +486,7 @@ P: Lennert Buytenhek M: buytenh@gnu.org L: bridge@math.leidenuniv.nl -W: http://www.math.leidenuniv.nl/~buytenh/bridge +W: http://bridge.sourceforge.net/ S: Maintained ETHERTEAM 16I DRIVER @@ -606,6 +613,13 @@ P: Nils Faerber M: nils@kernelconcepts.de W: http://www.kernelconcepts.de/ +S: Maintained + +IA64 (Itanium) PLATFORM +P: David Mosberger-Tang +M: davidm@hpl.hp.com +L: linux-ia64@linuxia64.org +W: http://www.linuxia64.org/ S: Maintained IBM MCA SCSI SUBSYSTEM DRIVER diff -u --recursive --new-file v2.4.7/linux/Makefile linux/Makefile --- v2.4.7/linux/Makefile Wed Jul 25 17:10:17 2001 +++ linux/Makefile Fri Aug 10 21:06:11 2001 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 7 +SUBLEVEL = 8 EXTRAVERSION = KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -u --recursive --new-file v2.4.7/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.4.7/linux/arch/alpha/kernel/entry.S Wed Jul 25 17:10:17 2001 +++ linux/arch/alpha/kernel/entry.S Wed Jul 25 17:11:05 2001 @@ -739,9 +739,12 @@ mov $30,$17 br $1,do_switch_stack mov $30,$18 + subq $30,16,$30 + stq $26,0($30) jsr $26,do_sigsuspend - lda $30,SWITCH_STACK_SIZE($30) - br ret_from_sys_call + ldq $26,0($30) + lda $30,SWITCH_STACK_SIZE+16($30) + ret $31,($26),1 .end sys_sigsuspend .align 3 @@ -750,9 +753,12 @@ mov $30,$18 br $1,do_switch_stack mov $30,$19 + subq $30,16,$30 + stq $26,0($30) jsr $26,do_rt_sigsuspend - lda $30,SWITCH_STACK_SIZE($30) - br ret_from_sys_call + ldq $26,0($30) + lda $30,SWITCH_STACK_SIZE+16($30) + ret $31,($26),1 .end sys_rt_sigsuspend .data diff -u --recursive --new-file v2.4.7/linux/arch/cris/Makefile linux/arch/cris/Makefile --- v2.4.7/linux/arch/cris/Makefile Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/Makefile Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.19 2001/06/11 12:06:40 bjornw Exp $ +# $Id: Makefile,v 1.20 2001/07/05 10:07:58 jonashg Exp $ # cris/Makefile # # This file is included by the global makefile so that you can add your own @@ -55,7 +55,8 @@ # each others config options SUBDIRS += arch/cris/boot/rescue endif -CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o arch/cris/drivers/drivers.o +CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o +DRIVERS += arch/cris/drivers/drivers.o LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a) LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC) diff -u --recursive --new-file v2.4.7/linux/arch/cris/boot/compressed/decompress.ld linux/arch/cris/boot/compressed/decompress.ld --- v2.4.7/linux/arch/cris/boot/compressed/decompress.ld Tue Jul 3 17:08:18 2001 +++ linux/arch/cris/boot/compressed/decompress.ld Thu Jul 26 15:10:06 2001 @@ -13,7 +13,6 @@ _stext = . ; *(.text) *(.rodata) - *(.rodata.*) _etext = . ; } > dram .data : diff -u --recursive --new-file v2.4.7/linux/arch/cris/config.in linux/arch/cris/config.in --- v2.4.7/linux/arch/cris/config.in Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/config.in Thu Jul 26 15:10:06 2001 @@ -49,6 +49,10 @@ int 'DRAM size (dec, in MB)' CONFIG_ETRAX_DRAM_SIZE 8 int 'Buswidth of flash in bytes' CONFIG_ETRAX_FLASH_BUSWIDTH 2 +bool 'Use flash mirroring (for cramfs)' CONFIG_ETRAX_FLASH_MIRRORING_FOR_CRAMFS +if [ "$CONFIG_ETRAX_FLASH_MIRRORING_FOR_CRAMFS" = "y" ]; then + int ' Individual flash chip size (in MB)' CONFIG_ETRAX_FLASH_SIZE 2 +fi choice 'Product LED port' \ "Port-PA-LEDs CONFIG_ETRAX_PA_LEDS \ @@ -61,8 +65,8 @@ int ' First red LED bit' CONFIG_ETRAX_LED1R 3 int ' Second green LED bit' CONFIG_ETRAX_LED2G 4 int ' Second red LED bit' CONFIG_ETRAX_LED2R 5 - int ' Third green LED bit' CONFIG_ETRAX_LED3R 2 - int ' Third red LED bit' CONFIG_ETRAX_LED3G 2 + int ' Third green LED bit' CONFIG_ETRAX_LED3G 2 + int ' Third red LED bit' CONFIG_ETRAX_LED3R 2 fi if [ "$CONFIG_ETRAX_CSP0_LEDS" = "y" ]; then @@ -169,7 +173,7 @@ source drivers/ieee1394/Config.in -source drivers/message/i2o/Config.in +source drivers/i2o/Config.in if [ "$CONFIG_NET" = "y" ]; then mainmenu_option next_comment diff -u --recursive --new-file v2.4.7/linux/arch/cris/cris.ld linux/arch/cris/cris.ld --- v2.4.7/linux/arch/cris/cris.ld Tue Jul 3 17:08:18 2001 +++ linux/arch/cris/cris.ld Thu Jul 26 15:10:06 2001 @@ -24,7 +24,7 @@ *(.fixup) *(.text.__*) *(.rodata) - *(.rodata.*) + *(.rodata.__*) } . = ALIGN(4); /* Exception table */ @@ -56,11 +56,18 @@ ___setup_start = .; .setup.init : { *(.setup.init) } ___setup_end = .; - ___initcall_start = .; - .initcall.init : { *(.initcall.init) } - ___initcall_end = .; + .initcall.init : { + ___initcall_start = .; + *(.initcall.init); + ___initcall_end = .; + + /* We fill to the next page, so we can discard all init + pages without needing to consider what payload might be + appended to the kernel image. */ + FILL (0); + . = ALIGN (8192); + } __vmlinux_end = .; /* last address of the physical file */ - . = ALIGN(8192); ___init_end = .; __data_end = . ; /* Move to _edata ? */ diff -u --recursive --new-file v2.4.7/linux/arch/cris/drivers/eeprom.c linux/arch/cris/drivers/eeprom.c --- v2.4.7/linux/arch/cris/drivers/eeprom.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/drivers/eeprom.c Thu Jul 26 15:10:06 2001 @@ -20,6 +20,18 @@ *! in the spin-lock. *! *! $Log: eeprom.c,v $ +*! Revision 1.8 2001/06/15 13:24:29 jonashg +*! * Added verification of pointers from userspace in read and write. +*! * Made busy counter volatile. +*! * Added define for inital write delay. +*! * Removed warnings by using loff_t instead of unsigned long. +*! +*! Revision 1.7 2001/06/14 15:26:54 jonashg +*! Removed test because condition is always true. +*! +*! Revision 1.6 2001/06/14 15:18:20 jonashg +*! Kb -> kB (makes quite a difference if you don't know if you have 2k or 16k). +*! *! Revision 1.5 2001/06/14 14:39:51 jonashg *! Forgot to use name when registering the driver. *! @@ -59,6 +71,7 @@ #include #include #include +#include #include "i2c.h" #define D(x) @@ -69,6 +82,10 @@ #define EEPROM_MAJOR_NR 122 /* use a LOCAL/EXPERIMENTAL major for now */ #define EEPROM_MINOR_NR 0 +/* Empirical sane initial value of the delay, the value will be adapted to + * what the chip needs when using EEPROM_ADAPTIVE_TIMING. + */ +#define INITIAL_WRITEDELAY_US 4000 #define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */ /* This one defines how many times to try when eeprom fails. */ @@ -98,7 +115,7 @@ /* this one is to keep the read/write operations atomic */ wait_queue_head_t wait_q; - int busy; + volatile int busy; int retry_cnt_addr; /* Used to keep track of number of retries for adaptive timing adjustments */ int retry_cnt_read; @@ -114,9 +131,8 @@ static int eeprom_address(unsigned long addr); static int read_from_eeprom(char * buf, int count); -static int eeprom_write_buf(unsigned long addr, const char * buf, int count); -static int eeprom_read_buf(unsigned long addr, - char * buf, int count); +static int eeprom_write_buf(loff_t addr, const char * buf, int count); +static int eeprom_read_buf(loff_t addr, char * buf, int count); static void eeprom_disable_write_protect(void); @@ -159,7 +175,7 @@ /* * Note: Most of this probing method was taken from the printserver (5470e) - * codebase. It did not contain a way of finding the 16Kb chips + * codebase. It did not contain a way of finding the 16kB chips * (M24128 or variants). The method used here might not work * for all models. If you encounter problems the easiest way * is probably to define your model within #ifdef's, and hard- @@ -167,7 +183,7 @@ */ eeprom.size = 0; - eeprom.usec_delay_writecycles = 4000;/*MAX_WRITEDELAY_US / EEPROM_RETRIES;*/ + eeprom.usec_delay_writecycles = INITIAL_WRITEDELAY_US; eeprom.usec_delay_step = 128; eeprom.adapt_state = 0; @@ -181,7 +197,7 @@ unsigned char buf_2k_start[16]; /* Im not sure this will work... :) */ - /* assume 2Kb, if failure go for 16Kb */ + /* assume 2kB, if failure go for 16kB */ /* Test with 16kB settings.. */ /* If it's a 2kB EEPROM and we address it outside it's range * it will mirror the address space: @@ -373,17 +389,17 @@ switch(eeprom.size) { case (EEPROM_2KB): - printk("%s: " EETEXT " i2c compatible 2Kb eeprom.\n", eeprom_name); + printk("%s: " EETEXT " i2c compatible 2kB eeprom.\n", eeprom_name); eeprom.sequential_write_pagesize = 16; eeprom.select_cmd = 0xA0; break; case (EEPROM_8KB): - printk("%s: " EETEXT " i2c compatible 8Kb eeprom.\n", eeprom_name); + printk("%s: " EETEXT " i2c compatible 8kB eeprom.\n", eeprom_name); eeprom.sequential_write_pagesize = 16; eeprom.select_cmd = 0x80; break; case (EEPROM_16KB): - printk("%s: " EETEXT " i2c compatible 16Kb eeprom.\n", eeprom_name); + printk("%s: " EETEXT " i2c compatible 16kB eeprom.\n", eeprom_name); eeprom.sequential_write_pagesize = 64; eeprom.select_cmd = 0xA0; break; @@ -463,8 +479,7 @@ /* Reads data from eeprom. */ -static int eeprom_read_buf(unsigned long addr, - char * buf, int count) +static int eeprom_read_buf(loff_t addr, char * buf, int count) { struct file f; @@ -543,7 +558,7 @@ /* Writes data to eeprom. */ -static int eeprom_write_buf(unsigned long addr, const char * buf, int count) +static int eeprom_write_buf(loff_t addr, const char * buf, int count) { struct file f; @@ -561,6 +576,11 @@ int i, written, restart=1; unsigned long p; + if (verify_area(VERIFY_READ, buf, count)) + { + return -EFAULT; + } + while(eeprom.busy) { interruptible_sleep_on(&eeprom.wait_q); @@ -641,11 +661,8 @@ /* To High before */ if (eeprom.usec_delay_step > 1) { - if (eeprom.usec_delay_step > 0) - { - eeprom.usec_delay_step *= 2; - eeprom.usec_delay_step--; - } + eeprom.usec_delay_step *= 2; + eeprom.usec_delay_step--; if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step) { @@ -807,7 +824,12 @@ while( (read < count)) { - buf[read++] = i2c_inbyte(); + if (put_user(i2c_inbyte(), &buf[read++])) + { + i2c_stop(); + + return -EFAULT; + } /* * make sure we don't ack last byte or you will get very strange diff -u --recursive --new-file v2.4.7/linux/arch/cris/drivers/lpslave/e100lpslave.S linux/arch/cris/drivers/lpslave/e100lpslave.S --- v2.4.7/linux/arch/cris/drivers/lpslave/e100lpslave.S Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/drivers/lpslave/e100lpslave.S Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ - ;; $Id: e100lpslave.S,v 1.2 2001/06/11 12:50:01 olof Exp $ + ;; $Id: e100lpslave.S,v 1.3 2001/06/21 16:55:26 olof Exp $ ;; ;; Etrax100 slave network<->parport forwarder ;; @@ -98,7 +98,7 @@ move.d r0, [R_PAR1_CONFIG] - moveq IO_FIELD(R_PAR1_DELAY, setup, 1), r0 ; setup time of value * 160 + 20 + moveq IO_FIELD(R_PAR1_DELAY, setup, 0), r0 ; setup time of value * 160 + 20 == 20 ns move.d r0, [R_PAR1_DELAY] ;; we got four descriptors, that can be active at the same time: diff -u --recursive --new-file v2.4.7/linux/arch/cris/drivers/lpslave/e100lpslavenet.c linux/arch/cris/drivers/lpslave/e100lpslavenet.c --- v2.4.7/linux/arch/cris/drivers/lpslave/e100lpslavenet.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/drivers/lpslave/e100lpslavenet.c Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ -/* $Id: e100lpslavenet.c,v 1.2 2001/06/11 15:39:52 olof Exp $ +/* $Id: e100lpslavenet.c,v 1.4 2001/06/21 16:55:26 olof Exp $ * * e100lpslavenet.c: A network driver for the ETRAX 100LX slave controller. * @@ -7,6 +7,12 @@ * The outline of this driver comes from skeleton.c. * * $Log: e100lpslavenet.c,v $ + * Revision 1.4 2001/06/21 16:55:26 olof + * Minimized par port setup time to gain bandwidth + * + * Revision 1.3 2001/06/21 15:49:02 olof + * Removed setting of default MAC address + * * Revision 1.2 2001/06/11 15:39:52 olof * Clean up and sync with ethernet.c rev 1.16. Increased reset time of slave. * @@ -198,10 +204,6 @@ dev->get_stats = e100_get_stats; dev->set_multicast_list = set_multicast_list; dev->set_mac_address = e100_set_mac_address; - - /* set the default MAC address */ - - e100_set_mac_address(dev, &default_mac); /* Initialise the list of Etrax DMA-descriptors */ @@ -385,8 +387,8 @@ /* We want ECP forward mode since PAR1 is TX */ IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd); - /* Setup time of value * 160 + 20 ns == 180 ns below */ - *R_PAR1_DELAY = IO_FIELD(R_PAR1_DELAY, setup, 1); + /* Setup time of value * 160 + 20 ns == 20 ns below */ + *R_PAR1_DELAY = IO_FIELD(R_PAR1_DELAY, setup, 0); *R_PAR1_CTRL = 0; @@ -944,7 +946,6 @@ TxDescList[1].ctrl = d_eol | d_int; TxDescList[1].buf = virt_to_phys(code); - /*TxDescList[1].buf = code;*/ TxDescList[1].next = 0; /* setup the dma channel and start it */ diff -u --recursive --new-file v2.4.7/linux/arch/cris/drivers/parport.c linux/arch/cris/drivers/parport.c --- v2.4.7/linux/arch/cris/drivers/parport.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/drivers/parport.c Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ -/* $Id: parport.c,v 1.5 2001/05/09 12:38:42 johana Exp $ +/* $Id: parport.c,v 1.7 2001/06/25 16:17:30 jonashg Exp $ * * Elinux parallel port driver * NOTE! @@ -49,7 +49,7 @@ * Par0 in : DMA3 * Par1 out : DMA4 * Par1 in : DMA5 - * NOTE! par0 is hared with ser2 and par1 is shared with ser3 regarding + * NOTE! par0 is shared with ser2 and par1 is shared with ser3 regarding * DMA and DMA irq */ @@ -80,8 +80,6 @@ volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */ volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */ volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */ - const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS, input */ - volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */ /* Non DMA interrupt stuff */ unsigned long int_irq; /* R_VECT_MASK_RD */ @@ -97,15 +95,6 @@ /* ----- end of fields initialised in port_table[] below ----- */ - // struct etrax_dma_descr tr_descr; - // unsigned char tr_buf[LP_BUFFER_SIZE]; - // const unsigned char *tr_buf_curr; /* current char sent */ - // const unsigned char *tr_buf_last; /* last char in buf */ - - // int fifo_magic; /* fifo amount - bytes left in dma buffer */ - // unsigned char fifo_didmagic; /* a fifo eop has been forced */ - // volatile int tr_running; /* 1 if output is running */ - struct parport *port; /* Shadow registers */ @@ -132,8 +121,6 @@ R_DMA_CH3_CLR_INTR, R_DMA_CH3_FIRST, R_DMA_CH3_CMD, - R_DMA_CH3_STATUS, - R_DMA_CH3_HWSW, /* Non DMA interrupt stuff */ IO_BITNR(R_VECT_MASK_RD, par0), R_IRQ_MASK0_RD, @@ -161,8 +148,6 @@ R_DMA_CH5_CLR_INTR, R_DMA_CH5_FIRST, R_DMA_CH5_CMD, - R_DMA_CH5_STATUS, - R_DMA_CH5_HWSW, /* Non DMA interrupt stuff */ IO_BITNR(R_VECT_MASK_RD, par1), R_IRQ_MASK1_RD, @@ -418,7 +403,7 @@ /* ----------- Initialisation code --------------------------------- */ -static void +static void __init parport_etrax_show_parallel_version(void) { printk("ETRAX 100LX parallel port driver v1.0, (c) 2001 Axis Communications AB\n"); @@ -436,15 +421,11 @@ #define PAR1_USE_DMA 0 #endif -static void +static void __init parport_etrax_init_registers(void) { struct etrax100par_struct *info; int i; - - /* The different times below will be (value*160 + 20) ns, */ - /* i.e. 20ns-4.98us. E.g. if setup is set to 00110 (0x6), */ - /* the setup time will be (6*160+20) = 980ns. */ for (i = 0, info = port_table; i < 2; i++, info++) { #ifndef CONFIG_ETRAX_PARALLEL_PORT0 diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/Makefile linux/arch/cris/kernel/Makefile --- v2.4.7/linux/arch/cris/kernel/Makefile Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/kernel/Makefile Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.5 2001/05/15 05:10:00 hp Exp $ +# $Id: Makefile,v 1.7 2001/07/05 01:11:48 hp Exp $ # # Makefile for the linux kernel. # @@ -8,8 +8,10 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... +# These assembly files can't be assembld with -traditional, so we +# need another build rule than the one in the toplevel Makefile. .S.o: - $(CC) $(AFLAGS) -traditional -c $< -o $*.o + $(CC) $(AFLAGS) -c $< -o $*.o all: kernel.o head.o @@ -20,6 +22,7 @@ obj-$(CONFIG_ETRAX_KGDB) += kgdb.o +# This dependency isn't caught by mkdep. See entry.S. entry.o: entryoffsets.s entryoffsets.s: entryoffsets.c diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/entry.S linux/arch/cris/kernel/entry.S --- v2.4.7/linux/arch/cris/kernel/entry.S Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/kernel/entry.S Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.27 2001/05/29 11:25:27 markusl Exp $ +/* $Id: entry.S,v 1.31 2001/07/25 16:07:42 bjornw Exp $ * * linux/arch/cris/entry.S * @@ -7,6 +7,36 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: entry.S,v $ + * Revision 1.31 2001/07/25 16:07:42 bjornw + * softirq_active/mask -> softirq_pending only + * + * Revision 1.30 2001/07/05 01:03:32 hp + * - include asm/errno.h to get ENOSYS. + * - Use ENOSYS, not local constant LENOSYS; tweak comments. + * - Explain why .include, not #include is used. + * - Make oops-register-dump if watchdog bits and it's not expected. + * - Don't jsr, use jump _hard_reset_now, and skip spurious nop. + * - Use correct section attribute for section .rodata. + * - Adjust sys_ni_syscall fill number. + * + * Revision 1.29 2001/06/25 14:07:00 hp + * Fix review comment. + * * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of + * magic numbers. Add comment that -traditional must not be used. + * * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation. + * Correct and update comment. + * * Makefile (.S.o): Don't use -traditional. Add comment why the + * toplevel rule can't be used (now that there's a reason). + * + * Revision 1.28 2001/06/21 02:00:40 hp + * * entry.S: Include asm/unistd.h. + * (_sys_call_table): Use section .rodata, not .data. + * (_kernel_thread): Move from... + * * process.c: ... here. + * * entryoffsets.c (VAL): Break out from... + * (OF): Use VAL. + * (LCLONE_VM): New asmified value from CLONE_VM. + * * Revision 1.27 2001/05/29 11:25:27 markusl * In case of "spurious_interrupt", do hard_reset instead of hanging system in a loop... * @@ -130,7 +160,9 @@ #include #include #include +#include #include +#include ;; functions exported from this file @@ -151,11 +183,9 @@ .globl _sys_call_table - ;; syscall error codes - -LENOSYS = 38 - - ;; Get offsets into various structs. + ;; Get values and offsets into various structs. The file isn't + ;; suitable for consumption by the preprocessor, so don't use + ;; #include. .include "entryoffsets.s" ;; process bits for ptrace. FIXME: Should be in a header file. @@ -227,7 +257,7 @@ push r10 ; push orig_r10 clear.d [sp=sp-4] ; frametype == 0, normal stackframe - movs.w -LENOSYS,r0 + movs.w -ENOSYS,r0 move.d r0,[sp+LR10] ; put the default return value in r10 in the frame ;; check if this process is syscall-traced @@ -271,9 +301,7 @@ ;; check if any bottom halves need service - move.d _irq_stat,r10 - move.d [r10+],r0 ; softirq_active - and.d [r10],r0 ; softirq_mask + test.d [_irq_stat] ; softirq_pending bne handle_softirq nop @@ -320,8 +348,8 @@ tracesys: ;; this first invocation of syscall_trace _requires_ that - ;; LR10 in the frame contains -LENOSYS (as is set in the beginning - ;; of system_call + ;; LR10 in the frame contains -ENOSYS (as is set in the beginning + ;; of system_call). jsr _syscall_trace @@ -333,7 +361,7 @@ ;; check for sanity in the requested syscall number move.d [sp+LR9], r9 - movs.w -LENOSYS, r10 + movs.w -ENOSYS, r10 cmpu.w NR_syscalls,r9 bcc 1f lslq 2,r9 ; multiply by 4, in the delay slot @@ -344,7 +372,7 @@ ;; restore r10, r11, r12, r13, mof and srp into the needed registers - move.d [sp+LORIG_R10], r10 ; LR10 is already filled with -LENOSYS + move.d [sp+LORIG_R10], r10 ; LR10 is already filled with -ENOSYS. move.d [sp+LR11], r11 move.d [sp+LR12], r12 move.d [sp+LR13], r13 @@ -484,10 +512,72 @@ #endif _IRQ1_interrupt: -_spurious_interrupt: + +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) +;; If we receive a watchdog interrupt while it is not expected, then set +;; up a canonical frame and dump register contents before dying. + + ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!! + move brp,[sp=sp-16] ; instruction pointer and room for a fake SBFS frame + push srp + push dccr + push mof di - jsr _hard_reset_now + subq 14*4,sp + movem r13,[sp] + push r10 ; push orig_r10 + clear.d [sp=sp-4] ; frametype == 0, normal frame + +;; We don't check that we actually were bit by the watchdog as opposed to +;; an external NMI, since there is currently no handler for external NMI. + +;; We'll see this in ksymoops dumps. +Watchdog_bite: + +;; We need to extend the 3.3ms after the NMI at watchdog bite, so we have +;; time for an oops-dump over a 115k2 serial wire. Another 100ms should do. + +;; Change the watchdog key to an arbitrary 3-bit value and restart the +;; watchdog. +#define WD_INIT 2 + moveq IO_FIELD (R_WATCHDOG, key, WD_INIT), r10 + move.d R_WATCHDOG, r11 + + move.d r10,[r11] + moveq IO_FIELD (R_WATCHDOG, key, \ + IO_EXTRACT (R_WATCHDOG, key, \ + IO_MASK (R_WATCHDOG, key)) \ + ^ WD_INIT) \ + | IO_STATE (R_WATCHDOG, enable, start),r10 + move.d r10,[r11] + +;; Note that we don't do "setf m" here (or after two necessary NOPs), +;; since *not* doing that saves us from re-entrancy checks. We don't want +;; to get here again due to possible subsequent NMIs; we want the watchdog +;; to reset us. + + move.d watchdogmsg,r10 + jsr _printk + + move.d sp,r10 + jsr _show_registers + +;; This nop is here so we see the "Watchdog_bite" label in ksymoops dumps +;; rather than "_spurious_interrupt". nop +;; At this point we drop down into _spurious_interrupt, which will do a +;; hard reset. + + .section .rodata,"a" +watchdogmsg: + .ascii "Oops: bitten by watchdog\n\0" + .previous + +#endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */ + +_spurious_interrupt: + di + jump _hard_reset_now ;; this handles the case when multiple interrupts arrive at the same time ;; we jump to the first set interrupt bit in a priority fashion @@ -579,14 +669,80 @@ _hw_bp_trig_ptr: .dword _hw_bp_trigs -/* Because we compile this file with -traditional, we need to redefine - token-concatenation to the traditional trick, using an empty comment. - Normally (in other files, with ISO C as in gcc default) this is done - with the ## preprocessor operator. */ +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process (i.e. the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + * + * This *can* be done in C with an single-asm-wrapped-in-a-function, but you + * get more or less gross code. The safer you make the asm-constraints, + * the grosser the code, at least with the gcc version in cris-dist-1.13. + */ + +/* int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */ +/* r10 r11 r12 */ + + .text + .global _kernel_thread +_kernel_thread: + + /* Save ARG for later. */ + move.d r11,r13 + + /* r11 is argument 2 to clone, the flags */ + move.d r12,r11 + or.w LCLONE_VM,r11 + + /* Save FN for later. */ + move.d r10,r12 + + /* r9 contains syscall number, to sys_clone */ + movu.w __NR_clone,r9 + + /* r10 is argument 1 to clone */ + clear.d r10 + + /* call sys_clone, this will fork */ + break 13 + + /* parent or child? child returns 0 here. */ + test.d r10 + + /* jump if parent */ + bne 1f + nop /* delay slot */ + + /* set argument to function to call */ + move.d r13,r10 + + /* call specified function */ + jsr r12 + /* If we ever return from the function, something bad has happened. */ + + /* r9 is sys_exit syscall number */ + movu.w __NR_exit,r9 + + /* Give a really bad exit-value */ + moveq -1,r10 + + /* call sys_exit, killing the child */ + break 13 +1: + ret + nop /* delay slot */ + + +/* The file include/linux/linkage.h is wrong for compiling the + Linux/CRIS kernel. We currently have C symbols in the kernel (only + the kernel) prefixed with _, hence, we need to redefine SYMBOL_NAME. */ #undef SYMBOL_NAME -#define SYMBOL_NAME(X) _/**/X - +#define SYMBOL_NAME(X) _##X + + .section .rodata,"a" _sys_call_table: .long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/ .long SYMBOL_NAME(sys_exit) @@ -819,7 +975,7 @@ * been shrunk every time we add a new system call. */ - .rept NR_syscalls-221 + .rept NR_syscalls-222 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/entryoffsets.c linux/arch/cris/kernel/entryoffsets.c --- v2.4.7/linux/arch/cris/kernel/entryoffsets.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/kernel/entryoffsets.c Thu Jul 26 15:10:06 2001 @@ -18,16 +18,20 @@ #include /* Exclude everything except the assembly by wrapping it in ".if 0". */ -#undef OF -#define OF(NAME, TYPE, MEMBER) \ +#undef VAL +#define VAL(NAME, VALUE) \ void NAME ## _fun (void) \ { \ __asm__ (".endif \n" \ #NAME " = %0 \n" \ ".if 0\n" \ - : : "i" (offsetof (TYPE, MEMBER))); \ + : : "i" (VALUE)); \ } +#undef OF +#define OF(NAME, TYPE, MEMBER) \ + VAL (NAME, offsetof (TYPE, MEMBER)) + /* task_struct offsets. */ OF (LTASK_SIGPENDING, struct task_struct, sigpending) OF (LTASK_NEEDRESCHED, struct task_struct, need_resched) @@ -50,5 +54,8 @@ OF (LTHREAD_KSP, struct thread_struct, ksp) OF (LTHREAD_USP, struct thread_struct, usp) OF (LTHREAD_DCCR, struct thread_struct, dccr) + +/* linux/sched.h values - doesn't have an #ifdef __ASSEMBLY__ for these. */ +VAL (LCLONE_VM, CLONE_VM) __asm__ (".endif"); diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/head.S linux/arch/cris/kernel/head.S --- v2.4.7/linux/arch/cris/kernel/head.S Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/kernel/head.S Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.34 2001/05/15 07:08:14 hp Exp $ +/* $Id: head.S,v 1.36 2001/06/29 12:39:31 pkj Exp $ * * Head of the kernel - alter with care * @@ -7,6 +7,19 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: head.S,v $ + * Revision 1.36 2001/06/29 12:39:31 pkj + * Added support for mirroring the first flash to just below the + * second one, to make them look consecutive to cramfs. + * + * Revision 1.35 2001/06/25 14:07:00 hp + * Fix review comment. + * * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of + * magic numbers. Add comment that -traditional must not be used. + * * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation. + * Correct and update comment. + * * Makefile (.S.o): Don't use -traditional. Add comment why the + * toplevel rule can't be used (now that there's a reason). + * * Revision 1.34 2001/05/15 07:08:14 hp * Tweak "notice" to reflect that both r8 r9 are used * @@ -122,6 +135,8 @@ #include #define ASSEMBLER_MACROS_ONLY +/* The IO_* macros use the ## token concatenation operator, so + -traditional must not be used when assembling this file. */ #include #define CRAMFS_MAGIC 0x28cd3d45 @@ -165,22 +180,72 @@ ;; 1G per process with CONFIG_CRIS_LOW_MAP. #ifdef CONFIG_CRIS_LOW_MAP - move.d 0x0004b098, r0 ; kseg mappings, temporary map of 0xc0->0x40 + ; kseg mappings, temporary map of 0xc0->0x40 + move.d IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \ + | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb) \ + | IO_FIELD (R_MMU_KBASE_HI, base_9, 9) \ + | IO_FIELD (R_MMU_KBASE_HI, base_8, 8), r0 move.d r0, [R_MMU_KBASE_HI] - move.d 0x04040000, r0 ; temporary map of 0x40->0x40 and 0x00->0x00 + ; temporary map of 0x40->0x40 and 0x60->0x40 + move.d IO_FIELD (R_MMU_KBASE_LO, base_6, 4) \ + | IO_FIELD (R_MMU_KBASE_LO, base_4, 4), r0 move.d r0, [R_MMU_KBASE_LO] - move.d 0x80075c71, r0 ; mmu enable, segs c,b,9,8,6,5,4,0 segment mapped + ; mmu enable, segs e,c,b,a,6,5,4,0 segment mapped + move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ + | IO_STATE (R_MMU_CONFIG, inv_excp, enable) \ + | IO_STATE (R_MMU_CONFIG, acc_excp, enable) \ + | IO_STATE (R_MMU_CONFIG, we_excp, enable) \ + | IO_STATE (R_MMU_CONFIG, seg_f, page) \ + | IO_STATE (R_MMU_CONFIG, seg_e, seg) \ + | IO_STATE (R_MMU_CONFIG, seg_d, page) \ + | IO_STATE (R_MMU_CONFIG, seg_c, seg) \ + | IO_STATE (R_MMU_CONFIG, seg_b, seg) \ + | IO_STATE (R_MMU_CONFIG, seg_a, seg) \ + | IO_STATE (R_MMU_CONFIG, seg_9, page) \ + | IO_STATE (R_MMU_CONFIG, seg_8, page) \ + | IO_STATE (R_MMU_CONFIG, seg_7, page) \ + | IO_STATE (R_MMU_CONFIG, seg_6, seg) \ + | IO_STATE (R_MMU_CONFIG, seg_5, seg) \ + | IO_STATE (R_MMU_CONFIG, seg_4, seg) \ + | IO_STATE (R_MMU_CONFIG, seg_3, page) \ + | IO_STATE (R_MMU_CONFIG, seg_2, page) \ + | IO_STATE (R_MMU_CONFIG, seg_1, page) \ + | IO_STATE (R_MMU_CONFIG, seg_0, seg), r0 move.d r0, [R_MMU_CONFIG] #else - move.d 0x0804b000, r0 ; kseg mappings + ; kseg mappings + move.d IO_FIELD (R_MMU_KBASE_HI, base_e, 8) \ + | IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \ + | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb), r0 move.d r0, [R_MMU_KBASE_HI] - move.d 0x00040000, r0 ; temporary map of 0x40->0x40 and 0x00->0x00 + ; temporary map of 0x40->0x40 and 0x00->0x00 + move.d IO_FIELD (R_MMU_KBASE_LO, base_4, 4), r0 move.d r0, [R_MMU_KBASE_LO] - move.d 0x8007d811, r0 ; mmu enable, segs f,e,c,b,4,0 segment mapped + ; mmu enable, segs f,e,c,b,4,0 segment mapped + move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \ + | IO_STATE (R_MMU_CONFIG, inv_excp, enable) \ + | IO_STATE (R_MMU_CONFIG, acc_excp, enable) \ + | IO_STATE (R_MMU_CONFIG, we_excp, enable) \ + | IO_STATE (R_MMU_CONFIG, seg_f, seg) \ + | IO_STATE (R_MMU_CONFIG, seg_e, seg) \ + | IO_STATE (R_MMU_CONFIG, seg_d, page) \ + | IO_STATE (R_MMU_CONFIG, seg_c, seg) \ + | IO_STATE (R_MMU_CONFIG, seg_b, seg) \ + | IO_STATE (R_MMU_CONFIG, seg_a, page) \ + | IO_STATE (R_MMU_CONFIG, seg_9, page) \ + | IO_STATE (R_MMU_CONFIG, seg_8, page) \ + | IO_STATE (R_MMU_CONFIG, seg_7, page) \ + | IO_STATE (R_MMU_CONFIG, seg_6, page) \ + | IO_STATE (R_MMU_CONFIG, seg_5, page) \ + | IO_STATE (R_MMU_CONFIG, seg_4, seg) \ + | IO_STATE (R_MMU_CONFIG, seg_3, page) \ + | IO_STATE (R_MMU_CONFIG, seg_2, page) \ + | IO_STATE (R_MMU_CONFIG, seg_1, page) \ + | IO_STATE (R_MMU_CONFIG, seg_0, seg), r0 move.d r0, [R_MMU_CONFIG] #endif @@ -309,6 +374,9 @@ #else add.d 0xf0000000, r9 ; add flash start in virtual memory (cached) #endif +#ifdef CONFIG_ETRAX_FLASH_MIRRORING_FOR_CRAMFS + add.d MEM_CSE1_START-CONFIG_ETRAX_FLASH_SIZE*0x100000, r9 ; move flash start to upper mirror +#endif move.d r9, [_romfs_start] moveq 1, r0 @@ -406,26 +474,34 @@ moveq 0,r0 move.d r0,[R_EXT_DMA_0_ADDR] - move.d 0x860000,r0 ; cnt enable, word size, output, stop, size 0 + ; cnt enable, word size, output, stop, size 0 + move.d IO_STATE (R_EXT_DMA_0_CMD, cnt, enable) \ + | IO_STATE (R_EXT_DMA_0_CMD, rqpol, ahigh) \ + | IO_STATE (R_EXT_DMA_0_CMD, apol, ahigh) \ + | IO_STATE (R_EXT_DMA_0_CMD, rq_ack, burst) \ + | IO_STATE (R_EXT_DMA_0_CMD, wid, word) \ + | IO_STATE (R_EXT_DMA_0_CMD, dir, output) \ + | IO_STATE (R_EXT_DMA_0_CMD, run, stop) \ + | IO_FIELD (R_EXT_DMA_0_CMD, trf_count, 0),r0 move.d r0,[R_EXT_DMA_0_CMD] ;; reset dma4 and wait for completion - moveq 4,r0 + moveq IO_STATE (R_DMA_CH4_CMD, cmd, reset),r0 move.b r0,[R_DMA_CH4_CMD] w4u: move.b [R_DMA_CH4_CMD],r0 - and.b 7,r0 - cmp.b 4,r0 + and.b IO_MASK (R_DMA_CH4_CMD, cmd),r0 + cmp.b IO_STATE (R_DMA_CH4_CMD, cmd, reset),r0 beq w4u nop ;; reset dma5 and wait for completion - moveq 4,r0 + moveq IO_STATE (R_DMA_CH5_CMD, cmd, reset),r0 move.b r0,[R_DMA_CH5_CMD] w5u: move.b [R_DMA_CH5_CMD],r0 - and.b 7,r0 - cmp.b 4,r0 + and.b IO_MASK (R_DMA_CH5_CMD, cmd),r0 + cmp.b IO_STATE (R_DMA_CH5_CMD, cmd, reset),r0 beq w5u nop #endif @@ -434,42 +510,66 @@ moveq 0,r0 #if !defined(CONFIG_ETRAX_KGDB) && !defined(CONFIG_DMA_MEMCPY) - or.d 0x140000,r0 ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA + ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA + or.d IO_STATE (R_GEN_CONFIG, dma7, serial0) \ + | IO_STATE (R_GEN_CONFIG, dma6, serial0),r0 #endif #if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1) - or.d 0xc00000,r0 ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA + or.d IO_STATE (R_GEN_CONFIG, dma9, serial1) \ + | IO_STATE (R_GEN_CONFIG, dma8, serial1),r0 #endif #ifdef CONFIG_DMA_MEMCPY - or.d 0x003c0000,r0 ; 6/7 memory-memory DMA + ; 6/7 memory-memory DMA + or.d IO_STATE (R_GEN_CONFIG, dma7, intdma6) \ + | IO_STATE (R_GEN_CONFIG, dma6, intdma7),r0 #endif #ifdef CONFIG_ETRAX_SERIAL_PORT2 - or.d 0x2808,r0 ; DMA channels 2 and 3 to serport 2, port 2 enabled + ; DMA channels 2 and 3 to serport 2, port 2 enabled + or.d IO_STATE (R_GEN_CONFIG, dma3, serial2) \ + | IO_STATE (R_GEN_CONFIG, dma2, serial2) \ + | IO_STATE (R_GEN_CONFIG, ser2, select),r0 #endif #if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) - or.d 0x28100,r0 ; DMA channels 4 and 5 to serport 3, port 3 enabled + ; DMA channels 4 and 5 to serport 3, port 3 enabled + or.d IO_STATE (R_GEN_CONFIG, dma5, serial3) \ + | IO_STATE (R_GEN_CONFIG, dma4, serial3) \ + | IO_STATE (R_GEN_CONFIG, ser3, select),r0 #endif #if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) - or.w 0x4,r0 ; parport 0 enabled using DMA 2/3 + ; parport 0 enabled using DMA 2/3 + or.w IO_STATE (R_GEN_CONFIG, par0, select),r0 #endif #if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE) - or.w 0x80,r0 ; parport 1 enabled using DMA 4/5 + ; parport 1 enabled using DMA 4/5 + or.w IO_STATE (R_GEN_CONFIG, par1, select),r0 #endif #ifdef CONFIG_ETRAX_IDE - or.d 0x3c02,r0 ; DMA channels 2 and 3 to ATA, ATA enabled + ; DMA channels 2 and 3 to ATA, ATA enabled + or.d IO_STATE (R_GEN_CONFIG, dma3, ata) \ + | IO_STATE (R_GEN_CONFIG, dma2, ata) \ + | IO_STATE (R_GEN_CONFIG, ata, select),r0 #endif #ifdef CONFIG_ETRAX_USB_HOST_PORT1 - or.d 0x20000000,r0 ; Set the USB port 1 enable bit + ; Set the USB port 1 enable bit + or.d IO_STATE (R_GEN_CONFIG, usb1, select),r0 #endif #ifdef CONFIG_ETRAX_USB_HOST_PORT2 - or.d 0x40000000,r0 ; Set the USB port 2 enable bit + ; Set the USB port 2 enable bit + or.d IO_STATE (R_GEN_CONFIG, usb2, select),r0 #endif #ifdef CONFIG_ETRAX_USB_HOST - and.d 0xff3fffff,r0 ; Connect DMA channels 8 and 9 to USB + ; Connect DMA channels 8 and 9 to USB + and.d (~(IO_MASK (R_GEN_CONFIG, dma9) \ + | IO_MASK (R_GEN_CONFIG, dma8))) \ + | IO_STATE (R_GEN_CONFIG, dma9, usb) \ + | IO_STATE (R_GEN_CONFIG, dma8, usb),r0 #endif #ifdef CONFIG_JULIETTE - or.d 0x3c000,r0 ; DMA channels 4 and 5 to EXTDMA0, for Juliette + ; DMA channels 4 and 5 to EXTDMA0, for Juliette + or.d IO_STATE (R_GEN_CONFIG, dma5, extdma0) \ + | IO_STATE (R_GEN_CONFIG, dma4, extdma0),r0 #endif move.d r0,[_genconfig_shadow] ; init a shadow register of R_GEN_CONFIG @@ -492,17 +592,17 @@ nop #endif - moveq 4,r0 + moveq IO_STATE (R_DMA_CH8_CMD, cmd, reset),r0 move.b r0,[R_DMA_CH8_CMD] ; reset (ser1 dma out) move.b r0,[R_DMA_CH9_CMD] ; reset (ser1 dma in) w81: move.b [R_DMA_CH8_CMD],r0 ; wait for reset cycle to finish - and.b 7,r0 - cmp.b 4,r0 + and.b IO_MASK (R_DMA_CH8_CMD, cmd),r0 + cmp.b IO_STATE (R_DMA_CH8_CMD, cmd, reset),r0 beq w81 nop w91: move.b [R_DMA_CH9_CMD],r0 ; wait for reset cycle to finish - and.b 7,r0 - cmp.b 4,r0 + and.b IO_MASK (R_DMA_CH9_CMD, cmd),r0 + cmp.b IO_STATE (R_DMA_CH9_CMD, cmd, reset),r0 beq w91 nop @@ -535,46 +635,106 @@ ;; setup the serial port 0 at 115200 baud for debug purposes - moveq 0,r0 + moveq IO_STATE (R_SERIAL0_XOFF, tx_stop, enable) \ + | IO_STATE (R_SERIAL0_XOFF, auto_xoff, disable) \ + | IO_FIELD (R_SERIAL0_XOFF, xoff_char, 0),r0 move.d r0,[R_SERIAL0_XOFF] - move.b 0x99,r0 - move.b r0,[R_SERIAL0_BAUD] ; 115.2kbaud for both transmit and receive - - move.b 0x40,r0 ; rec enable + ; 115.2kbaud for both transmit and receive + move.b IO_STATE (R_SERIAL0_BAUD, tr_baud, c115k2Hz) \ + | IO_STATE (R_SERIAL0_BAUD, rec_baud, c115k2Hz),r0 + move.b r0,[R_SERIAL0_BAUD] + + ; Set up and enable the serial0 receiver. + move.b IO_STATE (R_SERIAL0_REC_CTRL, dma_err, stop) \ + | IO_STATE (R_SERIAL0_REC_CTRL, rec_enable, enable) \ + | IO_STATE (R_SERIAL0_REC_CTRL, rts_, active) \ + | IO_STATE (R_SERIAL0_REC_CTRL, sampling, middle) \ + | IO_STATE (R_SERIAL0_REC_CTRL, rec_stick_par, normal) \ + | IO_STATE (R_SERIAL0_REC_CTRL, rec_par, even) \ + | IO_STATE (R_SERIAL0_REC_CTRL, rec_par_en, disable) \ + | IO_STATE (R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit),r0 move.b r0,[R_SERIAL0_REC_CTRL] - move.b 0x40,r0 ; tr enable + ; Set up and enable the serial0 transmitter. + move.b IO_FIELD (R_SERIAL0_TR_CTRL, txd, 0) \ + | IO_STATE (R_SERIAL0_TR_CTRL, tr_enable, enable) \ + | IO_STATE (R_SERIAL0_TR_CTRL, auto_cts, disabled) \ + | IO_STATE (R_SERIAL0_TR_CTRL, stop_bits, one_bit) \ + | IO_STATE (R_SERIAL0_TR_CTRL, tr_stick_par, normal) \ + | IO_STATE (R_SERIAL0_TR_CTRL, tr_par, even) \ + | IO_STATE (R_SERIAL0_TR_CTRL, tr_par_en, disable) \ + | IO_STATE (R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit),r0 move.b r0,[R_SERIAL0_TR_CTRL] ;; setup the serial port 1 at 115200 baud for debug purposes - moveq 0,r0 + moveq IO_STATE (R_SERIAL1_XOFF, tx_stop, enable) \ + | IO_STATE (R_SERIAL1_XOFF, auto_xoff, disable) \ + | IO_FIELD (R_SERIAL1_XOFF, xoff_char, 0),r0 move.d r0,[R_SERIAL1_XOFF] - move.b 0x99,r0 - move.b r0,[R_SERIAL1_BAUD] ; 115.2kbaud for both transmit and receive - - move.b 0x40,r0 ; rec enable + ; 115.2kbaud for both transmit and receive + move.b IO_STATE (R_SERIAL1_BAUD, tr_baud, c115k2Hz) \ + | IO_STATE (R_SERIAL1_BAUD, rec_baud, c115k2Hz),r0 + move.b r0,[R_SERIAL1_BAUD] + + ; Set up and enable the serial1 receiver. + move.b IO_STATE (R_SERIAL1_REC_CTRL, dma_err, stop) \ + | IO_STATE (R_SERIAL1_REC_CTRL, rec_enable, enable) \ + | IO_STATE (R_SERIAL1_REC_CTRL, rts_, active) \ + | IO_STATE (R_SERIAL1_REC_CTRL, sampling, middle) \ + | IO_STATE (R_SERIAL1_REC_CTRL, rec_stick_par, normal) \ + | IO_STATE (R_SERIAL1_REC_CTRL, rec_par, even) \ + | IO_STATE (R_SERIAL1_REC_CTRL, rec_par_en, disable) \ + | IO_STATE (R_SERIAL1_REC_CTRL, rec_bitnr, rec_8bit),r0 move.b r0,[R_SERIAL1_REC_CTRL] - move.b 0x40,r0 ; tr enable + ; Set up and enable the serial1 transmitter. + move.b IO_FIELD (R_SERIAL1_TR_CTRL, txd, 0) \ + | IO_STATE (R_SERIAL1_TR_CTRL, tr_enable, enable) \ + | IO_STATE (R_SERIAL1_TR_CTRL, auto_cts, disabled) \ + | IO_STATE (R_SERIAL1_TR_CTRL, stop_bits, one_bit) \ + | IO_STATE (R_SERIAL1_TR_CTRL, tr_stick_par, normal) \ + | IO_STATE (R_SERIAL1_TR_CTRL, tr_par, even) \ + | IO_STATE (R_SERIAL1_TR_CTRL, tr_par_en, disable) \ + | IO_STATE (R_SERIAL1_TR_CTRL, tr_bitnr, tr_8bit),r0 move.b r0,[R_SERIAL1_TR_CTRL] #ifdef CONFIG_ETRAX_SERIAL_PORT3 ;; setup the serial port 3 at 115200 baud for debug purposes - moveq 0,r0 + moveq IO_STATE (R_SERIAL3_XOFF, tx_stop, enable) \ + | IO_STATE (R_SERIAL3_XOFF, auto_xoff, disable) \ + | IO_FIELD (R_SERIAL3_XOFF, xoff_char, 0),r0 move.d r0,[R_SERIAL3_XOFF] - move.b 0x99,r0 - move.b r0,[R_SERIAL3_BAUD] ; 115.2kbaud for both transmit and receive - - move.b 0x40,r0 ; rec enable + ; 115.2kbaud for both transmit and receive + move.b IO_STATE (R_SERIAL3_BAUD, tr_baud, c115k2Hz) \ + | IO_STATE (R_SERIAL3_BAUD, rec_baud, c115k2Hz),r0 + move.b r0,[R_SERIAL3_BAUD] + + ; Set up and enable the serial3 receiver. + move.b IO_STATE (R_SERIAL3_REC_CTRL, dma_err, stop) \ + | IO_STATE (R_SERIAL3_REC_CTRL, rec_enable, enable) \ + | IO_STATE (R_SERIAL3_REC_CTRL, rts_, active) \ + | IO_STATE (R_SERIAL3_REC_CTRL, sampling, middle) \ + | IO_STATE (R_SERIAL3_REC_CTRL, rec_stick_par, normal) \ + | IO_STATE (R_SERIAL3_REC_CTRL, rec_par, even) \ + | IO_STATE (R_SERIAL3_REC_CTRL, rec_par_en, disable) \ + | IO_STATE (R_SERIAL3_REC_CTRL, rec_bitnr, rec_8bit),r0 move.b r0,[R_SERIAL3_REC_CTRL] - move.b 0x40,r0 ; tr enable + ; Set up and enable the serial3 transmitter. + move.b IO_FIELD (R_SERIAL3_TR_CTRL, txd, 0) \ + | IO_STATE (R_SERIAL3_TR_CTRL, tr_enable, enable) \ + | IO_STATE (R_SERIAL3_TR_CTRL, auto_cts, disabled) \ + | IO_STATE (R_SERIAL3_TR_CTRL, stop_bits, one_bit) \ + | IO_STATE (R_SERIAL3_TR_CTRL, tr_stick_par, normal) \ + | IO_STATE (R_SERIAL3_TR_CTRL, tr_par, even) \ + | IO_STATE (R_SERIAL3_TR_CTRL, tr_par_en, disable) \ + | IO_STATE (R_SERIAL3_TR_CTRL, tr_bitnr, tr_8bit),r0 move.b r0,[R_SERIAL3_TR_CTRL] #endif diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/irq.c linux/arch/cris/kernel/irq.c --- v2.4.7/linux/arch/cris/kernel/irq.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/kernel/irq.c Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.15 2001/06/10 11:18:46 bjornw Exp $ +/* $Id: irq.c,v 1.17 2001/07/25 16:08:01 bjornw Exp $ * * linux/arch/cris/kernel/irq.c * @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -278,7 +279,7 @@ } irq_exit(cpu); - if (softirq_active(cpu) & softirq_mask(cpu)) + if (softirq_pending(cpu)) do_softirq(); /* unmasking and bottom half handling is done magically for us. */ @@ -422,7 +423,8 @@ void do_sigtrap(void); /* from entry.S */ void gdb_handle_breakpoint(void); /* from entry.S */ -void init_IRQ(void) +void __init +init_IRQ(void) { int i; @@ -488,7 +490,8 @@ #if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL) /* Used by other archs to show/control IRQ steering during SMP */ -void init_irq_proc(void) +void __init +init_irq_proc(void) { } #endif diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/process.c linux/arch/cris/kernel/process.c --- v2.4.7/linux/arch/cris/kernel/process.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/kernel/process.c Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.14 2001/05/29 11:27:59 markusl Exp $ +/* $Id: process.c,v 1.16 2001/06/21 02:00:40 hp Exp $ * * linux/arch/cris/kernel/process.c * @@ -8,6 +8,18 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: process.c,v $ + * Revision 1.16 2001/06/21 02:00:40 hp + * * entry.S: Include asm/unistd.h. + * (_sys_call_table): Use section .rodata, not .data. + * (_kernel_thread): Move from... + * * process.c: ... here. + * * entryoffsets.c (VAL): Break out from... + * (OF): Use VAL. + * (LCLONE_VM): New asmified value from CLONE_VM. + * + * Revision 1.15 2001/06/20 16:31:57 hp + * Add comments to describe empty functions according to review. + * * Revision 1.14 2001/05/29 11:27:59 markusl * Fixed so that hard_reset_now will do reset even if watchdog wasn't enabled * @@ -71,6 +83,15 @@ __attribute__((__section__(".data.init_task"))) = { INIT_TASK(init_task_union.task) }; +/* + * The hlt_counter, disable_hlt and enable_hlt is just here as a hook if + * there would ever be a halt sequence (for power save when idle) with + * some largish delay when halting or resuming *and* a driver that can't + * afford that delay. The hlt_counter would then be checked before + * executing the halt sequence, and the driver marks the unhaltable + * region by enable_hlt/disable_hlt. + */ + static int hlt_counter=0; void disable_hlt(void) @@ -116,52 +137,27 @@ hard_reset_now(); } -/* can't do much here... */ +/* + * Similar to machine_power_off, but don't shut off power. Add code + * here to freeze the system for e.g. post-mortem debug purpose when + * possible. This halt has nothing to do with the idle halt. + */ void machine_halt(void) { } +/* If or when software power-off is implemented, add code here. */ + void machine_power_off(void) { } /* - * This is the mechanism for creating a new kernel thread. - * - * NOTE! Only a kernel-only process(ie the swapper or direct descendants - * who haven't done an "execve()") should use this: it will work within - * a system call from a "real" process, but the process memory space will - * not be free'd until both the parent and the child have exited. - */ - -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - register long __a __asm__ ("r10"); - - __asm__ __volatile__ - ("movu.w %1,r9\n\t" /* r9 contains syscall number, to sys_clone */ - "clear.d r10\n\t" /* r10 is argument 1 to clone */ - "move.d %2,r11\n\t" /* r11 is argument 2 to clone, the flags */ - "break 13\n\t" /* call sys_clone, this will fork */ - "test.d r10\n\t" /* parent or child? child returns 0 here. */ - "bne 1f\n\t" /* jump if parent */ - "nop\n\t" /* delay slot */ - "move.d %4,r10\n\t" /* set argument to function to call */ - "jsr %5\n\t" /* call specified function */ - "movu.w %3,r9\n\t" /* r9 is sys_exit syscall number */ - "moveq -1,r10\n\t" /* Give a really bad exit-value */ - "break 13\n\t" /* call sys_exit, killing the child */ - "1:\n\t" - : "=r" (__a) - : "g" (__NR_clone), "r" (flags | CLONE_VM), "g" (__NR_exit), - "r" (arg), "r" (fn) - : "r10", "r11", "r9"); - - return __a; -} - - + * When a process does an "exec", machine state like FPU and debug + * registers need to be reset. This is a hook function for that. + * Currently we don't have any such state to reset, so this is empty. + */ void flush_thread(void) { diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/ptrace.c linux/arch/cris/kernel/ptrace.c --- v2.4.7/linux/arch/cris/kernel/ptrace.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/kernel/ptrace.c Thu Jul 26 15:10:06 2001 @@ -8,6 +8,9 @@ * Authors: Bjorn Wesen * * $Log: ptrace.c,v $ + * Revision 1.6 2001/07/25 16:08:47 bjornw + * PTRACE_ATTACH bulk moved into arch-independant code in 2.4.7 + * * Revision 1.5 2001/03/26 14:24:28 orjanf * * Changed loop condition. * * Added comment documenting non-standard ptrace behaviour. diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/setup.c linux/arch/cris/kernel/setup.c --- v2.4.7/linux/arch/cris/kernel/setup.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/kernel/setup.c Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.16 2001/05/15 01:23:13 hp Exp $ +/* $Id: setup.c,v 1.18 2001/06/28 04:47:16 hp Exp $ * * linux/arch/cris/kernel/setup.c * @@ -162,9 +162,9 @@ paging_init(); - /* we dont use a command line yet, so just let it be an empty string - to start with */ - + /* We dont use a command line yet, so just re-initialize it without + saving anything that might be there. */ + *cmdline_p = command_line; strcpy(command_line, "root=/dev/rom"); /* use the appended romdisk as root */ @@ -249,7 +249,7 @@ cpu_info[revision].flags & HAS_SCSI ? "yes" : "no", cpu_info[revision].flags & HAS_ATA ? "yes" : "no", cpu_info[revision].flags & HAS_USB ? "yes" : "no", - (loops_per_jiffy * HZ + 500) / 100000, - ((loops_per_jiffy * HZ + 500) / 1000) % 100); + (loops_per_jiffy * HZ + 500) / 500000, + ((loops_per_jiffy * HZ + 500) / 5000) % 100); } #endif /* CONFIG_PROC_FS */ diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/sys_cris.c linux/arch/cris/kernel/sys_cris.c --- v2.4.7/linux/arch/cris/kernel/sys_cris.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/kernel/sys_cris.c Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ -/* $Id: sys_cris.c,v 1.9 2001/05/30 06:20:26 markusl Exp $ +/* $Id: sys_cris.c,v 1.10 2001/06/27 21:16:15 hp Exp $ * * linux/arch/cris/kernel/sys_cris.c * @@ -42,34 +42,6 @@ error = -EFAULT; } return error; -} - -/* sys_mmap used to take a ptr to a buffer instead containing the args - * but we support syscalls with 6 arguments now - */ - -asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t offset) -{ - struct file * file = NULL; - int ret = -EBADF; - - lock_kernel(); - if (!(flags & MAP_ANONYMOUS)) { - if (!(file = fget(fd))) - goto out; - } - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - down_write(¤t->mm->mmap_sem); - ret = do_mmap(file, addr, len, prot, flags, offset); - up_write(¤t->mm->mmap_sem); - if (file) - fput(file); - out: - unlock_kernel(); - return ret; } /* common code for old and new mmaps */ diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/time.c linux/arch/cris/kernel/time.c --- v2.4.7/linux/arch/cris/kernel/time.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/kernel/time.c Thu Jul 26 15:10:06 2001 @@ -1,9 +1,9 @@ -/* $Id: time.c,v 1.6 2001/05/29 11:29:42 markusl Exp $ +/* $Id: time.c,v 1.8 2001/07/18 14:01:03 bjornw Exp $ * * linux/arch/cris/kernel/time.c * * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * Copyright (C) 1999, 2000 Axis Communications AB + * Copyright (C) 1999, 2000, 2001 Axis Communications AB * * 1994-07-02 Alan Modra * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime @@ -228,7 +228,7 @@ #define WATCHDOG_MIN_FREE_PAGES 8 -static inline void +void reset_watchdog(void) { #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) @@ -242,6 +242,18 @@ #endif } +/* stop the watchdog - we still need the correct key */ + +void +stop_watchdog(void) +{ +#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) + watchdog_key ^= 0x7; /* invert key, which is 3 bits */ + *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) | + IO_STATE(R_WATCHDOG, enable, stop); +#endif +} + /* last time the cmos clock got updated */ static long last_rtc_update = 0; @@ -443,6 +455,19 @@ #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM) printk("Enabling watchdog...\n"); start_watchdog(); -#endif + /* If we use the hardware watchdog, we want to trap it as an NMI + and dump registers before it resets us. For this to happen, we + must set the "m" NMI enable flag (which once set, is unset only + when an NMI is taken). + + The same goes for the external NMI, but that doesn't have any + driver or infrastructure support yet. */ + asm ("setf m"); + + *R_IRQ_MASK0_SET = + IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set); + *R_VECT_MASK_SET = + IO_STATE(R_VECT_MASK_SET, nmi, set); +#endif } diff -u --recursive --new-file v2.4.7/linux/arch/cris/kernel/traps.c linux/arch/cris/kernel/traps.c --- v2.4.7/linux/arch/cris/kernel/traps.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/kernel/traps.c Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.12 2001/05/15 15:46:40 bjornw Exp $ +/* $Id: traps.c,v 1.15 2001/07/18 14:02:37 bjornw Exp $ * * linux/arch/cris/traps.c * @@ -9,6 +9,7 @@ * Copyright (C) 2000,2001 Axis Communications AB * * Authors: Bjorn Wesen + * Hans-Peter Nilsson * */ @@ -20,6 +21,7 @@ #include #include #include +#include #include #include @@ -36,6 +38,13 @@ #define MODULE_RANGE (8*1024*1024) +/* + * The output (format, strings and order) is adjusted to be usable with + * ksymoops-2.4.1 with some necessary CRIS-specific patches. Please don't + * change it unless you're serious about adjusting ksymoops and syncing + * with the ksymoops maintainer. + */ + void show_stack(unsigned long *sp) { @@ -43,22 +52,31 @@ int i; extern char _stext, _etext; - /* - * debugging aid: "show_stack(NULL);" prints the - * back trace for this cpu. - */ + /* + * debugging aid: "show_stack(NULL);" prints a + * back trace. + */ if(sp == NULL) sp = (unsigned long*)rdsp(); stack = sp; + printk("\nStack from %08lx:\n ", stack); for(i = 0; i < kstack_depth_to_print; i++) { if (((long) stack & (THREAD_SIZE-1)) == 0) break; if (i && ((i % 8) == 0)) printk("\n "); - printk("%08lx ", *stack++); + if (__get_user (addr, stack)) { + /* This message matches "failing address" marked + s390 in ksymoops, so lines containing it will + not be filtered out by ksymoops. */ + printk ("Failing address 0x%lx\n", stack); + break; + } + stack++; + printk("%08lx ", addr); } printk("\nCall Trace: "); @@ -67,7 +85,15 @@ module_start = VMALLOC_START; module_end = VMALLOC_END; while (((long) stack & (THREAD_SIZE-1)) != 0) { - addr = *stack++; + if (__get_user (addr, stack)) { + /* This message matches "failing address" marked + s390 in ksymoops, so lines containing it will + not be filtered out by ksymoops. */ + printk ("Failing address 0x%lx\n", stack); + break; + } + stack++; + /* * If the address is either in the text segment of the * kernel, or in the region which contains vmalloc'ed @@ -105,38 +131,53 @@ void show_registers(struct pt_regs * regs) { + /* We either use rdusp() - the USP register, which might not + correspond to the current process for all cases we're called, + or we use the current->thread.usp, which is not up to date for + the current process. Experience shows we want the USP + register. */ unsigned long usp = rdusp(); - printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx MOF: %08lx\n", + printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n", regs->irp, regs->srp, regs->dccr, usp, regs->mof ); - printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", + printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n", regs->r0, regs->r1, regs->r2, regs->r3); - printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", + printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n", regs->r4, regs->r5, regs->r6, regs->r7); - printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", + printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n", regs->r8, regs->r9, regs->r10, regs->r11); printk("r12: %08lx r13: %08lx oR10: %08lx\n", regs->r12, regs->r13, regs->orig_r10); + printk("R_MMU_CAUSE: %08lx\n", *R_MMU_CAUSE); printk("Process %s (pid: %d, stackpage=%08lx)\n", current->comm, current->pid, (unsigned long)current); - /* TODO, fix in_kernel detection */ - -#if 0 /* * When in-kernel, we also print out the stack and code at the * time of the fault.. */ - if (1) { - - printk("\nStack: "); + if (! user_mode(regs)) { + int i; + show_stack((unsigned long*)usp); + /* Dump kernel stack if the previous dump wasn't one. */ + if (usp != 0) + show_stack (NULL); + printk("\nCode: "); if(regs->irp < PAGE_OFFSET) goto bad; - for(i = 0; i < 20; i++) + /* Often enough the value at regs->irp does not point to + the interesting instruction, which is most often the + _previous_ instruction. So we dump at an offset large + enough that instruction decoding should be in sync at + the interesting point, but small enough to fit on a row + (sort of). We point out the regs->irp location in a + ksymoops-friendly way by wrapping the byte for that + address in parentheses. */ + for(i = -12; i < 12; i++) { unsigned char c; if(__get_user(c, &((unsigned char*)regs->irp)[i])) { @@ -144,11 +185,14 @@ printk(" Bad IP value."); break; } - printk("%02x ", c); + + if (i == 0) + printk("(%02x) ", c); + else + printk("%02x ", c); } + printk("\n"); } - printk("\n"); -#endif } void @@ -157,10 +201,13 @@ if(user_mode(regs)) return; + stop_watchdog(); + printk("%s: %04lx\n", str, err & 0xffff); show_registers(regs); - show_stack(NULL); /* print backtrace for kernel stack on this CPU */ + + reset_watchdog(); do_exit(SIGSEGV); } diff -u --recursive --new-file v2.4.7/linux/arch/cris/lib/Makefile linux/arch/cris/lib/Makefile --- v2.4.7/linux/arch/cris/lib/Makefile Thu Feb 8 16:32:44 2001 +++ linux/arch/cris/lib/Makefile Thu Jul 26 15:10:06 2001 @@ -6,6 +6,6 @@ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o L_TARGET = lib.a -obj-y = checksum.o checksumcopy.o string.o usercopy.o memset.o +obj-y = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.4.7/linux/arch/cris/lib/checksumcopy.S linux/arch/cris/lib/checksumcopy.S --- v2.4.7/linux/arch/cris/lib/checksumcopy.S Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/lib/checksumcopy.S Thu Jul 26 15:10:06 2001 @@ -1,4 +1,4 @@ -/* $Id: checksumcopy.S,v 1.5 2001/05/29 11:40:14 markusl Exp $ +/* $Id: checksumcopy.S,v 1.6 2001/06/28 03:57:16 hp Exp $ * A fast checksum+copy routine using movem * Copyright (c) 1998, 2001 Axis Communications AB * @@ -37,6 +37,7 @@ subq 10*4,r12 ; update length for the first loop mloop: movem [r10+],r9 ; read 10 longwords +1: ;; A failing userspace access will have this as PC. movem r9,[r11+] ; write 10 longwords ;; perform dword checksumming on the 10 longwords @@ -105,6 +106,7 @@ subq 2,r12 wloop: move.w [r10+],r9 +2: ;; A failing userspace access will have this as PC. addu.w r9,r13 subq 2,r12 bge wloop @@ -123,9 +125,8 @@ do_byte: ;; copy and checksum the last byte move.b [r10],r9 +3: ;; A failing userspace access will have this as PC. addu.b r9,r13 move.b r9,[r11] ret move.d r13, r10 - - diff -u --recursive --new-file v2.4.7/linux/arch/cris/lib/csumcpfruser.S linux/arch/cris/lib/csumcpfruser.S --- v2.4.7/linux/arch/cris/lib/csumcpfruser.S Wed Dec 31 16:00:00 1969 +++ linux/arch/cris/lib/csumcpfruser.S Thu Jul 26 15:10:06 2001 @@ -0,0 +1,64 @@ +/* + * Add-on to transform csum_partial_copy_nocheck in checksumcopy.S into + * csum_partial_copy_from_user by adding exception records. + * + * Copyright (C) 2001 Axis Communications AB. + * + * Author: Hans-Peter Nilsson. + */ + +#include + +/* Same function body, but a different name. If we just added exception + records to _csum_partial_copy_nocheck and made it generic, we wouldn't + know a user fault from a kernel fault and we would have overhead in + each kernel caller for the error-pointer argument. + + unsigned int csum_partial_copy_from_user + (const char *src, char *dst, int len, unsigned int sum, int *errptr); + + Note that the errptr argument is only set if we encounter an error. + It is conveniently located on the stack, so the normal function body + does not have to handle it. */ + +#define _csum_partial_copy_nocheck _csum_partial_copy_from_user + +/* There are local labels numbered 1, 2 and 3 present to mark the + different from-user accesses. */ +#include "checksumcopy.S" + + .section .fixup,"ax" + +;; Here from the movem loop; restore stack. +4: + movem [sp+],r8 +;; r12 is already decremented. Add back chunk_size-2. + addq 40-2,r12 + +;; Here from the word loop; r12 is off by 2; add it back. +5: + addq 2,r12 + +;; Here from a failing single byte. +6: + +;; Signal in *errptr that we had a failing access. + moveq -EFAULT,r9 + move.d r9,[[sp]] + +;; Clear the rest of the destination area using memset. Preserve the +;; checksum for the readable bytes. + push srp + push r13 + move.d r11,r10 + clear.d r11 + jsr _memset + pop r10 + jump [sp+] + + .previous + .section __ex_table,"a" + .dword 1b,4b + .dword 2b,5b + .dword 3b,6b + .previous diff -u --recursive --new-file v2.4.7/linux/arch/cris/mm/fault.c linux/arch/cris/mm/fault.c --- v2.4.7/linux/arch/cris/mm/fault.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/mm/fault.c Thu Jul 26 15:10:06 2001 @@ -6,6 +6,16 @@ * Authors: Bjorn Wesen * * $Log: fault.c,v $ + * Revision 1.18 2001/07/18 22:14:32 bjornw + * Enable interrupts in the bulk of do_page_fault + * + * Revision 1.17 2001/07/18 13:07:23 bjornw + * * Detect non-existant PTE's in vmalloc pmd synchronization + * * Remove comment about fast-paths for VMALLOC_START etc, because all that + * was totally bogus anyway it turned out :) + * * Fix detection of vmalloc-area synchronization + * * Add some comments + * * Revision 1.16 2001/06/13 00:06:08 bjornw * current_pgd should be volatile * @@ -76,7 +86,9 @@ volatile pgd_t *current_pgd; -/* fast TLB-fill fault handler */ +/* fast TLB-fill fault handler + * this is called from entry.S with interrupts disabled + */ void handle_mmu_bus_fault(struct pt_regs *regs) @@ -85,10 +97,9 @@ int index; int page_id; int miss, we, acc, inv; - struct mm_struct *mm = current->active_mm; pmd_t *pmd; pte_t pte; - int errcode = 0; + int errcode; unsigned long address; cause = *R_MMU_CAUSE; @@ -103,6 +114,20 @@ miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause); we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause); + /* Note: the reason we don't set errcode's r/w flag here + * using the 'we' flag, is because the latter is only given + * if there is a write-protection exception, not given as a + * general r/w access mode flag. It is currently not possible + * to get this from the MMU (TODO: check if this is the case + * for LXv2). + * + * The page-fault code won't care, but there will be two page- + * faults instead of one for the case of a write to a non-tabled + * page (miss, then write-protection). + */ + + errcode = 0; + D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, " "idx %d pid %d\n", regs->irp, address, miss, inv, we, acc, index, page_id)); @@ -157,14 +182,14 @@ * the write to R_TLB_LO also writes the vpn and page_id fields from * R_MMU_CAUSE, which we in this case obviously want to keep */ - + *R_TLB_LO = pte_val(pte); return; } - errcode = 0x01 | (we << 1); - + errcode = 1 | (we << 1); + dofault: /* leave it to the MM system fault handler below */ D(printk("do_page_fault %p errcode %d\n", address, errcode)); @@ -214,25 +239,21 @@ * NOTE2: This is done so that, when updating the vmalloc * mappings we don't have to walk all processes pgdirs and * add the high mappings all at once. Instead we do it as they - * are used. + * are used. However vmalloc'ed page entries have the PAGE_GLOBAL + * bit set so sometimes the TLB can use a lingering entry. * - * TODO: On CRIS, we have a PTE Global bit which should be set in - * all the PTE's related to vmalloc in all processes - that means if - * we switch process and a vmalloc PTE is still in the TLB, it won't - * need to be reloaded. It's an optimization. - * - * Linux/CRIS's kernel is not page-mapped, so the comparision below - * should really be >= VMALLOC_START, however, kernel fixup errors - * will be handled more quickly by going through vmalloc_fault and then - * into bad_area_nosemaphore than falling through the find_vma user-mode - * tests. As an aside can be mentioned that the difference in - * compiled code is neglibible; the instruction is the same, just a - * comparison with a different address of the same size. + * This verifies that the fault happens in kernel space + * and that the fault was not a protection error (error_code & 1). */ - if (address >= TASK_SIZE) + if (address >= VMALLOC_START && + !(error_code & 1) && + !user_mode(regs)) goto vmalloc_fault; + /* we can and should enable interrupts at this point */ + sti(); + mm = tsk->mm; writeaccess = error_code & 2; info.si_code = SEGV_MAPERR; @@ -409,29 +430,48 @@ * Use current_pgd instead of tsk->active_mm->pgd * since the latter might be unavailable if this * code is executed in a misfortunately run irq + * (like inside schedule() between switch_mm and + * switch_to...). */ int offset = pgd_index(address); pgd_t *pgd, *pgd_k; pmd_t *pmd, *pmd_k; + pte_t *pte_k; pgd = current_pgd + offset; pgd_k = init_mm.pgd + offset; - if (!pgd_present(*pgd)) { - if (!pgd_present(*pgd_k)) - goto bad_area_nosemaphore; - set_pgd(pgd, *pgd_k); - return; - } + /* Since we're two-level, we don't need to do both + * set_pgd and set_pmd (they do the same thing). If + * we go three-level at some point, do the right thing + * with pgd_present and set_pgd here. + * + * Also, since the vmalloc area is global, we don't + * need to copy individual PTE's, it is enough to + * copy the pgd pointer into the pte page of the + * root task. If that is there, we'll find our pte if + * it exists. + */ pmd = pmd_offset(pgd, address); pmd_k = pmd_offset(pgd_k, address); if (!pmd_present(*pmd_k)) goto bad_area_nosemaphore; + set_pmd(pmd, *pmd_k); + + /* Make sure the actual PTE exists as well to + * catch kernel vmalloc-area accesses to non-mapped + * addresses. If we don't do this, this will just + * silently loop forever. + */ + + pte_k = pte_offset(pmd_k, address); + if (!pte_present(*pte_k)) + goto no_context; + return; } - } diff -u --recursive --new-file v2.4.7/linux/arch/cris/mm/init.c linux/arch/cris/mm/init.c --- v2.4.7/linux/arch/cris/mm/init.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/mm/init.c Thu Jul 26 15:10:06 2001 @@ -7,6 +7,18 @@ * Authors: Bjorn Wesen (bjornw@axis.com) * * $Log: init.c,v $ + * Revision 1.29 2001/07/25 16:09:50 bjornw + * val->sharedram will stay 0 + * + * Revision 1.28 2001/06/28 16:30:17 bjornw + * Oops. This needs to wait until 2.4.6 is merged + * + * Revision 1.27 2001/06/28 14:04:07 bjornw + * Fill in sharedram + * + * Revision 1.26 2001/06/18 06:36:02 hp + * Enable free_initmem of __init-type pages + * * Revision 1.25 2001/06/13 00:02:23 bjornw * Use a separate variable to store the current pgd to avoid races in schedule * @@ -438,11 +450,6 @@ void free_initmem(void) { -#if 0 - /* currently this is a bad idea since the cramfs image is catted onto - * the vmlinux image, and the end of that image is not page-padded so - * part of the cramfs image will be freed here - */ unsigned long addr; addr = (unsigned long)(&__init_begin); @@ -454,7 +461,6 @@ } printk ("Freeing unused kernel memory: %dk freed\n", (&__init_end - &__init_begin) >> 10); -#endif } void @@ -464,7 +470,7 @@ i = max_mapnr; val->totalram = 0; - val->sharedram = atomic_read(&shmem_nrpages); + val->sharedram = 0; val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); while (i-- > 0) { diff -u --recursive --new-file v2.4.7/linux/arch/cris/mm/tlb.c linux/arch/cris/mm/tlb.c --- v2.4.7/linux/arch/cris/mm/tlb.c Wed Jul 25 17:10:17 2001 +++ linux/arch/cris/mm/tlb.c Thu Jul 26 15:10:06 2001 @@ -40,6 +40,10 @@ * * The last page_id is never running - it is used as an invalid page_id * so we can make TLB entries that will never match. + * + * Notice that we need to make the flushes atomic, otherwise an interrupt + * handler that uses vmalloced memory might cause a TLB load in the middle + * of a flush causing. */ struct mm_struct *page_id_map[NUM_PAGEID]; @@ -49,17 +53,18 @@ /* invalidate all TLB entries */ void -flush_tlb_all() +flush_tlb_all(void) { int i; + unsigned long flags; /* the vpn of i & 0xf is so we dont write similar TLB entries * in the same 4-way entry group. details.. */ + save_and_cli(flags); /* flush needs to be atomic */ for(i = 0; i < NUM_TLB_ENTRIES; i++) { *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); - *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) | IO_FIELD(R_TLB_HI, vpn, i & 0xf ) ); @@ -69,6 +74,7 @@ IO_STATE(R_TLB_LO, we, no ) | IO_FIELD(R_TLB_LO, pfn, 0 ) ); } + restore_flags(flags); D(printk("tlb: flushed all\n")); } @@ -79,6 +85,7 @@ { int i; int page_id = mm->context; + unsigned long flags; D(printk("tlb: flush mm context %d (%p)\n", page_id, mm)); @@ -90,6 +97,7 @@ * global pages. is it worth the extra I/O ? */ + save_and_cli(flags); /* flush needs to be atomic */ for(i = 0; i < NUM_TLB_ENTRIES; i++) { *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) { @@ -103,6 +111,7 @@ IO_FIELD(R_TLB_LO, pfn, 0 ) ); } } + restore_flags(flags); } /* invalidate a single page */ @@ -114,6 +123,7 @@ struct mm_struct *mm = vma->vm_mm; int page_id = mm->context; int i; + unsigned long flags; D(printk("tlb: flush page %p in context %d (%p)\n", addr, page_id, mm)); @@ -126,6 +136,7 @@ * and the virtual address requested */ + save_and_cli(flags); /* flush needs to be atomic */ for(i = 0; i < NUM_TLB_ENTRIES; i++) { unsigned long tlb_hi; *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); @@ -142,6 +153,7 @@ IO_FIELD(R_TLB_LO, pfn, 0 ) ); } } + restore_flags(flags); } /* invalidate a page range */ @@ -153,6 +165,7 @@ { int page_id = mm->context; int i; + unsigned long flags; D(printk("tlb: flush range %p<->%p in context %d (%p)\n", start, end, page_id, mm)); @@ -167,6 +180,7 @@ * and the virtual address range */ + save_and_cli(flags); /* flush needs to be atomic */ for(i = 0; i < NUM_TLB_ENTRIES; i++) { unsigned long tlb_hi, vpn; *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i); @@ -184,8 +198,30 @@ IO_FIELD(R_TLB_LO, pfn, 0 ) ); } } + restore_flags(flags); } +/* dump the entire TLB for debug purposes */ + +#if 0 +void +dump_tlb_all(void) +{ + int i; + unsigned long flags; + + printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we |\n"); + + save_and_cli(flags); + for(i = 0; i < NUM_TLB_ENTRIES; i++) { + *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) ); + printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n", + i, *R_TLB_HI, *R_TLB_LO); + } + restore_flags(flags); +} +#endif + /* * Initialize the context related info for a new mm_struct * instance. @@ -228,8 +264,7 @@ map_replace_ptr++; if(map_replace_ptr == INVALID_PAGEID) - map_replace_ptr = 0; /* wrap around */ - + map_replace_ptr = 0; /* wrap around */ } /* diff -u --recursive --new-file v2.4.7/linux/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile --- v2.4.7/linux/arch/i386/boot/Makefile Thu Feb 22 00:25:29 2001 +++ linux/arch/i386/boot/Makefile Sun Aug 5 13:13:19 2001 @@ -67,7 +67,7 @@ $(AS) -o $@ $< setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h - $(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ + $(CPP) $(CPPFLAGS) -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ bsetup: bsetup.o $(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $< @@ -76,7 +76,7 @@ $(AS) -o $@ $< bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h - $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ + $(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ dep: diff -u --recursive --new-file v2.4.7/linux/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S --- v2.4.7/linux/arch/i386/boot/setup.S Tue May 1 16:04:56 2001 +++ linux/arch/i386/boot/setup.S Sun Aug 5 13:13:19 2001 @@ -44,7 +44,6 @@ * */ -#define __ASSEMBLY__ #include #include #include diff -u --recursive --new-file v2.4.7/linux/arch/i386/kernel/cpuid.c linux/arch/i386/kernel/cpuid.c --- v2.4.7/linux/arch/i386/kernel/cpuid.c Sun Dec 31 09:23:51 2000 +++ linux/arch/i386/kernel/cpuid.c Thu Jul 26 13:37:38 2001 @@ -57,7 +57,7 @@ cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], &cmd->data[3]); } -extern inline void do_cpuid(int cpu, u32 reg, u32 *data) +static inline void do_cpuid(int cpu, u32 reg, u32 *data) { struct cpuid_command cmd; @@ -73,7 +73,7 @@ } #else /* ! CONFIG_SMP */ -extern inline void do_cpuid(int cpu, u32 reg, u32 *data) +static inline void do_cpuid(int cpu, u32 reg, u32 *data) { cpuid(reg, &data[0], &data[1], &data[2], &data[3]); } diff -u --recursive --new-file v2.4.7/linux/arch/i386/kernel/dmi_scan.c linux/arch/i386/kernel/dmi_scan.c --- v2.4.7/linux/arch/i386/kernel/dmi_scan.c Wed Jul 25 17:10:17 2001 +++ linux/arch/i386/kernel/dmi_scan.c Wed Jul 25 14:12:01 2001 @@ -15,12 +15,14 @@ }; #define dmi_printk(x) -//#define dmi_printk(x) printk(x) +//#define dmi_printk(x) printk x static char * __init dmi_string(struct dmi_header *dm, u8 s) { u8 *bp=(u8 *)dm; bp+=dm->length; + if(!s) + return ""; s--; while(s>0) { diff -u --recursive --new-file v2.4.7/linux/arch/i386/kernel/ldt.c linux/arch/i386/kernel/ldt.c --- v2.4.7/linux/arch/i386/kernel/ldt.c Wed Apr 11 19:05:37 2001 +++ linux/arch/i386/kernel/ldt.c Thu Jul 26 13:29:45 2001 @@ -70,34 +70,19 @@ } /* - * Horrible dependencies! Try to get rid of this. This is wrong, - * as it only reloads the ldt for the first process with this - * mm. The implications are that you should really make sure that - * you have a ldt before you do the first clone(), otherwise - * you get strange behaviour (the kernel is safe, it's just user - * space strangeness). - * - * we have two choices: either we preallocate the LDT descriptor - * and can do a shared modify_ldt(), or we postallocate it and do - * an smp message pass to update it. Currently we are a bit - * un-nice to user-space and reload the LDT only on the next - * schedule. (only an issue on SMP) - * * the GDT index of the LDT is allocated dynamically, and is * limited by MAX_LDT_DESCRIPTORS. */ down_write(&mm->mmap_sem); if (!mm->context.segments) { + void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); error = -ENOMEM; - mm->context.segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); - if (!mm->context.segments) + if (!segments) goto out_unlock; - memset(mm->context.segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE); - - /* - * Possibly do an SMP cross-call to other CPUs to reload - * their LDTs? - */ + memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE); + wmb(); + mm->context.segments = segments; + mm->context.cpuvalid = 1UL << smp_processor_id(); load_LDT(mm); } diff -u --recursive --new-file v2.4.7/linux/arch/i386/kernel/mpparse.c linux/arch/i386/kernel/mpparse.c --- v2.4.7/linux/arch/i386/kernel/mpparse.c Tue Jul 3 17:08:18 2001 +++ linux/arch/i386/kernel/mpparse.c Mon Aug 6 10:29:39 2001 @@ -273,24 +273,26 @@ int count=sizeof(*mpc); unsigned char *mpt=((unsigned char *)mpc)+count; - if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) - { + if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) { panic("SMP mptable: bad signature [%c%c%c%c]!\n", mpc->mpc_signature[0], mpc->mpc_signature[1], mpc->mpc_signature[2], mpc->mpc_signature[3]); - return 1; + return 0; } - if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) - { + if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) { panic("SMP mptable: checksum error!\n"); - return 1; + return 0; } - if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) - { - printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec); - return 1; + if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) { + printk(KERN_ERR "SMP mptable: bad table version (%d)!!\n", + mpc->mpc_spec); + return 0; + } + if (!mpc->mpc_lapic) { + printk(KERN_ERR "SMP mptable: null local APIC address!\n"); + return 0; } memcpy(str,mpc->mpc_oem,8); str[8]=0; @@ -358,6 +360,8 @@ } } } + if (!num_processors) + printk(KERN_ERR "SMP mptable: no processors registered!\n"); return num_processors; } @@ -508,8 +512,12 @@ * Read the physical hardware table. Anything here will * override the defaults. */ - smp_read_mpc((void *)mpf->mpf_physptr); - + if (!smp_read_mpc((void *)mpf->mpf_physptr)) { + smp_found_config = 0; + printk(KERN_ERR "BIOS bug, MP table errors detected!...\n"); + printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n"); + return; + } /* * If there are no explicit MP IRQ entries, then we are * broken. We set up most of the low 16 IO-APIC pins to diff -u --recursive --new-file v2.4.7/linux/arch/i386/kernel/msr.c linux/arch/i386/kernel/msr.c --- v2.4.7/linux/arch/i386/kernel/msr.c Sun Dec 31 09:24:08 2000 +++ linux/arch/i386/kernel/msr.c Thu Jul 26 13:37:38 2001 @@ -43,7 +43,7 @@ /* Note: "err" is handled in a funny way below. Otherwise one version of gcc or another breaks. */ -extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) +static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx) { int err; @@ -64,7 +64,7 @@ return err; } -extern inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) +static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx) { int err; @@ -110,7 +110,7 @@ cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]); } -extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) +static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) { struct msr_command cmd; @@ -127,7 +127,7 @@ } } -extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) +static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) { struct msr_command cmd; @@ -148,12 +148,12 @@ #else /* ! CONFIG_SMP */ -extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) +static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx) { return wrmsr_eio(reg, eax, edx); } -extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) +static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx) { return rdmsr_eio(reg, eax, edx); } diff -u --recursive --new-file v2.4.7/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.4.7/linux/arch/i386/kernel/process.c Wed Jul 25 17:10:17 2001 +++ linux/arch/i386/kernel/process.c Wed Jul 25 18:19:11 2001 @@ -518,6 +518,7 @@ memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE); } new_mm->context.segments = ldt; + new_mm->context.cpuvalid = ~0UL; /* valid on all CPU's - they can't have stale data */ } /* diff -u --recursive --new-file v2.4.7/linux/arch/i386/math-emu/poly.h linux/arch/i386/math-emu/poly.h --- v2.4.7/linux/arch/i386/math-emu/poly.h Fri Apr 6 10:42:47 2001 +++ linux/arch/i386/math-emu/poly.h Thu Jul 26 13:37:38 2001 @@ -60,7 +60,7 @@ /* Some versions of gcc make it difficult to stop eax from being clobbered. Merely specifying that it is used doesn't work... */ -extern inline unsigned long mul_32_32(const unsigned long arg1, +static inline unsigned long mul_32_32(const unsigned long arg1, const unsigned long arg2) { int retval; @@ -73,7 +73,7 @@ /* Add the 12 byte Xsig x2 to Xsig dest, with no checks for overflow. */ -extern inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2) +static inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2) { asm volatile ("movl %1,%%edi; movl %2,%%esi; movl (%%esi),%%eax; addl %%eax,(%%edi); @@ -88,7 +88,7 @@ /* Note: the constraints in the asm statement didn't always work properly with gcc 2.5.8. Changing from using edi to using ecx got around the problem, but keep fingers crossed! */ -extern inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp) +static inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp) { asm volatile ("movl %2,%%ecx; movl %3,%%esi; movl (%%esi),%%eax; addl %%eax,(%%ecx); @@ -108,7 +108,7 @@ /* Negate (subtract from 1.0) the 12 byte Xsig */ /* This is faster in a loop on my 386 than using the "neg" instruction. */ -extern inline void negate_Xsig(Xsig *x) +static inline void negate_Xsig(Xsig *x) { asm volatile("movl %1,%%esi; " "xorl %%ecx,%%ecx; " diff -u --recursive --new-file v2.4.7/linux/arch/ia64/Makefile linux/arch/ia64/Makefile --- v2.4.7/linux/arch/ia64/Makefile Thu Apr 5 12:51:46 2001 +++ linux/arch/ia64/Makefile Tue Jul 31 10:30:08 2001 @@ -14,18 +14,18 @@ export AWK LINKFLAGS = -static -T arch/$(ARCH)/vmlinux.lds -AFLAGS += -Wa,-x AFLAGS_KERNEL := -mconstant-gp EXTRA = -CFLAGS := $(CFLAGS) -pipe $(EXTRA) -Wa,-x -ffixed-r13 -mfixed-range=f10-f15,f32-f127 \ - -funwind-tables -falign-functions=32 -# -frename-registers (this crashes the Nov 17 compiler...) +CFLAGS := $(CFLAGS) -pipe $(EXTRA) -ffixed-r13 -mfixed-range=f10-f15,f32-f127 -falign-functions=32 CFLAGS_KERNEL := -mconstant-gp -ifeq ($(CONFIG_ITANIUM_ASTEP_SPECIFIC),y) - CFLAGS += -ma-step +GCC_VERSION=$(shell $(CROSS_COMPILE)$(HOSTCC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.') + +ifneq ($(GCC_VERSION),2) + CFLAGS += -frename-registers endif + ifeq ($(CONFIG_ITANIUM_BSTEP_SPECIFIC),y) CFLAGS += -mb-step endif diff -u --recursive --new-file v2.4.7/linux/arch/ia64/boot/bootloader.c linux/arch/ia64/boot/bootloader.c --- v2.4.7/linux/arch/ia64/boot/bootloader.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/boot/bootloader.c Tue Jul 31 10:30:08 2001 @@ -87,9 +87,6 @@ asm volatile ("movl gp=__gp;;" ::: "memory"); asm volatile ("mov sp=%0" :: "r"(stack) : "memory"); asm volatile ("bsw.1;;"); -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC - asm volative ("nop 0;; nop 0;; nop 0;;"); -#endif /* CONFIG_ITANIUM_ASTEP_SPECIFIC */ ssc(0, 0, 0, 0, SSC_CONSOLE_INIT); diff -u --recursive --new-file v2.4.7/linux/arch/ia64/config.in linux/arch/ia64/config.in --- v2.4.7/linux/arch/ia64/config.in Tue Apr 17 17:19:24 2001 +++ linux/arch/ia64/config.in Tue Jul 31 10:30:08 2001 @@ -26,6 +26,12 @@ define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n +if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then + define_bool CONFIG_ACPI y + define_bool CONFIG_ACPI_INTERPRETER y + define_bool CONFIG_ACPI_KERNEL_CONFIG y +fi + choice 'IA-64 processor type' \ "Itanium CONFIG_ITANIUM \ McKinley CONFIG_MCKINLEY" Itanium @@ -44,7 +50,6 @@ if [ "$CONFIG_ITANIUM" = "y" ]; then define_bool CONFIG_IA64_BRL_EMU y - bool ' Enable Itanium A-step specific code' CONFIG_ITANIUM_ASTEP_SPECIFIC bool ' Enable Itanium B-step specific code' CONFIG_ITANIUM_BSTEP_SPECIFIC if [ "$CONFIG_ITANIUM_BSTEP_SPECIFIC" = "y" ]; then bool ' Enable Itanium B0-step specific code' CONFIG_ITANIUM_B0_SPECIFIC @@ -59,7 +64,7 @@ if [ "$CONFIG_ITANIUM_CSTEP_SPECIFIC" = "y" ]; then bool ' Enable Itanium C0-step specific code' CONFIG_ITANIUM_C0_SPECIFIC fi - if [ "$CONFIG_ITANIUM_ASTEP_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B0_SPECIFIC" = "y" \ + if [ "$CONFIG_ITANIUM_B0_SPECIFIC" = "y" \ -o "$CONFIG_ITANIUM_B1_SPECIFIC" = "y" -o "$CONFIG_ITANIUM_B2_SPECIFIC" = "y" ]; then define_bool CONFIG_ITANIUM_PTCG n else @@ -84,13 +89,7 @@ if [ "$CONFIG_IA64_DIG" = "y" ]; then bool ' Force interrupt redirection' CONFIG_IA64_HAVE_IRQREDIR bool ' Enable IA-64 Machine Check Abort' CONFIG_IA64_MCA - bool ' Enable ACPI 2.0 with errata 1.3' CONFIG_ACPI20 - bool ' ACPI kernel configuration manager (EXPERIMENTAL)' CONFIG_ACPI_KERNEL_CONFIG - if [ "$CONFIG_ACPI_KERNEL_CONFIG" = "y" ]; then - define_bool CONFIG_PM y - define_bool CONFIG_ACPI y - define_bool CONFIG_ACPI_INTERPRETER y - fi + define_bool CONFIG_PM y fi if [ "$CONFIG_IA64_SGI_SN1" = "y" ]; then @@ -112,7 +111,7 @@ bool 'SMP support' CONFIG_SMP bool 'Performance monitor support' CONFIG_PERFMON tristate '/proc/pal support' CONFIG_IA64_PALINFO -tristate '/proc/efi support' CONFIG_IA64_EFIVARS +tristate '/proc/efi/vars support' CONFIG_EFI_VARS bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC @@ -123,6 +122,8 @@ if [ "$CONFIG_IA64_HP_SIM" = "n" ]; then +source drivers/acpi/Config.in + bool 'PCI support' CONFIG_PCI source drivers/pci/Config.in @@ -246,6 +247,10 @@ endmenu source drivers/usb/Config.in + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + source net/bluetooth/Config.in +fi fi # !HP_SIM diff -u --recursive --new-file v2.4.7/linux/arch/ia64/hp/hpsim_setup.c linux/arch/ia64/hp/hpsim_setup.c --- v2.4.7/linux/arch/ia64/hp/hpsim_setup.c Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/hp/hpsim_setup.c Tue Jul 31 10:30:08 2001 @@ -27,28 +27,15 @@ /* * Simulator system call. */ -inline long -ia64_ssc (long arg0, long arg1, long arg2, long arg3, int nr) -{ -#ifdef __GCC_DOESNT_KNOW_IN_REGS__ - register long in0 asm ("r32") = arg0; - register long in1 asm ("r33") = arg1; - register long in2 asm ("r34") = arg2; - register long in3 asm ("r35") = arg3; -#else - register long in0 asm ("in0") = arg0; - register long in1 asm ("in1") = arg1; - register long in2 asm ("in2") = arg2; - register long in3 asm ("in3") = arg3; -#endif - register long r8 asm ("r8"); - register long r15 asm ("r15") = nr; - - asm volatile ("break 0x80001" - : "=r"(r8) - : "r"(r15), "r"(in0), "r"(in1), "r"(in2), "r"(in3)); - return r8; -} +asm (".text\n" + ".align 32\n" + ".global ia64_ssc\n" + ".proc ia64_ssc\n" + "ia64_ssc:\n" + "mov r15=r36\n" + "break 0x80001\n" + "br.ret.sptk.many rp\n" + ".endp\n"); void ia64_ssc_connect_irq (long intr, long irq) diff -u --recursive --new-file v2.4.7/linux/arch/ia64/ia32/Makefile linux/arch/ia64/ia32/Makefile --- v2.4.7/linux/arch/ia64/ia32/Makefile Thu Jan 4 12:50:17 2001 +++ linux/arch/ia64/ia32/Makefile Tue Jul 31 10:30:08 2001 @@ -11,7 +11,8 @@ O_TARGET := ia32.o -obj-y := ia32_entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o ia32_support.o ia32_traps.o binfmt_elf32.o +obj-y := ia32_entry.o sys_ia32.o ia32_ioctl.o ia32_signal.o ia32_support.o ia32_traps.o \ + binfmt_elf32.o ia32_ldt.o clean:: diff -u --recursive --new-file v2.4.7/linux/arch/ia64/ia32/binfmt_elf32.c linux/arch/ia64/ia32/binfmt_elf32.c --- v2.4.7/linux/arch/ia64/ia32/binfmt_elf32.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/ia32/binfmt_elf32.c Tue Jul 31 10:30:08 2001 @@ -2,8 +2,11 @@ * IA-32 ELF support. * * Copyright (C) 1999 Arun Sharma + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 David Mosberger-Tang * * 06/16/00 A. Mallick initialize csd/ssd/tssd/cflg for ia32_load_state + * 04/13/01 D. Mosberger dropped saving tssd in ar.k1---it's not needed */ #include @@ -35,8 +38,8 @@ #undef CLOCKS_PER_SEC #define CLOCKS_PER_SEC IA32_CLOCKS_PER_SEC -extern void ia64_elf32_init(struct pt_regs *regs); -extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address); +extern void ia64_elf32_init (struct pt_regs *regs); +extern void put_dirty_page (struct task_struct * tsk, struct page *page, unsigned long address); #define ELF_PLAT_INIT(_r) ia64_elf32_init(_r) #define setup_arg_pages(bprm) ia32_setup_arg_pages(bprm) @@ -49,7 +52,7 @@ unsigned long *ia32_gdt_table, *ia32_tss; struct page * -put_shared_page(struct task_struct * tsk, struct page *page, unsigned long address) +put_shared_page (struct task_struct * tsk, struct page *page, unsigned long address) { pgd_t * pgd; pmd_t * pmd; @@ -83,85 +86,99 @@ return 0; } -void ia64_elf32_init(struct pt_regs *regs) +void +ia64_elf32_init (struct pt_regs *regs) { + struct vm_area_struct *vma; int nr; - put_shared_page(current, virt_to_page(ia32_gdt_table), IA32_PAGE_OFFSET); + /* + * Map GDT and TSS below 4GB, where the processor can find them. We need to map + * it with privilege level 3 because the IVE uses non-privileged accesses to these + * tables. IA-32 segmentation is used to protect against IA-32 accesses to them. + */ + put_shared_page(current, virt_to_page(ia32_gdt_table), IA32_GDT_OFFSET); if (PAGE_SHIFT <= IA32_PAGE_SHIFT) - put_shared_page(current, virt_to_page(ia32_tss), IA32_PAGE_OFFSET + PAGE_SIZE); + put_shared_page(current, virt_to_page(ia32_tss), IA32_TSS_OFFSET); - nr = smp_processor_id(); + /* + * Install LDT as anonymous memory. This gives us all-zero segment descriptors + * until a task modifies them via modify_ldt(). + */ + vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + if (vma) { + vma->vm_mm = current->mm; + vma->vm_start = IA32_LDT_OFFSET; + vma->vm_end = vma->vm_start + PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE); + vma->vm_page_prot = PAGE_SHARED; + vma->vm_flags = VM_READ|VM_WRITE|VM_MAYREAD|VM_MAYWRITE; + vma->vm_ops = NULL; + vma->vm_pgoff = 0; + vma->vm_file = NULL; + vma->vm_private_data = NULL; + insert_vm_struct(current->mm, vma); + } - /* Do all the IA-32 setup here */ + nr = smp_processor_id(); - current->thread.map_base = 0x40000000; - current->thread.task_size = 0xc0000000; /* use what Linux/x86 uses... */ + current->thread.map_base = IA32_PAGE_OFFSET/3; + current->thread.task_size = IA32_PAGE_OFFSET; /* use what Linux/x86 uses... */ set_fs(USER_DS); /* set addr limit for new TASK_SIZE */ - /* setup ia32 state for ia32_load_state */ - - current->thread.eflag = IA32_EFLAG; - current->thread.csd = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L, 3L, 1L, 1L, 1L); - current->thread.ssd = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L); - current->thread.tssd = IA64_SEG_DESCRIPTOR(IA32_PAGE_OFFSET + PAGE_SIZE, 0x1FFFL, 0xBL, - 1L, 3L, 1L, 1L, 1L); - - /* CS descriptor */ - __asm__("mov ar.csd = %0" : /* no outputs */ - : "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0xBL, 1L, - 3L, 1L, 1L, 1L)); - /* SS descriptor */ - __asm__("mov ar.ssd = %0" : /* no outputs */ - : "r" IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, - 3L, 1L, 1L, 1L)); - /* EFLAGS */ - __asm__("mov ar.eflag = %0" : /* no outputs */ : "r" (IA32_EFLAG)); - - /* Control registers */ - __asm__("mov ar.fsr = %0" - : /* no outputs */ - : "r" ((ulong)IA32_FSR_DEFAULT)); - __asm__("mov ar.fcr = %0" - : /* no outputs */ - : "r" ((ulong)IA32_FCR_DEFAULT)); - __asm__("mov ar.fir = r0"); - __asm__("mov ar.fdr = r0"); - current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE); - ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE); - - /* Get the segment selectors right */ - regs->r16 = (__USER_DS << 16) | (__USER_DS); /* ES == DS, GS, FS are zero */ - regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32) - | (__USER_DS << 16) | __USER_CS; - - /* Setup other segment descriptors - ESD, DSD, FSD, GSD */ - regs->r24 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L); - regs->r27 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L); - regs->r28 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L); - regs->r29 = IA64_SEG_DESCRIPTOR(0L, 0xFFFFFL, 0x3L, 1L, 3L, 1L, 1L, 1L); - - /* Setup the LDT and GDT */ - regs->r30 = ia32_gdt_table[_LDT(nr)]; - regs->r31 = IA64_SEG_DESCRIPTOR(0xc0000000L, 0x400L, 0x3L, 1L, 3L, - 1L, 1L, 1L); + /* Setup the segment selectors */ + regs->r16 = (__USER_DS << 16) | __USER_DS; /* ES == DS, GS, FS are zero */ + regs->r17 = (__USER_DS << 16) | __USER_CS; /* SS, CS; ia32_load_state() sets TSS and LDT */ + + /* Setup the segment descriptors */ + regs->r24 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]); /* ESD */ + regs->r27 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]); /* DSD */ + regs->r28 = 0; /* FSD (null) */ + regs->r29 = 0; /* GSD (null) */ + regs->r30 = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_LDT(nr)]); /* LDTD */ - /* Clear psr.ac */ - regs->cr_ipsr &= ~IA64_PSR_AC; + /* + * Setup GDTD. Note: GDTD is the descrambled version of the pseudo-descriptor + * format defined by Figure 3-11 "Pseudo-Descriptor Format" in the IA-32 + * architecture manual. + */ + regs->r31 = IA32_SEG_UNSCRAMBLE(IA32_SEG_DESCRIPTOR(IA32_GDT_OFFSET, IA32_PAGE_SIZE - 1, 0, + 0, 0, 0, 0, 0, 0)); + ia64_psr(regs)->ac = 0; /* turn off alignment checking */ regs->loadrs = 0; -} + /* + * According to the ABI %edx points to an `atexit' handler. Since we don't have + * one we'll set it to 0 and initialize all the other registers just to make + * things more deterministic, ala the i386 implementation. + */ + regs->r8 = 0; /* %eax */ + regs->r11 = 0; /* %ebx */ + regs->r9 = 0; /* %ecx */ + regs->r10 = 0; /* %edx */ + regs->r13 = 0; /* %ebp */ + regs->r14 = 0; /* %esi */ + regs->r15 = 0; /* %edi */ -#undef STACK_TOP -#define STACK_TOP ((IA32_PAGE_OFFSET/3) * 2) + current->thread.eflag = IA32_EFLAG; + current->thread.fsr = IA32_FSR_DEFAULT; + current->thread.fcr = IA32_FCR_DEFAULT; + current->thread.fir = 0; + current->thread.fdr = 0; + current->thread.csd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_CS >> 3]); + current->thread.ssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[__USER_DS >> 3]); + current->thread.tssd = IA32_SEG_UNSCRAMBLE(ia32_gdt_table[_TSS(nr)]); + + ia32_load_state(current); +} -int ia32_setup_arg_pages(struct linux_binprm *bprm) +int +ia32_setup_arg_pages (struct linux_binprm *bprm) { unsigned long stack_base; struct vm_area_struct *mpnt; int i; - stack_base = STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; + stack_base = IA32_STACK_TOP - MAX_ARG_PAGES*PAGE_SIZE; bprm->p += stack_base; if (bprm->loader) @@ -175,7 +192,7 @@ { mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) bprm->p; - mpnt->vm_end = STACK_TOP; + mpnt->vm_end = IA32_STACK_TOP; mpnt->vm_page_prot = PAGE_COPY; mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_ops = NULL; @@ -197,15 +214,15 @@ } static unsigned long -ia32_mm_addr(unsigned long addr) +ia32_mm_addr (unsigned long addr) { struct vm_area_struct *vma; if ((vma = find_vma(current->mm, addr)) == NULL) - return(ELF_PAGESTART(addr)); + return ELF_PAGESTART(addr); if (vma->vm_start > addr) - return(ELF_PAGESTART(addr)); - return(ELF_PAGEALIGN(addr)); + return ELF_PAGESTART(addr); + return ELF_PAGEALIGN(addr); } /* @@ -232,22 +249,9 @@ */ if (addr == 0) addr += PAGE_SIZE; -#if 1 set_brk(ia32_mm_addr(addr), addr + eppnt->p_memsz); memset((char *) addr + eppnt->p_filesz, 0, eppnt->p_memsz - eppnt->p_filesz); kernel_read(filep, eppnt->p_offset, (char *) addr, eppnt->p_filesz); retval = (unsigned long) addr; -#else - /* doesn't work yet... */ -# define IA32_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1)) -# define IA32_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1)) -# define IA32_PAGEALIGN(_v) (((_v) + ELF_EXEC_PAGESIZE - 1) & ~(ELF_EXEC_PAGESIZE - 1)) - - down_write(¤t->mm->mmap_sem); - retval = ia32_do_mmap(filep, IA32_PAGESTART(addr), - eppnt->p_filesz + IA32_PAGEOFFSET(eppnt->p_vaddr), prot, type, - eppnt->p_offset - IA32_PAGEOFFSET(eppnt->p_vaddr)); - up_write(¤t->mm->mmap_sem); -#endif return retval; } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/ia32/ia32_entry.S linux/arch/ia64/ia32/ia32_entry.S --- v2.4.7/linux/arch/ia64/ia32/ia32_entry.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/ia32/ia32_entry.S Tue Jul 31 10:30:08 2001 @@ -140,7 +140,7 @@ data8 sys_lchown data8 sys32_ni_syscall /* old break syscall holder */ data8 sys32_ni_syscall - data8 sys_lseek + data8 sys32_lseek data8 sys_getpid /* 20 */ data8 sys_mount data8 sys_oldumount @@ -233,7 +233,7 @@ data8 sys32_ni_syscall data8 sys_iopl /* 110 */ data8 sys_vhangup - data8 sys32_ni_syscall // used to be sys_idle + data8 sys32_ni_syscall /* used to be sys_idle */ data8 sys32_ni_syscall data8 sys32_wait4 data8 sys_swapoff /* 115 */ @@ -244,7 +244,7 @@ data8 sys_clone /* 120 */ data8 sys_setdomainname data8 sys32_newuname - data8 sys_modify_ldt + data8 sys32_modify_ldt data8 sys_adjtimex data8 sys32_mprotect /* 125 */ data8 sys_sigprocmask @@ -286,13 +286,13 @@ data8 sys32_nanosleep data8 sys_mremap data8 sys_setresuid - data8 sys_getresuid /* 165 */ + data8 sys32_getresuid /* 165 */ data8 sys_vm86 data8 sys_query_module data8 sys_poll data8 sys_nfsservctl data8 sys_setresgid /* 170 */ - data8 sys_getresgid + data8 sys32_getresgid data8 sys_prctl data8 sys32_rt_sigreturn data8 sys32_rt_sigaction diff -u --recursive --new-file v2.4.7/linux/arch/ia64/ia32/ia32_ldt.c linux/arch/ia64/ia32/ia32_ldt.c --- v2.4.7/linux/arch/ia64/ia32/ia32_ldt.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/ia32/ia32_ldt.c Tue Jul 31 10:30:08 2001 @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 David Mosberger-Tang + * + * Adapted from arch/i386/kernel/ldt.c + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * read_ldt() is not really atomic - this is not a problem since synchronization of reads + * and writes done to the LDT has to be assured by user-space anyway. Writes are atomic, + * to protect the security checks done on new descriptors. + */ +static int +read_ldt (void *ptr, unsigned long bytecount) +{ + char *src, *dst, buf[256]; /* temporary buffer (don't overflow kernel stack!) */ + unsigned long bytes_left, n; + + if (bytecount > IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE) + bytecount = IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE; + + bytes_left = bytecount; + + src = (void *) IA32_LDT_OFFSET; + dst = ptr; + + while (bytes_left) { + n = sizeof(buf); + if (n > bytes_left) + n = bytes_left; + + /* + * We know we're reading valid memory, but we still must guard against + * running out of memory. + */ + if (__copy_from_user(buf, src, n)) + return -EFAULT; + + if (copy_to_user(dst, buf, n)) + return -EFAULT; + + src += n; + dst += n; + bytes_left -= n; + } + return bytecount; +} + +static int +write_ldt (void * ptr, unsigned long bytecount, int oldmode) +{ + struct ia32_modify_ldt_ldt_s ldt_info; + __u64 entry; + + if (bytecount != sizeof(ldt_info)) + return -EINVAL; + if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info))) + return -EFAULT; + + if (ldt_info.entry_number >= IA32_LDT_ENTRIES) + return -EINVAL; + if (ldt_info.contents == 3) { + if (oldmode) + return -EINVAL; + if (ldt_info.seg_not_present == 0) + return -EINVAL; + } + + if (ldt_info.base_addr == 0 && ldt_info.limit == 0 + && (oldmode || (ldt_info.contents == 0 && ldt_info.read_exec_only == 1 + && ldt_info.seg_32bit == 0 && ldt_info.limit_in_pages == 0 + && ldt_info.seg_not_present == 1 && ldt_info.useable == 0))) + /* allow LDTs to be cleared by the user */ + entry = 0; + else + /* we must set the "Accessed" bit as IVE doesn't emulate it */ + entry = IA32_SEG_DESCRIPTOR(ldt_info.base_addr, ldt_info.limit, + (((ldt_info.read_exec_only ^ 1) << 1) + | (ldt_info.contents << 2)) | 1, + 1, 3, ldt_info.seg_not_present ^ 1, + (oldmode ? 0 : ldt_info.useable), + ldt_info.seg_32bit, + ldt_info.limit_in_pages); + /* + * Install the new entry. We know we're accessing valid (mapped) user-level + * memory, but we still need to guard against out-of-memory, hence we must use + * put_user(). + */ + return __put_user(entry, (__u64 *) IA32_LDT_OFFSET + ldt_info.entry_number); +} + +asmlinkage int +sys32_modify_ldt (int func, void *ptr, unsigned int bytecount) +{ + int ret = -ENOSYS; + + switch (func) { + case 0: + ret = read_ldt(ptr, bytecount); + break; + case 1: + ret = write_ldt(ptr, bytecount, 1); + break; + case 0x11: + ret = write_ldt(ptr, bytecount, 0); + break; + } + return ret; +} diff -u --recursive --new-file v2.4.7/linux/arch/ia64/ia32/ia32_support.c linux/arch/ia64/ia32/ia32_support.c --- v2.4.7/linux/arch/ia64/ia32/ia32_support.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/ia32/ia32_support.c Tue Jul 31 10:30:08 2001 @@ -1,6 +1,11 @@ /* * IA32 helper functions * + * Copyright (C) 1999 Arun Sharma + * Copyright (C) 2000 Asit K. Mallick + * Copyright (C) 2001 Hewlett-Packard Co + * Copyright (C) 2001 David Mosberger-Tang + * * 06/16/00 A. Mallick added csd/ssd/tssd for ia32 thread context * 02/19/01 D. Mosberger dropped tssd; it's not needed */ @@ -21,7 +26,7 @@ extern void die_if_kernel (char *str, struct pt_regs *regs, long err); void -ia32_save_state (struct thread_struct *thread) +ia32_save_state (struct task_struct *t) { unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd; @@ -33,28 +38,30 @@ "mov %5=ar.csd;" "mov %6=ar.ssd;" : "=r"(eflag), "=r"(fsr), "=r"(fcr), "=r"(fir), "=r"(fdr), "=r"(csd), "=r"(ssd)); - thread->eflag = eflag; - thread->fsr = fsr; - thread->fcr = fcr; - thread->fir = fir; - thread->fdr = fdr; - thread->csd = csd; - thread->ssd = ssd; - asm ("mov ar.k0=%0 ;;" :: "r"(thread->old_iob)); + t->thread.eflag = eflag; + t->thread.fsr = fsr; + t->thread.fcr = fcr; + t->thread.fir = fir; + t->thread.fdr = fdr; + t->thread.csd = csd; + t->thread.ssd = ssd; + ia64_set_kr(IA64_KR_IO_BASE, t->thread.old_iob); } void -ia32_load_state (struct thread_struct *thread) +ia32_load_state (struct task_struct *t) { unsigned long eflag, fsr, fcr, fir, fdr, csd, ssd; + struct pt_regs *regs = ia64_task_regs(t); + int nr; - eflag = thread->eflag; - fsr = thread->fsr; - fcr = thread->fcr; - fir = thread->fir; - fdr = thread->fdr; - csd = thread->csd; - ssd = thread->ssd; + eflag = t->thread.eflag; + fsr = t->thread.fsr; + fcr = t->thread.fcr; + fir = t->thread.fir; + fdr = t->thread.fdr; + csd = t->thread.csd; + ssd = t->thread.ssd; asm volatile ("mov ar.eflag=%0;" "mov ar.fsr=%1;" @@ -64,17 +71,22 @@ "mov ar.csd=%5;" "mov ar.ssd=%6;" :: "r"(eflag), "r"(fsr), "r"(fcr), "r"(fir), "r"(fdr), "r"(csd), "r"(ssd)); - asm ("mov %0=ar.k0 ;;" : "=r"(thread->old_iob)); - asm ("mov ar.k0=%0 ;;" :: "r"(IA32_IOBASE)); + current->thread.old_iob = ia64_get_kr(IA64_KR_IO_BASE); + ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE); + + /* load TSS and LDT while preserving SS and CS: */ + nr = smp_processor_id(); + regs->r17 = (_TSS(nr) << 48) | (_LDT(nr) << 32) | (__u32) regs->r17; } /* - * Setup IA32 GDT and TSS + * Setup IA32 GDT and TSS */ void -ia32_gdt_init(void) +ia32_gdt_init (void) { - unsigned long gdt_and_tss_page; + unsigned long gdt_and_tss_page, ldt_size; + int nr; /* allocate two IA-32 pages of memory: */ gdt_and_tss_page = __get_free_pages(GFP_KERNEL, @@ -86,17 +98,28 @@ /* Zero the gdt and tss */ memset((void *) gdt_and_tss_page, 0, 2*IA32_PAGE_SIZE); - /* CS descriptor in IA-32 format */ - ia32_gdt_table[4] = IA32_SEG_DESCRIPTOR(0L, 0xBFFFFFFFL, 0xBL, 1L, - 3L, 1L, 1L, 1L, 1L); - - /* DS descriptor in IA-32 format */ - ia32_gdt_table[5] = IA32_SEG_DESCRIPTOR(0L, 0xBFFFFFFFL, 0x3L, 1L, - 3L, 1L, 1L, 1L, 1L); + /* CS descriptor in IA-32 (scrambled) format */ + ia32_gdt_table[__USER_CS >> 3] = + IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT, + 0xb, 1, 3, 1, 1, 1, 1); + + /* DS descriptor in IA-32 (scrambled) format */ + ia32_gdt_table[__USER_DS >> 3] = + IA32_SEG_DESCRIPTOR(0, (IA32_PAGE_OFFSET - 1) >> IA32_PAGE_SHIFT, + 0x3, 1, 3, 1, 1, 1, 1); + + /* We never change the TSS and LDT descriptors, so we can share them across all CPUs. */ + ldt_size = PAGE_ALIGN(IA32_LDT_ENTRIES*IA32_LDT_ENTRY_SIZE); + for (nr = 0; nr < NR_CPUS; ++nr) { + ia32_gdt_table[_TSS(nr)] = IA32_SEG_DESCRIPTOR(IA32_TSS_OFFSET, 235, + 0xb, 0, 3, 1, 1, 1, 0); + ia32_gdt_table[_LDT(nr)] = IA32_SEG_DESCRIPTOR(IA32_LDT_OFFSET, ldt_size - 1, + 0x2, 0, 3, 1, 1, 1, 0); + } } /* - * Handle bad IA32 interrupt via syscall + * Handle bad IA32 interrupt via syscall */ void ia32_bad_interrupt (unsigned long int_num, struct pt_regs *regs) @@ -106,8 +129,7 @@ die_if_kernel("Bad IA-32 interrupt", regs, int_num); siginfo.si_signo = SIGTRAP; - siginfo.si_errno = int_num; /* XXX is it legal to abuse si_errno like this? */ + siginfo.si_errno = int_num; /* XXX is it OK to abuse si_errno like this? */ siginfo.si_code = TRAP_BRKPT; force_sig_info(SIGTRAP, &siginfo, current); } - diff -u --recursive --new-file v2.4.7/linux/arch/ia64/ia32/sys_ia32.c linux/arch/ia64/ia32/sys_ia32.c --- v2.4.7/linux/arch/ia64/ia32/sys_ia32.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/ia32/sys_ia32.c Tue Jul 31 10:30:08 2001 @@ -232,10 +232,17 @@ back = NULL; if ((baddr = (addr & PAGE_MASK)) != addr && get_user(c, (char *)baddr) == 0) { front = kmalloc(addr - baddr, GFP_KERNEL); + if (!front) + return -ENOMEM; __copy_user(front, (void *)baddr, addr - baddr); } if (addr && ((addr + len) & ~PAGE_MASK) && get_user(c, (char *)(addr + len)) == 0) { back = kmalloc(PAGE_SIZE - ((addr + len) & ~PAGE_MASK), GFP_KERNEL); + if (!back) { + if (front) + kfree(front); + return -ENOMEM; + } __copy_user(back, (char *)addr + len, PAGE_SIZE - ((addr + len) & ~PAGE_MASK)); } down_write(¤t->mm->mmap_sem); @@ -334,9 +341,9 @@ down_write(¤t->mm->mmap_sem); retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, a.offset >> PAGE_SHIFT); up_write(¤t->mm->mmap_sem); -#else // CONFIG_IA64_PAGE_SIZE_4KB +#else retval = ia32_do_mmap(file, a.addr, a.len, a.prot, a.flags, a.fd, a.offset); -#endif // CONFIG_IA64_PAGE_SIZE_4KB +#endif if (file) fput(file); return retval; @@ -660,9 +667,11 @@ long ret; if (times32) { - get_user(tv[0].tv_sec, ×32->atime); + if (get_user(tv[0].tv_sec, ×32->atime)) + return -EFAULT; tv[0].tv_usec = 0; - get_user(tv[1].tv_sec, ×32->mtime); + if (get_user(tv[1].tv_sec, ×32->mtime)) + return -EFAULT; tv[1].tv_usec = 0; set_fs (KERNEL_DS); tvp = tv; @@ -747,15 +756,18 @@ buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + buf->error = -EFAULT; /* only used if we fail.. */ dirent = buf->previous; if (dirent) - put_user(offset, &dirent->d_off); + if (put_user(offset, &dirent->d_off)) + return -EFAULT; dirent = buf->current_dir; buf->previous = dirent; - put_user(ino, &dirent->d_ino); - put_user(reclen, &dirent->d_reclen); - copy_to_user(dirent->d_name, name, namlen); - put_user(0, dirent->d_name + namlen); + if (put_user(ino, &dirent->d_ino) + || put_user(reclen, &dirent->d_reclen) + || copy_to_user(dirent->d_name, name, namlen) + || put_user(0, dirent->d_name + namlen)) + return -EFAULT; ((char *) dirent) += reclen; buf->current_dir = dirent; buf->count -= reclen; @@ -786,7 +798,9 @@ error = buf.error; lastdirent = buf.previous; if (lastdirent) { - put_user(file->f_pos, &lastdirent->d_off); + error = -EINVAL; + if (put_user(file->f_pos, &lastdirent->d_off)) + goto out_putf; error = count - buf.count; } @@ -807,11 +821,12 @@ return -EINVAL; buf->count++; dirent = buf->dirent; - put_user(ino, &dirent->d_ino); - put_user(offset, &dirent->d_offset); - put_user(namlen, &dirent->d_namlen); - copy_to_user(dirent->d_name, name, namlen); - put_user(0, dirent->d_name + namlen); + if (put_user(ino, &dirent->d_ino) + || put_user(offset, &dirent->d_offset) + || put_user(namlen, &dirent->d_namlen) + || copy_to_user(dirent->d_name, name, namlen) + || put_user(0, dirent->d_name + namlen)) + return -EFAULT; return 0; } @@ -862,8 +877,10 @@ if (tvp32) { time_t sec, usec; - get_user(sec, &tvp32->tv_sec); - get_user(usec, &tvp32->tv_usec); + ret = -EFAULT; + if (get_user(sec, &tvp32->tv_sec) + || get_user(usec, &tvp32->tv_usec)) + goto out_nofds; ret = -EINVAL; if (sec < 0 || usec < 0) @@ -916,8 +933,12 @@ usec = timeout % HZ; usec *= (1000000/HZ); } - put_user(sec, (int *)&tvp32->tv_sec); - put_user(usec, (int *)&tvp32->tv_usec); + if (put_user(sec, (int *)&tvp32->tv_sec) + || put_user(usec, (int *)&tvp32->tv_usec)) + { + ret = -EFAULT; + goto out; + } } if (ret < 0) @@ -1558,16 +1579,15 @@ { union semun fourth; u32 pad; - int err, err2; + int err = 0, err2; struct semid64_ds s; struct semid_ds32 *usp; mm_segment_t old_fs; if (!uptr) return -EINVAL; - err = -EFAULT; - if (get_user (pad, (u32 *)uptr)) - return err; + if (get_user(pad, (u32 *)uptr)) + return -EFAULT; if(third == SETVAL) fourth.val = (int)pad; else @@ -1749,15 +1769,14 @@ { unsigned long raddr; u32 *uaddr = (u32 *)A((u32)third); - int err = -EINVAL; + int err; if (version == 1) - return err; + return -EINVAL; err = sys_shmat (first, uptr, second, &raddr); if (err) return err; - err = put_user (raddr, uaddr); - return err; + return put_user(raddr, uaddr); } static int @@ -1886,8 +1905,7 @@ break; case SHMAT: - err = do_sys32_shmat (first, second, third, - version, (void *)AA(ptr)); + err = do_sys32_shmat (first, second, third, version, (void *)AA(ptr)); break; case SHMDT: err = sys_shmdt ((char *)AA(ptr)); @@ -2125,7 +2143,7 @@ case PT_CS: return((unsigned int)__USER_CS); default: - printk("getregs:unknown register %d\n", regno); + printk(KERN_ERR "getregs:unknown register %d\n", regno); break; } @@ -2177,14 +2195,16 @@ case PT_GS: case PT_SS: if (value != __USER_DS) - printk("setregs:try to set invalid segment register %d = %x\n", regno, value); + printk(KERN_ERR "setregs:try to set invalid segment register %d = %x\n", + regno, value); break; case PT_CS: if (value != __USER_CS) - printk("setregs:try to set invalid segment register %d = %x\n", regno, value); + printk(KERN_ERR "setregs:try to set invalid segment register %d = %x\n", + regno, value); break; default: - printk("getregs:unknown register %d\n", regno); + printk(KERN_ERR "getregs:unknown register %d\n", regno); break; } @@ -2240,7 +2260,6 @@ } __copy_to_user(reg, f, sizeof(*reg)); - return; } void @@ -2334,8 +2353,8 @@ * the address of `stack' will not be the address of the `pt_regs'. */ asmlinkage long -sys32_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, - long arg4, long arg5, long arg6, long arg7, long stack) +sys32_ptrace (int request, pid_t pid, unsigned int addr, unsigned int data, + long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *regs = (struct pt_regs *) &stack; struct task_struct *child; @@ -2379,7 +2398,7 @@ case PTRACE_PEEKDATA: /* read word at location addr */ ret = ia32_peek(regs, child, addr, &value); if (ret == 0) - ret = put_user(value, (unsigned int *)data); + ret = put_user(value, (unsigned int *)A(data)); else ret = -EIO; goto out; @@ -2398,12 +2417,12 @@ break; case IA32_PTRACE_GETREGS: - if (!access_ok(VERIFY_WRITE, (int *)data, 17*sizeof(int))) { + if (!access_ok(VERIFY_WRITE, (int *) A(data), 17*sizeof(int))) { ret = -EIO; break; } for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) { - __put_user(getreg(child, i),(unsigned int *) data); + __put_user(getreg(child, i), (unsigned int *) A(data)); data += sizeof(int); } ret = 0; @@ -2412,12 +2431,12 @@ case IA32_PTRACE_SETREGS: { unsigned int tmp; - if (!access_ok(VERIFY_READ, (int *)data, 17*sizeof(int))) { + if (!access_ok(VERIFY_READ, (int *) A(data), 17*sizeof(int))) { ret = -EIO; break; } for ( i = 0; i < 17*sizeof(int); i += sizeof(int) ) { - __get_user(tmp, (unsigned int *) data); + __get_user(tmp, (unsigned int *) A(data)); putreg(child, i, tmp); data += sizeof(int); } @@ -2426,11 +2445,11 @@ } case IA32_PTRACE_GETFPREGS: - ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *)data); + ret = save_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data)); break; case IA32_PTRACE_SETFPREGS: - ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *)data); + ret = restore_ia32_fpstate(child, (struct _fpstate_ia32 *) A(data)); break; case PTRACE_SYSCALL: /* continue, stop after next syscall */ @@ -2547,8 +2566,8 @@ { struct pt_regs *regs = (struct pt_regs *)&stack; - printk("IA32 syscall #%d issued, maybe we should implement it\n", - (int)regs->r1); + printk(KERN_WARNING "IA32 syscall #%d issued, maybe we should implement it\n", + (int)regs->r1); return(sys_ni_syscall()); } @@ -2558,7 +2577,7 @@ #define IOLEN ((65536 / 4) * 4096) asmlinkage long -sys_iopl (int level, long arg1, long arg2, long arg3) +sys_iopl (int level) { extern unsigned long ia64_iobase; int fd; @@ -2570,7 +2589,7 @@ if (level != 3) return(-EINVAL); /* Trying to gain more privileges? */ - __asm__ __volatile__("mov %0=ar.eflag ;;" : "=r"(old)); + asm volatile ("mov %0=ar.eflag ;;" : "=r"(old)); if (level > ((old >> 12) & 3)) { if (!capable(CAP_SYS_RAWIO)) return -EPERM; @@ -2587,17 +2606,13 @@ } down_write(¤t->mm->mmap_sem); - lock_kernel(); - addr = do_mmap_pgoff(file, IA32_IOBASE, - IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED, - (ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT); - - unlock_kernel(); + IOLEN, PROT_READ|PROT_WRITE, MAP_SHARED, + (ia64_iobase & ~PAGE_OFFSET) >> PAGE_SHIFT); up_write(¤t->mm->mmap_sem); if (addr >= 0) { - __asm__ __volatile__("mov ar.k0=%0 ;;" :: "r"(addr)); + ia64_set_kr(IA64_KR_IO_BASE, addr); old = (old & ~0x3000) | (level << 12); __asm__ __volatile__("mov ar.eflag=%0 ;;" :: "r"(old)); } @@ -2608,7 +2623,7 @@ } asmlinkage long -sys_ioperm (unsigned long from, unsigned long num, int on) +sys_ioperm (unsigned int from, unsigned int num, int on) { /* @@ -2621,7 +2636,7 @@ * XXX proper ioperm() support should be emulated by * manipulating the page protections... */ - return(sys_iopl(3, 0, 0, 0)); + return sys_iopl(3); } typedef struct { @@ -2750,6 +2765,54 @@ return ret; } +extern asmlinkage long sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); + +asmlinkage long +sys32_getresuid (u16 *ruid, u16 *euid, u16 *suid) +{ + uid_t a, b, c; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + ret = sys_getresuid(&a, &b, &c); + set_fs(old_fs); + + if (put_user(a, ruid) || put_user(b, euid) || put_user(c, suid)) + return -EFAULT; + return ret; +} + +extern asmlinkage long sys_getresgid (gid_t *rgid, gid_t *egid, gid_t *sgid); + +asmlinkage long +sys32_getresgid(u16 *rgid, u16 *egid, u16 *sgid) +{ + gid_t a, b, c; + int ret; + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + ret = sys_getresgid(&a, &b, &c); + set_fs(old_fs); + + if (!ret) { + ret = put_user(a, rgid); + ret |= put_user(b, egid); + ret |= put_user(c, sgid); + } + return ret; +} + +int +sys32_lseek (unsigned int fd, int offset, unsigned int whence) +{ + extern off_t sys_lseek (unsigned int fd, off_t offset, unsigned int origin); + + /* Sign-extension of "offset" is important here... */ + return sys_lseek(fd, offset, whence); +} + #ifdef NOTYET /* UNTESTED FOR IA64 FROM HERE DOWN */ /* In order to reduce some races, while at the same time doing additional @@ -3235,7 +3298,7 @@ siginfo_t32 * siginfo64to32(siginfo_t32 *d, siginfo_t *s) { - memset (&d, 0, sizeof(siginfo_t32)); + memset(d, 0, sizeof(siginfo_t32)); d->si_signo = s->si_signo; d->si_errno = s->si_errno; d->si_code = s->si_code; @@ -3440,27 +3503,6 @@ segid = (egid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)egid); ssgid = (sgid == (__kernel_gid_t32)-1) ? ((gid_t)-1) : ((gid_t)sgid); return sys_setresgid(srgid, segid, ssgid); -} - -extern asmlinkage long sys_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); - -asmlinkage long -sys32_getresgid(__kernel_gid_t32 *rgid, __kernel_gid_t32 *egid, - __kernel_gid_t32 *sgid) -{ - gid_t a, b, c; - int ret; - mm_segment_t old_fs = get_fs(); - - set_fs (KERNEL_DS); - ret = sys_getresgid(&a, &b, &c); - set_fs (old_fs); - if (!ret) { - ret = put_user (a, rgid); - ret |= put_user (b, egid); - ret |= put_user (c, sgid); - } - return ret; } extern asmlinkage long sys_getgroups(int gidsetsize, gid_t *grouplist); diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/Makefile linux/arch/ia64/kernel/Makefile --- v2.4.7/linux/arch/ia64/kernel/Makefile Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/Makefile Tue Jul 31 10:30:08 2001 @@ -13,13 +13,13 @@ export-objs := ia64_ksyms.o -obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_sapic.o ivt.o \ +obj-y := acpi.o entry.o gate.o efi.o efi_stub.o ia64_ksyms.o irq.o irq_ia64.o irq_lsapic.o ivt.o \ machvec.o pal.o process.o perfmon.o ptrace.o sal.o semaphore.o setup.o \ signal.o sys_ia64.o traps.o time.o unaligned.o unwind.o obj-$(CONFIG_IA64_GENERIC) += machvec.o iosapic.o obj-$(CONFIG_IA64_DIG) += iosapic.o obj-$(CONFIG_IA64_PALINFO) += palinfo.o -obj-$(CONFIG_IA64_EFIVARS) += efivars.o +obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_SMP) += smp.o smpboot.o obj-$(CONFIG_IA64_MCA) += mca.o mca_asm.o diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/acpi.c linux/arch/ia64/kernel/acpi.c --- v2.4.7/linux/arch/ia64/kernel/acpi.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/acpi.c Tue Jul 31 10:30:08 2001 @@ -25,14 +25,12 @@ #include #include +#include #include #include #include #include #include -#ifdef CONFIG_ACPI_KERNEL_CONFIG -# include -#endif #undef ACPI_DEBUG /* Guess what this does? */ @@ -40,7 +38,8 @@ int __initdata available_cpus; int __initdata total_cpus; -void (*pm_idle)(void); +void (*pm_idle) (void); +void (*pm_power_off) (void); asm (".weak iosapic_register_legacy_irq"); asm (".weak iosapic_init"); @@ -206,11 +205,21 @@ case ACPI20_ENTRY_IO_SAPIC: iosapic = (acpi_entry_iosapic_t *) p; if (iosapic_init) - iosapic_init(iosapic->address, iosapic->irq_base); + /* + * The PCAT_COMPAT flag indicates that the system has a + * dual-8259 compatible setup. + */ + iosapic_init(iosapic->address, iosapic->irq_base, +#ifdef CONFIG_ITANIUM + 1 /* fw on some Itanium systems is broken... */ +#else + (madt->flags & MADT_PCAT_COMPAT) +#endif + ); break; case ACPI20_ENTRY_PLATFORM_INT_SOURCE: - printk("ACPI 2.0 MADT: PLATFORM INT SOUCE\n"); + printk("ACPI 2.0 MADT: PLATFORM INT SOURCE\n"); acpi20_platform(p); break; @@ -257,6 +266,7 @@ int __init acpi20_parse (acpi20_rsdp_t *rsdp20) { +# ifdef CONFIG_ACPI acpi_xsdt_t *xsdt; acpi_desc_table_hdr_t *hdrp; int tables, i; @@ -287,9 +297,7 @@ hdrp->oem_revision >> 16, hdrp->oem_revision & 0xffff); -#ifdef CONFIG_ACPI_KERNEL_CONFIG acpi_cf_init((void *)rsdp20); -#endif tables =(hdrp->length -sizeof(acpi_desc_table_hdr_t))>>3; @@ -305,17 +313,16 @@ acpi20_parse_madt((acpi_madt_t *) hdrp); } -#ifdef CONFIG_ACPI_KERNEL_CONFIG acpi_cf_terminate(); -#endif -#ifdef CONFIG_SMP +# ifdef CONFIG_SMP if (available_cpus == 0) { printk("ACPI: Found 0 CPUS; assuming 1\n"); available_cpus = 1; /* We've got at least one of these, no? */ } smp_boot_data.cpu_count = total_cpus; -#endif +# endif +# endif /* CONFIG_ACPI */ return 1; } /* @@ -395,7 +402,12 @@ case ACPI_ENTRY_IO_SAPIC: iosapic = (acpi_entry_iosapic_t *) p; if (iosapic_init) - iosapic_init(iosapic->address, iosapic->irq_base); + /* + * The ACPI I/O SAPIC table doesn't have a PCAT_COMPAT + * flag like the MADT table, but we can safely assume that + * ACPI 1.0b systems have a dual-8259 setup. + */ + iosapic_init(iosapic->address, iosapic->irq_base, 1); break; case ACPI_ENTRY_INT_SRC_OVERRIDE: @@ -421,6 +433,7 @@ int __init acpi_parse (acpi_rsdp_t *rsdp) { +# ifdef CONFIG_ACPI acpi_rsdt_t *rsdt; acpi_desc_table_hdr_t *hdrp; long tables, i; @@ -439,9 +452,7 @@ printk("ACPI: %.6s %.8s %d.%d\n", rsdt->header.oem_id, rsdt->header.oem_table_id, rsdt->header.oem_revision >> 16, rsdt->header.oem_revision & 0xffff); -#ifdef CONFIG_ACPI_KERNEL_CONFIG acpi_cf_init(rsdp); -#endif tables = (rsdt->header.length - sizeof(acpi_desc_table_hdr_t)) / 8; for (i = 0; i < tables; i++) { @@ -454,16 +465,15 @@ acpi_parse_msapic((acpi_sapic_t *) hdrp); } -#ifdef CONFIG_ACPI_KERNEL_CONFIG acpi_cf_terminate(); -#endif -#ifdef CONFIG_SMP +# ifdef CONFIG_SMP if (available_cpus == 0) { printk("ACPI: Found 0 CPUS; assuming 1\n"); available_cpus = 1; /* We've got at least one of these, no? */ } smp_boot_data.cpu_count = total_cpus; -#endif +# endif +# endif /* CONFIG_ACPI */ return 1; } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/efi.c linux/arch/ia64/kernel/efi.c --- v2.4.7/linux/arch/ia64/kernel/efi.c Thu Apr 12 12:16:35 2001 +++ linux/arch/ia64/kernel/efi.c Tue Jul 31 10:30:08 2001 @@ -18,10 +18,12 @@ * Goutham Rao: * Skip non-WB memory and ignore empty memory ranges. */ +#include #include #include #include #include +#include #include #include @@ -36,6 +38,17 @@ struct efi efi; static efi_runtime_services_t *runtime; +/* + * efi_dir is allocated here, but the directory isn't created + * here, as proc_mkdir() doesn't work this early in the bootup + * process. Therefore, each module, like efivars, must test for + * if (!efi_dir) efi_dir = proc_mkdir("efi", NULL); + * prior to creating their own entries under /proc/efi. + */ +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *efi_dir = NULL; +#endif + static unsigned long mem_limit = ~0UL; static efi_status_t @@ -220,10 +233,8 @@ /* * The only ITLB entry in region 7 that is used is the one installed by * __start(). That entry covers a 64MB range. - * - * XXX Fixme: should be dynamic here (for page size) */ - mask = ~((1 << _PAGE_SIZE_64M) - 1); + mask = ~((1 << KERNEL_PG_SHIFT) - 1); vaddr = PAGE_OFFSET + md->phys_addr; /* @@ -246,14 +257,14 @@ printk("CPU %d: mapping PAL code [0x%lx-0x%lx) into [0x%lx-0x%lx)\n", smp_processor_id(), md->phys_addr, md->phys_addr + (md->num_pages << 12), - vaddr & mask, (vaddr & mask) + 64*1024*1024); + vaddr & mask, (vaddr & mask) + KERNEL_PG_SIZE); /* * Cannot write to CRx with PSR.ic=1 */ ia64_clear_ic(flags); ia64_itr(0x1, IA64_TR_PALCODE, vaddr & mask, - pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), _PAGE_SIZE_64M); + pte_val(mk_pte_phys(md->phys_addr, PAGE_KERNEL)), KERNEL_PG_SHIFT); local_irq_restore(flags); ia64_srlz_i(); } @@ -440,4 +451,36 @@ efi.set_variable = __va(runtime->set_variable); efi.get_next_high_mono_count = __va(runtime->get_next_high_mono_count); efi.reset_system = __va(runtime->reset_system); +} + +/* + * Walk the EFI memory map looking for the I/O port range. There can only be one entry of + * this type, other I/O port ranges should be described via ACPI. + */ +u64 +efi_get_iobase (void) +{ + void *efi_map_start, *efi_map_end, *p; + efi_memory_desc_t *md; + u64 efi_desc_size; + + efi_map_start = __va(ia64_boot_param->efi_memmap); + efi_map_end = efi_map_start + ia64_boot_param->efi_memmap_size; + efi_desc_size = ia64_boot_param->efi_memdesc_size; + + for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) { + md = p; + if (md->type == EFI_MEMORY_MAPPED_IO_PORT_SPACE) { + /* paranoia attribute checking */ + if (md->attribute == (EFI_MEMORY_UC | EFI_MEMORY_RUNTIME)) + return md->phys_addr; + } + } + return 0; +} + +static void __exit +efivars_exit(void) +{ + remove_proc_entry(efi_dir->name, NULL); } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/efivars.c linux/arch/ia64/kernel/efivars.c --- v2.4.7/linux/arch/ia64/kernel/efivars.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/efivars.c Tue Jul 31 10:30:08 2001 @@ -6,8 +6,8 @@ * This code takes all variables accessible from EFI runtime and * exports them via /proc * - * Reads to /proc/efi/varname return an efi_variable_t structure. - * Writes to /proc/efi/varname must be an efi_variable_t structure. + * Reads to /proc/efi/vars/varname return an efi_variable_t structure. + * Writes to /proc/efi/vars/varname must be an efi_variable_t structure. * Writes with DataSize = 0 or Attributes = 0 deletes the variable. * Writes with a new value in VariableName+VendorGuid creates * a new variable. @@ -29,6 +29,15 @@ * * Changelog: * + * 20 April 2001 - Matt Domsch + * Moved vars from /proc/efi to /proc/efi/vars, and made + * efi.c own the /proc/efi directory. + * v0.03 release to linux-ia64@linuxia64.org + * + * 26 March 2001 - Matt Domsch + * At the request of Stephane, moved ownership of /proc/efi + * to efi.c, and now efivars lives under /proc/efi/vars. + * * 12 March 2001 - Matt Domsch * Feedback received from Stephane Eranian incorporated. * efivar_write() checks copy_from_user() return value. @@ -57,7 +66,7 @@ MODULE_AUTHOR("Matt Domsch "); MODULE_DESCRIPTION("/proc interface to EFI Variables"); -#define EFIVARS_VERSION "0.02 2001-Mar-12" +#define EFIVARS_VERSION "0.03 2001-Apr-20" static int efivar_read(char *page, char **start, off_t off, @@ -92,7 +101,7 @@ spinlock_t efivars_lock = SPIN_LOCK_UNLOCKED; static LIST_HEAD(efivar_list); -static struct proc_dir_entry *efi_dir = NULL; +static struct proc_dir_entry *efi_vars_dir = NULL; #define efivar_entry(n) list_entry(n, efivar_entry_t, list) @@ -188,7 +197,7 @@ /* Create the entry in proc */ - new_efivar->entry = create_proc_entry(short_name, 0600, efi_dir); + new_efivar->entry = create_proc_entry(short_name, 0600, efi_vars_dir); kfree(short_name); short_name = NULL; if (!new_efivar->entry) return 1; @@ -286,7 +295,7 @@ /* Since the data ptr we've currently got is probably for a different variable find the right variable. This allows any properly formatted data structure to - be written to any of the files in /proc/efi and it will work. + be written to any of the files in /proc/efi/vars and it will work. */ list_for_each(pos, &efivar_list) { search_efivar = efivar_entry(pos); @@ -320,7 +329,7 @@ if (!var_data->DataSize || !var_data->Attributes) { /* We just deleted the NVRAM variable */ - remove_proc_entry(efivar->entry->name, efi_dir); + remove_proc_entry(efivar->entry->name, efi_vars_dir); list_del(&efivar->list); kfree(efivar); } @@ -354,12 +363,22 @@ printk(KERN_INFO "EFI Variables Facility v%s\n", EFIVARS_VERSION); + /* Since efi.c happens before procfs is available, + we create the directory here if it doesn't + already exist. There's probably a better way + to do this. + */ + if (!efi_dir) + efi_dir = proc_mkdir("efi", NULL); + + efi_vars_dir = proc_mkdir("vars", efi_dir); + + + /* Per EFI spec, the maximum storage allocated for both the variable name and variable data is 1024 bytes. */ - efi_dir = proc_mkdir("efi", NULL); - memset(variable_name, 0, 1024); do { @@ -401,11 +420,11 @@ list_for_each(pos, &efivar_list) { efivar = efivar_entry(pos); - remove_proc_entry(efivar->entry->name, efi_dir); + remove_proc_entry(efivar->entry->name, efi_vars_dir); list_del(&efivar->list); kfree(efivar); } - remove_proc_entry(efi_dir->name, NULL); + remove_proc_entry(efi_vars_dir->name, efi_dir); spin_unlock(&efivars_lock); } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/entry.S linux/arch/ia64/kernel/entry.S --- v2.4.7/linux/arch/ia64/kernel/entry.S Wed Jul 25 17:10:17 2001 +++ linux/arch/ia64/kernel/entry.S Tue Jul 31 10:30:08 2001 @@ -140,8 +140,8 @@ dep r20=0,in0,61,3 // physical address of "current" ;; st8 [r22]=sp // save kernel stack pointer of old task - shr.u r26=r20,_PAGE_SIZE_64M - mov r16=1 + shr.u r26=r20,KERNEL_PG_SHIFT + mov r16=KERNEL_PG_NUM ;; cmp.ne p6,p7=r26,r16 // check >= 64M && < 128M adds r21=IA64_TASK_THREAD_KSP_OFFSET,in0 @@ -175,7 +175,7 @@ ;; srlz.d or r23=r25,r20 // construct PA | page properties - mov r25=_PAGE_SIZE_64M<<2 + mov r25=KERNEL_PG_SHIFT<<2 ;; mov cr.itir=r25 mov cr.ifa=in0 // VA of next task... @@ -212,23 +212,20 @@ .save @priunat,r17 mov r17=ar.unat // preserve caller's .body -#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) +#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) adds r3=80,sp ;; lfetch.fault.excl.nt1 [r3],128 #endif mov ar.rsc=0 // put RSE in mode: enforced lazy, little endian, pl 0 -#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) +#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) adds r2=16+128,sp ;; lfetch.fault.excl.nt1 [r2],128 lfetch.fault.excl.nt1 [r3],128 #endif adds r14=SW(R4)+16,sp -#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) +#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) ;; lfetch.fault.excl [r2] lfetch.fault.excl [r3] @@ -325,8 +322,7 @@ .prologue .altrp b7 .body -#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) +#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) lfetch.fault.nt1 [sp] #endif @@ -496,15 +492,13 @@ GLOBAL_ENTRY(ia64_ret_from_clone) PT_REGS_UNWIND_INFO(0) -#ifdef CONFIG_SMP /* - * In SMP mode, we need to call invoke_schedule_tail to complete the scheduling process. + * We need to call schedule_tail() to complete the scheduling process. * Called by ia64_switch_to after do_fork()->copy_thread(). r8 contains the * address of the previously executing task. */ br.call.sptk.few rp=invoke_schedule_tail .ret8: -#endif adds r2=IA64_TASK_PTRACE_OFFSET,r13 ;; ld8 r2=[r2] @@ -530,14 +524,9 @@ // fall through GLOBAL_ENTRY(ia64_leave_kernel) PT_REGS_UNWIND_INFO(0) - cmp.eq p16,p0=r0,r0 // set the "first_time" flag - movl r15=PERCPU_ADDR+IA64_CPU_SOFTIRQ_ACTIVE_OFFSET // r15 = &cpu_data.softirq.active - ;; - ld8 r2=[r15] + lfetch.fault [sp] movl r14=.restart ;; - lfetch.fault [sp] - shr.u r3=r2,32 // r3 = cpu_data.softirq.mask MOVBR(.ret.sptk,rp,r14,.restart) .restart: adds r17=IA64_TASK_NEED_RESCHED_OFFSET,r13 @@ -546,37 +535,28 @@ adds r19=IA64_TASK_PFM_NOTIFY_OFFSET,r13 #endif ;; - ld8 r17=[r17] // load current->need_resched - ld4 r18=[r18] // load current->sigpending -(p16) and r2=r2,r3 // r2 <- (softirq.active & softirq.mask) - ;; #ifdef CONFIG_PERFMON ld8 r19=[r19] // load current->task.pfm_notify #endif -(p16) cmp4.ne.unc p6,p0=r2,r0 // p6 <- (softirq.active & softirq.mask) != 0 -(pUser) cmp.ne.unc p7,p0=r17,r0 // current->need_resched != 0? + ld8 r17=[r17] // load current->need_resched + ld4 r18=[r18] // load current->sigpending ;; -(pUser) cmp.ne.unc p8,p0=r18,r0 // current->sigpending != 0? #ifdef CONFIG_PERFMON cmp.ne p9,p0=r19,r0 // current->task.pfm_notify != 0? #endif - cmp.ne p16,p0=r0,r0 // clear the "first_time" flag +(pUser) cmp.ne.unc p7,p0=r17,r0 // current->need_resched != 0? +(pUser) cmp.ne.unc p8,p0=r18,r0 // current->sigpending != 0? ;; -# if __GNUC__ < 3 -(p6) br.call.spnt.many b7=invoke_do_softirq -# else -(p6) br.call.spnt.many b7=do_softirq -# endif + adds r2=PT(R8)+16,r12 + adds r3=PT(R9)+16,r12 #ifdef CONFIG_PERFMON (p9) br.call.spnt.many b7=pfm_overflow_notify #endif -# if __GNUC__ < 3 +#if __GNUC__ < 3 (p7) br.call.spnt.many b7=invoke_schedule #else (p7) br.call.spnt.many b7=schedule #endif - adds r2=PT(R8)+16,r12 - adds r3=PT(R9)+16,r12 (p8) br.call.spnt.many b7=handle_signal_delivery // check & deliver pending signals ;; // start restoring the state saved on the kernel stack (struct pt_regs): @@ -634,14 +614,6 @@ ;; bsw.0 // switch back to bank 0 ;; -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC - nop.i 0x0 - ;; - nop.i 0x0 - ;; - nop.i 0x0 - ;; -#endif adds r16=16,r12 adds r17=24,r12 ;; @@ -792,7 +764,6 @@ br.cond.sptk.many ia64_leave_kernel END(handle_syscall_error) -# ifdef CONFIG_SMP /* * Invoke schedule_tail(task) while preserving in0-in7, which may be needed * in case a system call gets restarted. @@ -809,29 +780,7 @@ br.ret.sptk.many rp END(invoke_schedule_tail) -# endif /* CONFIG_SMP */ - #if __GNUC__ < 3 - /* - * Invoke do_softirq() while preserving in0-in7, which may be needed - * in case a system call gets restarted. Note that declaring do_softirq() - * with asmlinkage() is NOT enough because that will only preserve as many - * registers as there are formal arguments. - * - * XXX fix me: with gcc 3.0, we won't need this anymore because syscall_linkage - * renders all eight input registers (in0-in7) as "untouchable". - */ -ENTRY(invoke_do_softirq) - .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8) - alloc loc1=ar.pfs,8,2,0,0 - mov loc0=rp - ;; - .body - br.call.sptk.few rp=do_softirq -.ret13: mov ar.pfs=loc1 - mov rp=loc0 - br.ret.sptk.many rp -END(invoke_do_softirq) /* * Invoke schedule() while preserving in0-in7, which may be needed @@ -1187,7 +1136,7 @@ data8 sys_newfstat data8 sys_clone2 data8 sys_getdents64 - data8 ia64_ni_syscall // 1215 + data8 sys_getunwind // 1215 data8 ia64_ni_syscall data8 ia64_ni_syscall data8 ia64_ni_syscall diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/entry.h linux/arch/ia64/kernel/entry.h --- v2.4.7/linux/arch/ia64/kernel/entry.h Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/entry.h Tue Jul 31 10:30:08 2001 @@ -1,7 +1,7 @@ #include /* XXX fixme */ -#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC) +#if defined(CONFIG_ITANIUM_B1_SPECIFIC) # define MOVBR(type,br,gr,lbl) mov br=gr #else # define MOVBR(type,br,gr,lbl) mov##type br=gr,lbl diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/fw-emu.c linux/arch/ia64/kernel/fw-emu.c --- v2.4.7/linux/arch/ia64/kernel/fw-emu.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/fw-emu.c Tue Jul 31 10:30:08 2001 @@ -20,7 +20,7 @@ #define MB (1024*1024UL) -#define NUM_MEM_DESCS 2 +#define NUM_MEM_DESCS 3 static char fw_mem[( sizeof(struct ia64_boot_param) + sizeof(efi_system_table_t) @@ -121,68 +121,63 @@ */ extern void pal_emulator_static (void); -asm (" - .proc pal_emulator_static -pal_emulator_static: - mov r8=-1 - - mov r9=256 - ;; - cmp.gtu p6,p7=r9,r28 /* r28 <= 255? */ -(p6) br.cond.sptk.few static - ;; - mov r9=512 - ;; - cmp.gtu p6,p7=r9,r28 -(p6) br.cond.sptk.few stacked - ;; -static: cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */ -(p7) br.cond.sptk.few 1f - ;; - mov r8=0 /* status = 0 */ - movl r9=0x100000000 /* tc.base */ - movl r10=0x0000000200000003 /* count[0], count[1] */ - movl r11=0x1000000000002000 /* stride[0], stride[1] */ - br.cond.sptk.few rp - -1: cmp.eq p6,p7=14,r28 /* PAL_FREQ_RATIOS */ -(p7) br.cond.sptk.few 1f - mov r8=0 /* status = 0 */ - movl r9 =0x100000064 /* proc_ratio (1/100) */ - movl r10=0x100000100 /* bus_ratio<<32 (1/256) */ - movl r11=0x100000064 /* itc_ratio<<32 (1/100) */ - ;; -1: cmp.eq p6,p7=19,r28 /* PAL_RSE_INFO */ -(p7) br.cond.sptk.few 1f - mov r8=0 /* status = 0 */ - mov r9=96 /* num phys stacked */ - mov r10=0 /* hints */ - mov r11=0 - br.cond.sptk.few rp - -1: cmp.eq p6,p7=1,r28 /* PAL_CACHE_FLUSH */ -(p7) br.cond.sptk.few 1f - mov r9=ar.lc - movl r8=524288 /* flush 512k million cache lines (16MB) */ - ;; - mov ar.lc=r8 - movl r8=0xe000000000000000 - ;; -.loop: fc r8 - add r8=32,r8 - br.cloop.sptk.few .loop - sync.i - ;; - srlz.i - ;; - mov ar.lc=r9 - mov r8=r0 -1: br.cond.sptk.few rp - -stacked: - br.ret.sptk.few rp - - .endp pal_emulator_static\n"); +asm ( +" .proc pal_emulator_static\n" +"pal_emulator_static:" +" mov r8=-1\n" +" mov r9=256\n" +" ;;\n" +" cmp.gtu p6,p7=r9,r28 /* r28 <= 255? */\n" +"(p6) br.cond.sptk.few static\n" +" ;;\n" +" mov r9=512\n" +" ;;\n" +" cmp.gtu p6,p7=r9,r28\n" +"(p6) br.cond.sptk.few stacked\n" +" ;;\n" +"static: cmp.eq p6,p7=6,r28 /* PAL_PTCE_INFO */\n" +"(p7) br.cond.sptk.few 1f\n" +" ;;\n" +" mov r8=0 /* status = 0 */\n" +" movl r9=0x100000000 /* tc.base */\n" +" movl r10=0x0000000200000003 /* count[0], count[1] */\n" +" movl r11=0x1000000000002000 /* stride[0], stride[1] */\n" +" br.cond.sptk.few rp\n" +"1: cmp.eq p6,p7=14,r28 /* PAL_FREQ_RATIOS */\n" +"(p7) br.cond.sptk.few 1f\n" +" mov r8=0 /* status = 0 */\n" +" movl r9 =0x100000064 /* proc_ratio (1/100) */\n" +" movl r10=0x100000100 /* bus_ratio<<32 (1/256) */\n" +" movl r11=0x100000064 /* itc_ratio<<32 (1/100) */\n" +" ;;\n" +"1: cmp.eq p6,p7=19,r28 /* PAL_RSE_INFO */\n" +"(p7) br.cond.sptk.few 1f\n" +" mov r8=0 /* status = 0 */\n" +" mov r9=96 /* num phys stacked */\n" +" mov r10=0 /* hints */\n" +" mov r11=0\n" +" br.cond.sptk.few rp\n" +"1: cmp.eq p6,p7=1,r28 /* PAL_CACHE_FLUSH */\n" +"(p7) br.cond.sptk.few 1f\n" +" mov r9=ar.lc\n" +" movl r8=524288 /* flush 512k million cache lines (16MB) */\n" +" ;;\n" +" mov ar.lc=r8\n" +" movl r8=0xe000000000000000\n" +" ;;\n" +".loop: fc r8\n" +" add r8=32,r8\n" +" br.cloop.sptk.few .loop\n" +" sync.i\n" +" ;;\n" +" srlz.i\n" +" ;;\n" +" mov ar.lc=r9\n" +" mov r8=r0\n" +"1: br.cond.sptk.few rp\n" +"stacked:\n" +" br.ret.sptk.few rp\n" +" .endp pal_emulator_static\n"); /* Macro to emulate SAL call using legacy IN and OUT calls to CF8, CFC etc.. */ @@ -437,8 +432,17 @@ sal_systab->checksum = -checksum; - /* fill in a memory descriptor: */ + /* simulate free memory at physical address zero */ md = &efi_memmap[0]; + md->type = EFI_BOOT_SERVICES_DATA; + md->pad = 0; + md->phys_addr = 0*MB; + md->virt_addr = 0; + md->num_pages = (1*MB) >> 12; /* 1MB (in 4KB pages) */ + md->attribute = EFI_MEMORY_WB; + + /* fill in a memory descriptor: */ + md = &efi_memmap[1]; md->type = EFI_CONVENTIONAL_MEMORY; md->pad = 0; md->phys_addr = 2*MB; @@ -447,7 +451,7 @@ md->attribute = EFI_MEMORY_WB; /* descriptor for firmware emulator: */ - md = &efi_memmap[1]; + md = &efi_memmap[2]; md->type = EFI_PAL_CODE; md->pad = 0; md->phys_addr = 1*MB; @@ -462,7 +466,7 @@ */ /* descriptor for high memory (>4GB): */ - md = &efi_memmap[2]; + md = &efi_memmap[3]; md->type = EFI_CONVENTIONAL_MEMORY; md->pad = 0; md->phys_addr = 4096*MB; diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/gate.S linux/arch/ia64/kernel/gate.S --- v2.4.7/linux/arch/ia64/kernel/gate.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/gate.S Tue Jul 31 10:30:08 2001 @@ -15,15 +15,23 @@ .section .text.gate,"ax" - .align PAGE_SIZE +# define ARG0_OFF (16 + IA64_SIGFRAME_ARG0_OFFSET) +# define ARG1_OFF (16 + IA64_SIGFRAME_ARG1_OFFSET) +# define ARG2_OFF (16 + IA64_SIGFRAME_ARG2_OFFSET) +# define RBS_BASE_OFF (16 + IA64_SIGFRAME_RBS_BASE_OFFSET) +# define SIGHANDLER_OFF (16 + IA64_SIGFRAME_HANDLER_OFFSET) +# define SIGCONTEXT_OFF (16 + IA64_SIGFRAME_SIGCONTEXT_OFFSET) -# define SIGINFO_OFF 16 -# define SIGCONTEXT_OFF (SIGINFO_OFF + ((IA64_SIGINFO_SIZE + 15) & ~15)) # define FLAGS_OFF IA64_SIGCONTEXT_FLAGS_OFFSET # define CFM_OFF IA64_SIGCONTEXT_CFM_OFFSET # define FR6_OFF IA64_SIGCONTEXT_FR6_OFFSET # define BSP_OFF IA64_SIGCONTEXT_AR_BSP_OFFSET # define RNAT_OFF IA64_SIGCONTEXT_AR_RNAT_OFFSET +# define UNAT_OFF IA64_SIGCONTEXT_AR_UNAT_OFFSET +# define FPSR_OFF IA64_SIGCONTEXT_AR_FPSR_OFFSET +# define PR_OFF IA64_SIGCONTEXT_PR_OFFSET +# define RP_OFF IA64_SIGCONTEXT_B0_OFFSET +# define SP_OFF IA64_SIGCONTEXT_R12_OFFSET # define base0 r2 # define base1 r3 /* @@ -31,17 +39,9 @@ * * +===============================+ * | | - * // struct sigcontext // + * // struct sigframe // * | | - * +===============================+ <-- sp+SIGCONTEXT_OFF - * | | - * // rest of siginfo // - * | | - * + +---------------+ - * | | siginfo.code | - * +---------------+---------------+ - * | siginfo.errno | siginfo.signo | - * +-------------------------------+ <-- sp+SIGINFO_OFF + * +-------------------------------+ <-- sp+16 * | 16 byte of scratch | * | space | * +-------------------------------+ <-- sp @@ -51,46 +51,60 @@ * incoming general register may be a NaT value (including sp, in which case the * process ends up dying with a SIGSEGV). * - * The first need to do is a cover to get the registers onto the backing store. - * Once that is done, we invoke the signal handler which may modify some of the - * machine state. After returning from the signal handler, we return control to - * the previous context by executing a sigreturn system call. A signal handler - * may call the rt_sigreturn() function to directly return to a given sigcontext. - * However, the user-level sigreturn() needs to do much more than calling the - * rt_sigreturn() system call as it needs to unwind the stack to restore preserved - * registers that may have been saved on the signal handler's call stack. - * - * On entry: - * r2 = signal number - * r3 = plabel of signal handler - * r15 = new register backing store - * [sp+16] = sigframe + * The first thing need to do is a cover to get the registers onto the backing + * store. Once that is done, we invoke the signal handler which may modify some + * of the machine state. After returning from the signal handler, we return + * control to the previous context by executing a sigreturn system call. A signal + * handler may call the rt_sigreturn() function to directly return to a given + * sigcontext. However, the user-level sigreturn() needs to do much more than + * calling the rt_sigreturn() system call as it needs to unwind the stack to + * restore preserved registers that may have been saved on the signal handler's + * call stack. */ GLOBAL_ENTRY(ia64_sigtramp) - ld8 r10=[r3],8 // get signal handler entry point - br.call.sptk.many rp=invoke_sighandler -END(ia64_sigtramp) - -ENTRY(invoke_sighandler) - ld8 gp=[r3] // get signal handler's global pointer - mov b6=r10 + // describe the state that is active when we get here: + .prologue + .unwabi @svr4, 's' // mark this as a sigtramp handler (saves scratch regs) + .savesp ar.unat, UNAT_OFF+SIGCONTEXT_OFF + .savesp ar.fpsr, FPSR_OFF+SIGCONTEXT_OFF + .savesp pr, PR_OFF+SIGCONTEXT_OFF + .savesp rp, RP_OFF+SIGCONTEXT_OFF + .vframesp SP_OFF+SIGCONTEXT_OFF + .body + + .prologue + adds base0=SIGHANDLER_OFF,sp + adds base1=RBS_BASE_OFF,sp + br.call.sptk.many rp=1f +1: + ld8 r17=[base0],(ARG0_OFF-SIGHANDLER_OFF) // get pointer to signal handler's plabel + ld8 r15=[base1],(ARG1_OFF-RBS_BASE_OFF) // get address of new RBS base (or NULL) cover // push args in interrupted frame onto backing store ;; + .save ar.pfs, r8 alloc r8=ar.pfs,0,0,3,0 // get CFM0, EC0, and CPL0 into r8 + ld8 out0=[base0],16 // load arg0 (signum) ;; - mov r17=ar.bsp // fetch ar.bsp + ld8 out1=[base1] // load arg1 (siginfop) + ld8 r10=[r17],8 // get signal handler entry point + ;; + ld8 out2=[base0] // load arg2 (sigcontextp) + ld8 gp=[r17] // get signal handler's global pointer cmp.ne p8,p0=r15,r0 // do we need to switch the rbs? - mov out0=r2 // signal number + + mov.m r17=ar.bsp // fetch ar.bsp + .spillsp.p p8, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF (p8) br.cond.spnt.few setup_rbs // yup -> (clobbers r14 and r16) back_from_setup_rbs: adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp ;; + .spillsp ar.bsp, BSP_OFF+SIGCONTEXT_OFF st8 [base0]=r17,(CFM_OFF-BSP_OFF) // save sc_ar_bsp - dep r8=0,r8,38,26 // clear EC0, CPL0 and reserved bits + dep r8=0,r8,38,26 // clear EC0, CPL0 and reserved bits adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp ;; - + .spillsp ar.pfs, CFM_OFF st8 [base0]=r8 // save CFM0 adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp ;; @@ -99,14 +113,13 @@ ;; stf.spill [base0]=f8,32 stf.spill [base1]=f9,32 + mov b6=r10 ;; stf.spill [base0]=f10,32 stf.spill [base1]=f11,32 - adds out1=SIGINFO_OFF,sp // siginfo pointer ;; stf.spill [base0]=f12,32 stf.spill [base1]=f13,32 - adds out2=SIGCONTEXT_OFF,sp // sigcontext pointer ;; stf.spill [base0]=f14,32 stf.spill [base1]=f15,32 @@ -140,9 +153,8 @@ ldf.fill f15=[base1],32 mov r15=__NR_rt_sigreturn break __BREAK_SYSCALL -END(invoke_sighandler) -ENTRY(setup_rbs) +setup_rbs: flushrs // must be first in insn mov ar.rsc=0 // put RSE into enforced lazy mode adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp @@ -150,13 +162,13 @@ mov r14=ar.rnat // get rnat as updated by flushrs mov ar.bspstore=r15 // set new register backing store area ;; + .spillsp ar.rnat, RNAT_OFF+SIGCONTEXT_OFF st8 [r16]=r14 // save sc_ar_rnat mov ar.rsc=0xf // set RSE into eager mode, pl 3 invala // invalidate ALAT br.cond.sptk.many back_from_setup_rbs -END(setup_rbs) -ENTRY(restore_rbs) +restore_rbs: flushrs mov ar.rsc=0 // put RSE into enforced lazy mode adds r16=(RNAT_OFF+SIGCONTEXT_OFF),sp @@ -168,4 +180,4 @@ mov ar.rsc=0xf // (will be restored later on from sc_ar_rsc) // invala not necessary as that will happen when returning to user-mode br.cond.sptk.many back_from_restore_rbs -END(restore_rbs) +END(ia64_sigtramp) diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/head.S linux/arch/ia64/kernel/head.S --- v2.4.7/linux/arch/ia64/kernel/head.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/head.S Tue Jul 31 10:30:08 2001 @@ -63,17 +63,17 @@ * that maps the kernel's text and data: */ rsm psr.i | psr.ic - mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (_PAGE_SIZE_64M << 2)) + mov r16=((ia64_rid(IA64_REGION_ID_KERNEL, PAGE_OFFSET) << 8) | (KERNEL_PG_SHIFT << 2)) ;; srlz.i - mov r18=_PAGE_SIZE_64M<<2 - movl r17=PAGE_OFFSET + 64*1024*1024 + mov r18=KERNEL_PG_SHIFT<<2 + movl r17=PAGE_OFFSET + KERNEL_PG_NUM*KERNEL_PG_SIZE ;; mov rr[r17]=r16 mov cr.itir=r18 mov cr.ifa=r17 mov r16=IA64_TR_KERNEL - movl r18=(64*1024*1024 | PAGE_KERNEL) + movl r18=(KERNEL_PG_NUM*KERNEL_PG_SIZE | PAGE_KERNEL) ;; srlz.i ;; @@ -111,7 +111,7 @@ ;; #ifdef CONFIG_IA64_EARLY_PRINTK - mov r3=(6<<8) | (_PAGE_SIZE_64M<<2) + mov r3=(6<<8) | (KERNEL_PG_SHIFT<<2) movl r2=6<<61 ;; mov rr[r2]=r3 @@ -123,11 +123,12 @@ #define isAP p2 // are we an Application Processor? #define isBP p3 // are we the Bootstrap Processor? +#ifdef CONFIG_SMP /* * Find the init_task for the currently booting CPU. At poweron, and in - * UP mode, cpu_now_booting is 0. + * UP mode, cpucount is 0. */ - movl r3=cpu_now_booting + movl r3=cpucount ;; ld4 r3=[r3] // r3 <- smp_processor_id() movl r2=init_tasks @@ -135,6 +136,11 @@ shladd r2=r3,3,r2 ;; ld8 r2=[r2] +#else + mov r3=0 + movl r2=init_task_union + ;; +#endif cmp4.ne isAP,isBP=r3,r0 ;; // RAW on r2 extr r3=r2,0,61 // r3 == phys addr of task struct @@ -182,7 +188,7 @@ #endif /* CONFIG_IA64_EARLY_PRINTK */ #ifdef CONFIG_SMP -(isAP) br.call.sptk.few rp=smp_callin +(isAP) br.call.sptk.few rp=start_secondary .ret0: (isAP) br.cond.sptk.few self #endif @@ -212,8 +218,7 @@ add r19=IA64_NUM_DBG_REGS*8,in0 ;; 1: mov r16=dbr[r18] -#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) \ - || defined(CONFIG_ITANIUM_C0_SPECIFIC) +#if defined(CONFIG_ITANIUM_C0_SPECIFIC) ;; srlz.d #endif @@ -230,8 +235,7 @@ GLOBAL_ENTRY(ia64_load_debug_regs) alloc r16=ar.pfs,1,0,0,0 -#if !(defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) \ - || defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) +#if !(defined(CONFIG_ITANIUM_B0_SPECIFIC) || defined(CONFIG_ITANIUM_B1_SPECIFIC)) lfetch.nta [in0] #endif mov r20=ar.lc // preserve ar.lc @@ -244,8 +248,7 @@ add r18=1,r18 ;; mov dbr[r18]=r16 -#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) \ - || defined(CONFIG_ITANIUM_C0_SPECIFIC) +#if defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) || defined(CONFIG_ITANIUM_C0_SPECIFIC) ;; srlz.d #endif diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/ia64_ksyms.c linux/arch/ia64/kernel/ia64_ksyms.c --- v2.4.7/linux/arch/ia64/kernel/ia64_ksyms.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/ia64_ksyms.c Tue Jul 31 10:30:08 2001 @@ -7,6 +7,7 @@ #include EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(memcmp); EXPORT_SYMBOL_NOVERS(memcpy); EXPORT_SYMBOL(memmove); @@ -30,6 +31,9 @@ EXPORT_SYMBOL(disable_irq); EXPORT_SYMBOL(disable_irq_nosync); +#include +EXPORT_SYMBOL(probe_irq_mask); + #include #include /* not coded yet?? EXPORT_SYMBOL(csum_ipv6_magic); */ @@ -48,15 +52,14 @@ EXPORT_SYMBOL_NOVERS(__down_interruptible); EXPORT_SYMBOL_NOVERS(__down_trylock); EXPORT_SYMBOL_NOVERS(__up); -EXPORT_SYMBOL_NOVERS(__down_read_failed); -EXPORT_SYMBOL_NOVERS(__down_write_failed); -EXPORT_SYMBOL_NOVERS(__rwsem_wake); #include EXPORT_SYMBOL(clear_page); #include -EXPORT_SYMBOL(cpu_data); +# ifndef CONFIG_NUMA +EXPORT_SYMBOL(_cpu_data); +# endif EXPORT_SYMBOL(kernel_thread); #include @@ -78,6 +81,7 @@ EXPORT_SYMBOL(smp_call_function); EXPORT_SYMBOL(smp_call_function_single); EXPORT_SYMBOL(cpu_online_map); +EXPORT_SYMBOL(ia64_cpu_to_sapicid); #include EXPORT_SYMBOL(smp_num_cpus); @@ -137,3 +141,8 @@ extern struct efi efi; EXPORT_SYMBOL(efi); + +#include +extern struct proc_dir_entry *efi_dir; +EXPORT_SYMBOL(efi_dir); + diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/iosapic.c linux/arch/ia64/kernel/iosapic.c --- v2.4.7/linux/arch/ia64/kernel/iosapic.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/iosapic.c Tue Jul 31 10:30:08 2001 @@ -20,7 +20,7 @@ * Here is what the interrupt logic between a PCI device and the CPU looks like: * * (1) A PCI device raises one of the four interrupt pins (INTA, INTB, INTC, INTD). The - * device is uniquely identified by its bus-, device-, and slot-number (the function + * device is uniquely identified by its bus--, and slot-number (the function * number does not matter here because all functions share the same interrupt * lines). * @@ -51,6 +51,7 @@ #include #include +#include #include #include #include @@ -59,9 +60,6 @@ #include #include -#ifdef CONFIG_ACPI_KERNEL_CONFIG -# include -#endif #undef DEBUG_IRQ_ROUTING @@ -207,7 +205,45 @@ static void iosapic_set_affinity (unsigned int irq, unsigned long mask) { - printk("iosapic_set_affinity: not implemented yet\n"); +#ifdef CONFIG_SMP + unsigned long flags; + u32 high32, low32; + int dest, pin; + char *addr; + + mask &= (1UL << smp_num_cpus) - 1; + + if (!mask || irq >= IA64_NUM_VECTORS) + return; + + dest = cpu_physical_id(ffz(~mask)); + + pin = iosapic_irq[irq].pin; + addr = iosapic_irq[irq].addr; + + if (pin < 0) + return; /* not an IOSAPIC interrupt */ + + /* dest contains both id and eid */ + high32 = dest << IOSAPIC_DEST_SHIFT; + + spin_lock_irqsave(&iosapic_lock, flags); + { + /* get current delivery mode by reading the low32 */ + writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + low32 = readl(addr + IOSAPIC_WINDOW); + + /* change delivery mode to fixed */ + low32 &= ~(7 << IOSAPIC_DELIVERY_SHIFT); + low32 |= (IOSAPIC_FIXED << IOSAPIC_DELIVERY_SHIFT); + + writel(IOSAPIC_RTE_HIGH(pin), addr + IOSAPIC_REG_SELECT); + writel(high32, addr + IOSAPIC_WINDOW); + writel(IOSAPIC_RTE_LOW(pin), addr + IOSAPIC_REG_SELECT); + writel(low32, addr + IOSAPIC_WINDOW); + } + spin_unlock_irqrestore(&iosapic_lock, flags); +#endif } /* @@ -330,7 +366,7 @@ } void __init -iosapic_init (unsigned long phys_addr, unsigned int base_irq) +iosapic_init (unsigned long phys_addr, unsigned int base_irq, int pcat_compat) { struct hw_interrupt_type *irq_type; int i, irq, max_pin, vector; @@ -348,13 +384,7 @@ /* * Fetch the PCI interrupt routing table: */ -#ifdef CONFIG_ACPI_KERNEL_CONFIG acpi_cf_get_pci_vectors(&pci_irq.route, &pci_irq.num_routes); -#else - pci_irq.route = - (struct pci_vector_struct *) __va(ia64_boot_param->pci_vectors); - pci_irq.num_routes = ia64_boot_param->num_pci_vectors; -#endif } addr = ioremap(phys_addr, 0); @@ -365,7 +395,7 @@ printk("IOSAPIC: version %x.%x, address 0x%lx, IRQs 0x%02x-0x%02x\n", (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, base_irq, base_irq + max_pin); - if (base_irq == 0) + if ((base_irq == 0) && pcat_compat) /* * Map the legacy ISA devices into the IOSAPIC data. Some of these may * get reprogrammed later on with data from the ACPI Interrupt Source diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/irq.c linux/arch/ia64/kernel/irq.c --- v2.4.7/linux/arch/ia64/kernel/irq.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/irq.c Tue Jul 31 10:30:08 2001 @@ -626,6 +626,8 @@ desc->handler->end(irq); spin_unlock(&desc->lock); } + if (local_softirq_pending()) + do_softirq(); return 1; } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/irq_ia64.c linux/arch/ia64/kernel/irq_ia64.c --- v2.4.7/linux/arch/ia64/kernel/irq_ia64.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/irq_ia64.c Tue Jul 31 10:30:08 2001 @@ -72,6 +72,11 @@ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs) { unsigned long saved_tpr; +#ifdef CONFIG_SMP +# define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE) +#else +# define IS_RESCHEDULE(vec) (0) +#endif #if IRQ_DEBUG { @@ -110,24 +115,25 @@ */ saved_tpr = ia64_get_tpr(); ia64_srlz_d(); - do { - ia64_set_tpr(vector); - ia64_srlz_d(); - - do_IRQ(local_vector_to_irq(vector), regs); - - /* - * Disable interrupts and send EOI: - */ - local_irq_disable(); - ia64_set_tpr(saved_tpr); + while (vector != IA64_SPURIOUS_INT_VECTOR) { + if (!IS_RESCHEDULE(vector)) { + ia64_set_tpr(vector); + ia64_srlz_d(); + + do_IRQ(local_vector_to_irq(vector), regs); + + /* + * Disable interrupts and send EOI: + */ + local_irq_disable(); + ia64_set_tpr(saved_tpr); + } ia64_eoi(); vector = ia64_get_ivr(); - } while (vector != IA64_SPURIOUS_INT_VECTOR); + } } #ifdef CONFIG_SMP - extern void handle_IPI (int irq, void *dev_id, struct pt_regs *regs); static struct irqaction ipi_irqaction = { @@ -147,7 +153,7 @@ if (irq_to_vector(irq) == vec) { desc = irq_desc(irq); desc->status |= IRQ_PER_CPU; - desc->handler = &irq_type_ia64_sapic; + desc->handler = &irq_type_ia64_lsapic; if (action) setup_irq(irq, action); } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/irq_lsapic.c linux/arch/ia64/kernel/irq_lsapic.c --- v2.4.7/linux/arch/ia64/kernel/irq_lsapic.c Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/irq_lsapic.c Tue Jul 31 10:30:08 2001 @@ -0,0 +1,38 @@ +/* + * LSAPIC Interrupt Controller + * + * This takes care of interrupts that are generated by the CPU's + * internal Streamlined Advanced Programmable Interrupt Controller + * (LSAPIC), such as the ITC and IPI interrupts. + * + * Copyright (C) 1999 VA Linux Systems + * Copyright (C) 1999 Walt Drummond + * Copyright (C) 2000 Hewlett-Packard Co + * Copyright (C) 2000 David Mosberger-Tang + */ + +#include +#include + +static unsigned int +lsapic_noop_startup (unsigned int irq) +{ + return 0; +} + +static void +lsapic_noop (unsigned int irq) +{ + /* nuthing to do... */ +} + +struct hw_interrupt_type irq_type_ia64_lsapic = { + typename: "LSAPIC", + startup: lsapic_noop_startup, + shutdown: lsapic_noop, + enable: lsapic_noop, + disable: lsapic_noop, + ack: lsapic_noop, + end: lsapic_noop, + set_affinity: (void (*)(unsigned int, unsigned long)) lsapic_noop +}; diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/irq_sapic.c linux/arch/ia64/kernel/irq_sapic.c --- v2.4.7/linux/arch/ia64/kernel/irq_sapic.c Fri Apr 21 15:21:24 2000 +++ linux/arch/ia64/kernel/irq_sapic.c Wed Dec 31 16:00:00 1969 @@ -1,38 +0,0 @@ -/* - * SAPIC Interrupt Controller - * - * This takes care of interrupts that are generated by the CPU's - * internal Streamlined Advanced Programmable Interrupt Controller - * (SAPIC), such as the ITC and IPI interrupts. - * - * Copyright (C) 1999 VA Linux Systems - * Copyright (C) 1999 Walt Drummond - * Copyright (C) 2000 Hewlett-Packard Co - * Copyright (C) 2000 David Mosberger-Tang - */ - -#include -#include - -static unsigned int -sapic_noop_startup (unsigned int irq) -{ - return 0; -} - -static void -sapic_noop (unsigned int irq) -{ - /* nuthing to do... */ -} - -struct hw_interrupt_type irq_type_ia64_sapic = { - typename: "SAPIC", - startup: sapic_noop_startup, - shutdown: sapic_noop, - enable: sapic_noop, - disable: sapic_noop, - ack: sapic_noop, - end: sapic_noop, - set_affinity: (void (*)(unsigned int, unsigned long)) sapic_noop -}; diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/ivt.S linux/arch/ia64/kernel/ivt.S --- v2.4.7/linux/arch/ia64/kernel/ivt.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/ivt.S Tue Jul 31 10:30:08 2001 @@ -9,16 +9,14 @@ * 00/12/20 David Mosberger-Tang DTLB/ITLB handler now uses virtual PT. */ /* - * This file defines the interrupt vector table used by the CPU. + * This file defines the interruption vector table used by the CPU. * It does not include one entry per possible cause of interruption. * - * External interrupts only use 1 entry. All others are internal interrupts - * * The first 20 entries of the table contain 64 bundles each while the * remaining 48 entries contain only 16 bundles each. * * The 64 bundles are used to allow inlining the whole handler for critical - * interrupts like TLB misses. + * interruptions like TLB misses. * * For each entry, the comment is as follows: * @@ -27,7 +25,7 @@ * entry number ---------/ / / / * size of the entry -------------/ / / * vector name -------------------------------------/ / - * related interrupts (what is the real interrupt?) ----------/ + * interruptions triggering this vector ----------------------/ * * The table is 32KB in size and must be aligned on 32KB boundary. * (The CPU ignores the 15 lower bits of the address) @@ -363,7 +361,7 @@ ;; ssm psr.ic | PSR_DEFAULT_BITS ;; - srlz.i // guarantee that interrupt collection is enabled + srlz.i // guarantee that interruption collectin is on ;; (p15) ssm psr.i // restore psr.i movl r14=ia64_leave_kernel @@ -536,8 +534,7 @@ ;; 1: ld8 r18=[r17] ;; -# if defined(CONFIG_IA32_SUPPORT) && \ - (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC)) +# if defined(CONFIG_IA32_SUPPORT) && defined(CONFIG_ITANIUM_B0_SPECIFIC) /* * Erratum 85 (Access bit fault could be reported before page not present fault) * If the PTE is indicates the page is not present, then just turn this into a @@ -567,8 +564,7 @@ ;; 1: ld8 r18=[r17] ;; -# if defined(CONFIG_IA32_SUPPORT) && \ - (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_B0_SPECIFIC)) +# if defined(CONFIG_IA32_SUPPORT) && defined(CONFIG_ITANIUM_B0_SPECIFIC) /* * Erratum 85 (Access bit fault could be reported before page not present fault) * If the PTE is indicates the page is not present, then just turn this into a @@ -650,7 +646,7 @@ ssm psr.ic | PSR_DEFAULT_BITS ;; - srlz.i // guarantee that interrupt collection is enabled + srlz.i // guarantee that interruption collection is on cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0 ;; (p15) ssm psr.i // restore psr.i @@ -702,7 +698,7 @@ st8 [r16]=r18 // store new value for cr.isr (p8) br.call.sptk.many b6=b6 // ignore this return addr - br.call.sptk.many rp=ia64_trace_syscall // rp will be overwritten (ignored) + br.cond.sptk.many ia64_trace_syscall // NOT REACHED END(break_fault) @@ -724,11 +720,14 @@ tnat.nz p15,p0=in7 (p11) mov in3=-1 + tnat.nz p8,p0=r15 // demining r15 is not a must, but it is safer + (p12) mov in4=-1 (p13) mov in5=-1 ;; (p14) mov in6=-1 (p15) mov in7=-1 +(p8) mov r15=-1 br.ret.sptk.many rp END(demine_args) @@ -790,7 +789,7 @@ SAVE_MIN_WITH_COVER ssm psr.ic | PSR_DEFAULT_BITS ;; - srlz.i // guarantee that interrupt collection is enabled + srlz.i // guarantee that interruption collection is on ;; (p15) ssm psr.i // restore psr.i adds r3=8,r2 // set up second base pointer for SAVE_REST @@ -839,7 +838,7 @@ mov r14=cr.isr ssm psr.ic | PSR_DEFAULT_BITS ;; - srlz.i // guarantee that interrupt collection is enabled + srlz.i // guarantee that interruption collection is on ;; (p15) ssm psr.i adds r3=8,r2 // Base pointer for SAVE_REST @@ -890,8 +889,7 @@ ;; mov rp=r15 (p8) br.call.sptk.many b6=b6 - ;; - br.call.sptk.many rp=ia32_trace_syscall // rp will be overwritten (ignored) + br.cond.sptk.many ia32_trace_syscall non_ia32_syscall: alloc r15=ar.pfs,0,0,2,0 @@ -928,7 +926,7 @@ ssm psr.ic | PSR_DEFAULT_BITS ;; - srlz.i // guarantee that interrupt collection is enabled + srlz.i // guarantee that interruption collection is on ;; (p15) ssm psr.i // restore psr.i movl r15=ia64_leave_kernel @@ -961,7 +959,7 @@ ssm psr.ic | PSR_DEFAULT_BITS ;; - srlz.i // guarantee that interrupt collection is enabled + srlz.i // guarantee that interruption collection is on ;; (p15) ssm psr.i // restore psr.i adds r3=8,r2 // set up second base pointer @@ -1003,7 +1001,7 @@ ;; ssm psr.ic | PSR_DEFAULT_BITS ;; - srlz.i // guarantee that interrupt collection is enabled + srlz.i // guarantee that interruption collection is on ;; (p15) ssm psr.i // restore psr.i adds r3=8,r2 // set up second base pointer for SAVE_REST diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/mca.c linux/arch/ia64/kernel/mca.c --- v2.4.7/linux/arch/ia64/kernel/mca.c Thu Apr 12 12:16:35 2001 +++ linux/arch/ia64/kernel/mca.c Tue Jul 31 10:30:08 2001 @@ -27,6 +27,7 @@ #include #include +#include typedef struct ia64_fptr { diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/mca_asm.S linux/arch/ia64/kernel/mca_asm.S --- v2.4.7/linux/arch/ia64/kernel/mca_asm.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/mca_asm.S Tue Jul 31 10:30:08 2001 @@ -672,7 +672,7 @@ // mov r17=cr.lid // XXX fix me: this is wrong: hard_smp_processor_id() is a pair of lid/eid - movl r18=__cpu_physical_id + movl r18=ia64_cpu_to_sapicid ;; dep r18=0,r18,61,3 // convert to physical address ;; diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/minstate.h linux/arch/ia64/kernel/minstate.h --- v2.4.7/linux/arch/ia64/kernel/minstate.h Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/minstate.h Tue Jul 31 10:30:08 2001 @@ -235,12 +235,6 @@ stf.spill [r2]=f8,32; \ stf.spill [r3]=f9,32 -#ifdef CONFIG_ITANIUM_ASTEP_SPECIFIC -# define STOPS nop.i 0x0;; nop.i 0x0;; nop.i 0x0;; -#else -# define STOPS -#endif - -#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs,) STOPS -#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs, mov r15=r19) STOPS -#define SAVE_MIN DO_SAVE_MIN( , mov rCRIFS=r0, ) STOPS +#define SAVE_MIN_WITH_COVER DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs,) +#define SAVE_MIN_WITH_COVER_R19 DO_SAVE_MIN(cover, mov rCRIFS=cr.ifs, mov r15=r19) +#define SAVE_MIN DO_SAVE_MIN( , mov rCRIFS=r0, ) diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/pci.c linux/arch/ia64/kernel/pci.c --- v2.4.7/linux/arch/ia64/kernel/pci.c Fri Feb 9 11:29:44 2001 +++ linux/arch/ia64/kernel/pci.c Tue Jul 31 10:30:08 2001 @@ -1,6 +1,6 @@ /* * pci.c - Low-Level PCI Access in IA-64 - * + * * Derived from bios32.c of i386 tree. */ #include @@ -53,7 +53,7 @@ #define PCI_CONFIG_ADDRESS(dev, where) \ (((u64) dev->bus->number << 16) | ((u64) (dev->devfn & 0xff) << 8) | (where & 0xff)) -static int +static int pci_conf_read_config_byte(struct pci_dev *dev, int where, u8 *value) { s64 status; @@ -64,7 +64,7 @@ return status; } -static int +static int pci_conf_read_config_word(struct pci_dev *dev, int where, u16 *value) { s64 status; @@ -75,7 +75,7 @@ return status; } -static int +static int pci_conf_read_config_dword(struct pci_dev *dev, int where, u32 *value) { s64 status; @@ -86,19 +86,19 @@ return status; } -static int +static int pci_conf_write_config_byte (struct pci_dev *dev, int where, u8 value) { return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 1, value); } -static int +static int pci_conf_write_config_word (struct pci_dev *dev, int where, u16 value) { return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 2, value); } -static int +static int pci_conf_write_config_dword (struct pci_dev *dev, int where, u32 value) { return ia64_sal_pci_config_write(PCI_CONFIG_ADDRESS(dev, where), 4, value); @@ -116,7 +116,7 @@ /* * Initialization. Uses the SAL interface */ -void __init +void __init pcibios_init (void) { # define PCI_BUSES_TO_SCAN 255 @@ -125,7 +125,7 @@ platform_pci_fixup(0); /* phase 0 initialization (before PCI bus has been scanned) */ printk("PCI: Probing PCI hardware\n"); - for (i = 0; i < PCI_BUSES_TO_SCAN; i++) + for (i = 0; i < PCI_BUSES_TO_SCAN; i++) pci_scan_bus(i, &pci_conf, NULL); platform_pci_fixup(1); /* phase 1 initialization (after PCI bus has been scanned) */ @@ -146,14 +146,14 @@ pcibios_update_resource (struct pci_dev *dev, struct resource *root, struct resource *res, int resource) { - unsigned long where, size; - u32 reg; + unsigned long where, size; + u32 reg; - where = PCI_BASE_ADDRESS_0 + (resource * 4); - size = res->end - res->start; - pci_read_config_dword(dev, where, ®); - reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); - pci_write_config_dword(dev, where, reg); + where = PCI_BASE_ADDRESS_0 + (resource * 4); + size = res->end - res->start; + pci_read_config_dword(dev, where, ®); + reg = (reg & size) | (((u32)(res->start - root->start)) & ~size); + pci_write_config_dword(dev, where, reg); /* ??? FIXME -- record old value for shutdown. */ } @@ -190,7 +190,7 @@ /* * PCI BIOS setup, always defaults to SAL interface */ -char * __init +char * __init pcibios_setup (char *str) { return NULL; diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/perfmon.c linux/arch/ia64/kernel/perfmon.c --- v2.4.7/linux/arch/ia64/kernel/perfmon.c Fri Apr 13 15:29:37 2001 +++ linux/arch/ia64/kernel/perfmon.c Tue Jul 31 10:30:08 2001 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include /* for ia64_get_itc() */ @@ -467,7 +468,7 @@ if (size > current->rlim[RLIMIT_MEMLOCK].rlim_cur) return -EAGAIN; /* find some free area in address space */ - addr = get_unmapped_area(NULL, 0, size, 0, 0); + addr = get_unmapped_area(NULL, 0, size, 0, MAP_PRIVATE); if (!addr) goto no_addr; DBprintk((" entries=%ld aligned size=%ld, unmapped @0x%lx\n", entries, size, addr)); @@ -573,12 +574,8 @@ /* cannot send to process 1, 0 means do not notify */ if (pfx->notify_pid < 0 || pfx->notify_pid == 1) return 0; - /* asked for sampling, but nothing to record ! */ - if (pfx->smpl_entries > 0 && pfm_smpl_entry_size(&pfx->smpl_regs, 1) == 0) return 0; - /* probably more to add here */ - return 1; } @@ -786,26 +783,22 @@ /* XXX: ctx locking may be required here */ for (i = 0; i < count; i++, req++) { - int k; - if (copy_from_user(&tmp, req, sizeof(tmp))) return -EFAULT; if (!PMD_IS_IMPL(tmp.pfr_reg.reg_num)) return -EINVAL; - k = tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER; - if (PMD_IS_COUNTER(tmp.pfr_reg.reg_num)) { if (ta == current){ val = ia64_get_pmd(tmp.pfr_reg.reg_num); } else { - val = th->pmd[k]; + val = th->pmd[tmp.pfr_reg.reg_num]; } val &= pmu_conf.perf_ovfl_val; /* * lower part of .val may not be zero, so we must be an addition because of * residual count (see update_counters). */ - val += ctx->ctx_pmds[k].val; + val += ctx->ctx_pmds[tmp.pfr_reg.reg_num - PMU_FIRST_COUNTER].val; } else { /* for now */ if (ta != current) return -EINVAL; @@ -1646,7 +1639,7 @@ pmu_conf.pfm_is_disabled = 1; - printk("perfmon: version %s\n", PFM_VERSION); + printk("perfmon: version %s (sampling format v%d)\n", PFM_VERSION, PFM_SMPL_HDR_VERSION); printk("perfmon: Interrupt vectored to %u\n", IA64_PERFMON_VECTOR); if ((status=ia64_pal_perf_mon_info(pmu_conf.impl_regs, &pm_info)) != 0) { @@ -1658,11 +1651,8 @@ pmu_conf.num_pmds = find_num_pm_regs(pmu_conf.impl_regs); pmu_conf.num_pmcs = find_num_pm_regs(&pmu_conf.impl_regs[4]); - printk("perfmon: Counters are %d bits\n", pm_info.pal_perf_mon_info_s.width); - printk("perfmon: Maximum counter value 0x%lx\n", pmu_conf.perf_ovfl_val); - printk("perfmon: %ld PMC/PMD pairs\n", pmu_conf.max_counters); - printk("perfmon: %ld PMCs, %ld PMDs\n", pmu_conf.num_pmcs, pmu_conf.num_pmds); - printk("perfmon: Sampling format v%d\n", PFM_SMPL_HDR_VERSION); + printk("perfmon: %d bits counters (max value 0x%lx)\n", pm_info.pal_perf_mon_info_s.width, pmu_conf.perf_ovfl_val); + printk("perfmon: %ld PMC/PMD pairs, %ld PMCs, %ld PMDs\n", pmu_conf.max_counters, pmu_conf.num_pmcs, pmu_conf.num_pmds); /* sanity check */ if (pmu_conf.num_pmds >= IA64_NUM_PMD_REGS || pmu_conf.num_pmcs >= IA64_NUM_PMC_REGS) { diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/process.c linux/arch/ia64/kernel/process.c --- v2.4.7/linux/arch/ia64/kernel/process.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/process.c Tue Jul 31 10:30:08 2001 @@ -143,7 +143,7 @@ pfm_save_regs(task); #endif if (IS_IA32_PROCESS(ia64_task_regs(task))) - ia32_save_state(&task->thread); + ia32_save_state(task); } void @@ -156,7 +156,7 @@ pfm_load_regs(task); #endif if (IS_IA32_PROCESS(ia64_task_regs(task))) - ia32_load_state(&task->thread); + ia32_load_state(task); } /* @@ -282,10 +282,11 @@ * state from the current task to the new task */ if (IS_IA32_PROCESS(ia64_task_regs(current))) - ia32_save_state(&p->thread); + ia32_save_state(p); #endif #ifdef CONFIG_PERFMON - if (current->thread.pfm_context) + p->thread.pfm_pend_notify = 0; + if (p->thread.pfm_context) retval = pfm_inherit(p); #endif return retval; @@ -294,11 +295,10 @@ void do_copy_regs (struct unw_frame_info *info, void *arg) { - unsigned long ar_bsp, addr, mask, sp, nat_bits = 0, ip, ar_rnat; + unsigned long mask, sp, nat_bits = 0, ip, ar_rnat, urbs_end, cfm; elf_greg_t *dst = arg; struct pt_regs *pt; char nat; - long val; int i; memset(dst, 0, sizeof(elf_gregset_t)); /* don't leak any kernel bits to user-level */ @@ -309,17 +309,13 @@ unw_get_sp(info, &sp); pt = (struct pt_regs *) (sp + 16); - ar_bsp = ia64_get_user_bsp(current, pt); + urbs_end = ia64_get_user_rbs_end(current, pt, &cfm); - /* - * Write portion of RSE backing store living on the kernel stack to the VM of the - * process. - */ - for (addr = pt->ar_bspstore; addr < ar_bsp; addr += 8) - if (ia64_peek(current, ar_bsp, addr, &val) == 0) - access_process_vm(current, addr, &val, sizeof(val), 1); + if (ia64_sync_user_rbs(current, info->sw, pt->ar_bspstore, urbs_end) < 0) + return; - ia64_peek(current, ar_bsp, (long) ia64_rse_rnat_addr((long *) addr - 1), &ar_rnat); + ia64_peek(current, info->sw, urbs_end, (long) ia64_rse_rnat_addr((long *) urbs_end), + &ar_rnat); /* * coredump format: @@ -347,7 +343,7 @@ unw_get_rp(info, &ip); dst[42] = ip + ia64_psr(pt)->ri; - dst[43] = pt->cr_ifs & 0x3fffffffff; + dst[43] = cfm; dst[44] = pt->cr_ipsr & IA64_PSR_UM; unw_get_ar(info, UNW_AR_RSC, &dst[45]); @@ -355,7 +351,7 @@ * For bsp and bspstore, unw_get_ar() would return the kernel * addresses, but we need the user-level addresses instead: */ - dst[46] = ar_bsp; + dst[46] = urbs_end; /* note: by convention PT_AR_BSP points to the end of the urbs! */ dst[47] = pt->ar_bspstore; dst[48] = ar_rnat; unw_get_ar(info, UNW_AR_CCV, &dst[49]); @@ -528,13 +524,11 @@ void machine_halt (void) { - printk("machine_halt: need PAL or ACPI version here!!\n"); - machine_restart(0); } void machine_power_off (void) { - printk("machine_power_off: unimplemented (need ACPI version here)\n"); - machine_halt (); + if (pm_power_off) + pm_power_off(); } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/ptrace.c linux/arch/ia64/kernel/ptrace.c --- v2.4.7/linux/arch/ia64/kernel/ptrace.c Wed Jul 25 17:10:17 2001 +++ linux/arch/ia64/kernel/ptrace.c Tue Jul 31 10:30:08 2001 @@ -144,12 +144,10 @@ } /* - * This routine is used to read an rnat bits that are stored on the - * kernel backing store. Since, in general, the alignment of the user - * and kernel are different, this is not completely trivial. In - * essence, we need to construct the user RNAT based on up to two - * kernel RNAT values and/or the RNAT value saved in the child's - * pt_regs. + * This routine is used to read an rnat bits that are stored on the kernel backing store. + * Since, in general, the alignment of the user and kernel are different, this is not + * completely trivial. In essence, we need to construct the user RNAT based on up to two + * kernel RNAT values and/or the RNAT value saved in the child's pt_regs. * * user rbs * @@ -182,20 +180,18 @@ * +--------+ * <--- child_stack->ar_bspstore * - * The way to think of this code is as follows: bit 0 in the user rnat - * corresponds to some bit N (0 <= N <= 62) in one of the kernel rnat - * value. The kernel rnat value holding this bit is stored in - * variable rnat0. rnat1 is loaded with the kernel rnat value that + * The way to think of this code is as follows: bit 0 in the user rnat corresponds to some + * bit N (0 <= N <= 62) in one of the kernel rnat value. The kernel rnat value holding + * this bit is stored in variable rnat0. rnat1 is loaded with the kernel rnat value that * form the upper bits of the user rnat value. * * Boundary cases: * - * o when reading the rnat "below" the first rnat slot on the kernel - * backing store, rnat0/rnat1 are set to 0 and the low order bits - * are merged in from pt->ar_rnat. + * o when reading the rnat "below" the first rnat slot on the kernel backing store, + * rnat0/rnat1 are set to 0 and the low order bits are merged in from pt->ar_rnat. * - * o when reading the rnat "above" the last rnat slot on the kernel - * backing store, rnat0/rnat1 gets its value from sw->ar_rnat. + * o when reading the rnat "above" the last rnat slot on the kernel backing store, + * rnat0/rnat1 gets its value from sw->ar_rnat. */ static unsigned long get_rnat (struct pt_regs *pt, struct switch_stack *sw, @@ -289,57 +285,82 @@ } } +/* + * Read a word from the user-level backing store of task CHILD. ADDR is the user-level + * address to read the word from, VAL a pointer to the return value, and USER_BSP gives + * the end of the user-level backing store (i.e., it's the address that would be in ar.bsp + * after the user executed a "cover" instruction). + * + * This routine takes care of accessing the kernel register backing store for those + * registers that got spilled there. It also takes care of calculating the appropriate + * RNaT collection words. + */ long -ia64_peek (struct task_struct *child, unsigned long user_bsp, unsigned long addr, long *val) +ia64_peek (struct task_struct *child, struct switch_stack *child_stack, unsigned long user_rbs_end, + unsigned long addr, long *val) { - unsigned long *bspstore, *krbs, regnum, *laddr, *ubsp = (long *) user_bsp; - struct switch_stack *child_stack; + unsigned long *bspstore, *krbs, regnum, *laddr, *urbs_end, *rnat_addr; struct pt_regs *child_regs; size_t copied; long ret; + urbs_end = (long *) user_rbs_end; laddr = (unsigned long *) addr; child_regs = ia64_task_regs(child); - child_stack = (struct switch_stack *) (child->thread.ksp + 16); bspstore = (unsigned long *) child_regs->ar_bspstore; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(ubsp)) { + if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(urbs_end)) { /* * Attempt to read the RBS in an area that's actually on the kernel RBS => * read the corresponding bits in the kernel RBS. */ - if (ia64_rse_is_rnat_slot(laddr)) - ret = get_rnat(child_regs, child_stack, krbs, laddr); - else { - if (laddr >= ubsp) - ret = 0; - else { - regnum = ia64_rse_num_regs(bspstore, laddr); - ret = *ia64_rse_skip_regs(krbs, regnum); - } + rnat_addr = ia64_rse_rnat_addr(laddr); + ret = get_rnat(child_regs, child_stack, krbs, rnat_addr); + + if (laddr == rnat_addr) { + /* return NaT collection word itself */ + *val = ret; + return 0; + } + + if (((1UL << ia64_rse_slot_num(laddr)) & ret) != 0) { + /* + * It is implementation dependent whether the data portion of a + * NaT value gets saved on a st8.spill or RSE spill (e.g., see + * EAS 2.6, 4.4.4.6 Register Spill and Fill). To get consistent + * behavior across all possible IA-64 implementations, we return + * zero in this case. + */ + *val = 0; + return 0; + } + + if (laddr < urbs_end) { + /* the desired word is on the kernel RBS and is not a NaT */ + regnum = ia64_rse_num_regs(bspstore, laddr); + *val = *ia64_rse_skip_regs(krbs, regnum); + return 0; } - } else { - copied = access_process_vm(child, addr, &ret, sizeof(ret), 0); - if (copied != sizeof(ret)) - return -EIO; } + copied = access_process_vm(child, addr, &ret, sizeof(ret), 0); + if (copied != sizeof(ret)) + return -EIO; *val = ret; return 0; } long -ia64_poke (struct task_struct *child, unsigned long user_bsp, unsigned long addr, long val) +ia64_poke (struct task_struct *child, struct switch_stack *child_stack, unsigned long user_rbs_end, + unsigned long addr, long val) { - unsigned long *bspstore, *krbs, regnum, *laddr, *ubsp = (long *) user_bsp; - struct switch_stack *child_stack; + unsigned long *bspstore, *krbs, regnum, *laddr, *urbs_end = (long *) user_rbs_end; struct pt_regs *child_regs; laddr = (unsigned long *) addr; child_regs = ia64_task_regs(child); - child_stack = (struct switch_stack *) (child->thread.ksp + 16); bspstore = (unsigned long *) child_regs->ar_bspstore; krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; - if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(ubsp)) { + if (laddr >= bspstore && laddr <= ia64_rse_rnat_addr(urbs_end)) { /* * Attempt to write the RBS in an area that's actually on the kernel RBS * => write the corresponding bits in the kernel RBS. @@ -347,7 +368,7 @@ if (ia64_rse_is_rnat_slot(laddr)) put_rnat(child_regs, child_stack, krbs, laddr, val); else { - if (laddr < ubsp) { + if (laddr < urbs_end) { regnum = ia64_rse_num_regs(bspstore, laddr); *ia64_rse_skip_regs(krbs, regnum) = val; } @@ -359,11 +380,13 @@ } /* - * Calculate the user-level address that would have been in ar.bsp had the user executed a - * "cover" instruction right before entering the kernel. + * Calculate the address of the end of the user-level register backing store. This is the + * address that would have been stored in ar.bsp if the user had executed a "cover" + * instruction right before entering the kernel. If CFMP is not NULL, it is used to + * return the "current frame mask" that was active at the time the kernel was entered. */ unsigned long -ia64_get_user_bsp (struct task_struct *child, struct pt_regs *pt) +ia64_get_user_rbs_end (struct task_struct *child, struct pt_regs *pt, unsigned long *cfmp) { unsigned long *krbs, *bspstore, cfm; struct unw_frame_info info; @@ -372,6 +395,7 @@ krbs = (unsigned long *) child + IA64_RBS_OFFSET/8; bspstore = (unsigned long *) pt->ar_bspstore; ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); + cfm = pt->cr_ifs & ~(1UL << 63); if ((long) pt->cr_ifs >= 0) { /* @@ -385,81 +409,102 @@ ndirty += (cfm & 0x7f); } } + if (cfmp) + *cfmp = cfm; return (unsigned long) ia64_rse_skip_regs(bspstore, ndirty); } /* * Synchronize (i.e, write) the RSE backing store living in kernel space to the VM of the - * indicated child process. - * - * If new_bsp is non-zero, the bsp will (effectively) be updated to the new value upon - * resumption of the child process. This is accomplished by setting the loadrs value to - * zero and the bspstore value to the new bsp value. - * - * When new_bsp and flush_user_rbs are both 0, the register backing store in kernel space - * is written to user space and the loadrs and bspstore values are left alone. - * - * When new_bsp is zero and flush_user_rbs is 1 (non-zero), loadrs is set to 0, and the - * bspstore value is set to the old bsp value. This will cause the stacked registers (r32 - * and up) to be obtained entirely from the child's memory space rather than from the - * kernel. (This makes it easier to write code for modifying the stacked registers in - * multi-threaded programs.) - * - * Note: I had originally written this function without the flush_user_rbs parameter; it - * was written so that loadrs would always be set to zero. But I had problems with - * certain system calls apparently causing a portion of the RBS to be zeroed. (I still - * don't understand why this was happening.) Anyway, it'd definitely less intrusive to - * leave loadrs and bspstore alone if possible. + * CHILD task. SW and PT are the pointers to the switch_stack and pt_regs structures, + * respectively. USER_RBS_END is the user-level address at which the backing store ends. */ -static long -sync_kernel_register_backing_store (struct task_struct *child, long user_bsp, long new_bsp, - int flush_user_rbs) +long +ia64_sync_user_rbs (struct task_struct *child, struct switch_stack *sw, + unsigned long user_rbs_start, unsigned long user_rbs_end) { - struct pt_regs *child_regs = ia64_task_regs(child); unsigned long addr, val; long ret; - /* - * Return early if nothing to do. Note that new_bsp will be zero if the caller - * wants to force synchronization without changing bsp. - */ - if (user_bsp == new_bsp) - return 0; - - /* Write portion of backing store living on kernel stack to the child's VM. */ - for (addr = child_regs->ar_bspstore; addr < user_bsp; addr += 8) { - ret = ia64_peek(child, user_bsp, addr, &val); - if (ret != 0) + /* now copy word for word from kernel rbs to user rbs: */ + for (addr = user_rbs_start; addr < user_rbs_end; addr += 8) { + ret = ia64_peek(child, sw, user_rbs_end, addr, &val); + if (ret < 0) return ret; if (access_process_vm(child, addr, &val, sizeof(val), 1) != sizeof(val)) return -EIO; } + return 0; +} - if (new_bsp != 0) { - flush_user_rbs = 1; - user_bsp = new_bsp; - } +/* + * Simulate user-level "flushrs". Note: we can't just add pt->loadrs>>16 to + * pt->ar_bspstore because the kernel backing store and the user-level backing store may + * have different alignments (and therefore a different number of intervening rnat slots). + */ +static void +user_flushrs (struct task_struct *task, struct pt_regs *pt) +{ + unsigned long *krbs; + long ndirty; - if (flush_user_rbs) { - child_regs->loadrs = 0; - child_regs->ar_bspstore = user_bsp; - } - return 0; + krbs = (unsigned long *) task + IA64_RBS_OFFSET/8; + ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19)); + + pt->ar_bspstore = (unsigned long) ia64_rse_skip_regs((unsigned long *) pt->ar_bspstore, + ndirty); + pt->loadrs = 0; } +/* + * Synchronize the RSE backing store of CHILD and all tasks that share the address space + * with it. CHILD_URBS_END is the address of the end of the register backing store of + * CHILD. If MAKE_WRITABLE is set, a user-level "flushrs" is simulated such that the VM + * can be written via ptrace() and the tasks will pick up the newly written values. It + * would be OK to unconditionally simulate a "flushrs", but this would be more intrusive + * than strictly necessary (e.g., it would make it impossible to obtain the original value + * of ar.bspstore). + */ static void -sync_thread_rbs (struct task_struct *child, long bsp, struct mm_struct *mm, int make_writable) +threads_sync_user_rbs (struct task_struct *child, unsigned long child_urbs_end, int make_writable) { + struct switch_stack *sw; + unsigned long urbs_end; struct task_struct *p; - read_lock(&tasklist_lock); + struct mm_struct *mm; + struct pt_regs *pt; + long multi_threaded; + + task_lock(child); { - for_each_task(p) { - if (p->mm == mm && p->state != TASK_RUNNING) - sync_kernel_register_backing_store(p, bsp, 0, make_writable); + mm = child->mm; + multi_threaded = mm && (atomic_read(&mm->mm_users) > 1); + } + task_unlock(child); + + if (!multi_threaded) { + sw = (struct switch_stack *) (child->thread.ksp + 16); + pt = ia64_task_regs(child); + ia64_sync_user_rbs(child, sw, pt->ar_bspstore, child_urbs_end); + if (make_writable) + user_flushrs(child, pt); + } else { + read_lock(&tasklist_lock); + { + for_each_task(p) { + if (p->mm == mm && p->state != TASK_RUNNING) { + sw = (struct switch_stack *) (p->thread.ksp + 16); + pt = ia64_task_regs(p); + urbs_end = ia64_get_user_rbs_end(p, pt, NULL); + ia64_sync_user_rbs(p, sw, pt->ar_bspstore, urbs_end); + if (make_writable) + user_flushrs(p, pt); + } + } } + read_unlock(&tasklist_lock); } - read_unlock(&tasklist_lock); - child->thread.flags |= IA64_THREAD_KRBS_SYNCED; + child->thread.flags |= IA64_THREAD_KRBS_SYNCED; /* set the flag in the child thread only */ } /* @@ -528,7 +573,7 @@ static int access_uarea (struct task_struct *child, unsigned long addr, unsigned long *data, int write_access) { - unsigned long *ptr, regnum, bsp, rnat_addr; + unsigned long *ptr, regnum, urbs_end, rnat_addr; struct switch_stack *sw; struct unw_frame_info info; struct pt_regs *pt; @@ -625,13 +670,24 @@ /* scratch state */ switch (addr) { case PT_AR_BSP: - bsp = ia64_get_user_bsp(child, pt); - if (write_access) - return sync_kernel_register_backing_store(child, bsp, *data, 1); - else { - *data = bsp; - return 0; - } + /* + * By convention, we use PT_AR_BSP to refer to the end of the user-level + * backing store. Use ia64_rse_skip_regs(PT_AR_BSP, -CFM.sof) to get + * the real value of ar.bsp at the time the kernel was entered. + */ + urbs_end = ia64_get_user_rbs_end(child, pt, NULL); + if (write_access) { + if (*data != urbs_end) { + if (ia64_sync_user_rbs(child, sw, + pt->ar_bspstore, urbs_end) < 0) + return -1; + /* simulate user-level write of ar.bsp: */ + pt->loadrs = 0; + pt->ar_bspstore = *data; + } + } else + *data = urbs_end; + return 0; case PT_CFM: if ((long) pt->cr_ifs < 0) { @@ -666,12 +722,12 @@ return 0; case PT_AR_RNAT: - bsp = ia64_get_user_bsp(child, pt); - rnat_addr = (long) ia64_rse_rnat_addr((long *) bsp - 1); + urbs_end = ia64_get_user_rbs_end(child, pt, NULL); + rnat_addr = (long) ia64_rse_rnat_addr((long *) urbs_end); if (write_access) - return ia64_poke(child, bsp, rnat_addr, *data); + return ia64_poke(child, sw, urbs_end, rnat_addr, *data); else - return ia64_peek(child, bsp, rnat_addr, data); + return ia64_peek(child, sw, urbs_end, rnat_addr, data); case PT_R1: case PT_R2: case PT_R3: case PT_R8: case PT_R9: case PT_R10: case PT_R11: @@ -738,8 +794,9 @@ long arg4, long arg5, long arg6, long arg7, long stack) { struct pt_regs *pt, *regs = (struct pt_regs *) &stack; + unsigned long flags, urbs_end; struct task_struct *child; - unsigned long flags, bsp; + struct switch_stack *sw; long ret; lock_kernel(); @@ -784,25 +841,17 @@ goto out_tsk; pt = ia64_task_regs(child); + sw = (struct switch_stack *) (child->thread.ksp + 16); switch (request) { case PTRACE_PEEKTEXT: case PTRACE_PEEKDATA: /* read word at location addr */ - bsp = ia64_get_user_bsp(child, pt); - if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) { - struct mm_struct *mm; - long do_sync; - - task_lock(child); - { - mm = child->mm; - do_sync = mm && (atomic_read(&mm->mm_users) > 1); - } - task_unlock(child); - if (do_sync) - sync_thread_rbs(child, bsp, mm, 0); - } - ret = ia64_peek(child, bsp, addr, &data); + urbs_end = ia64_get_user_rbs_end(child, pt, NULL); + + if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) + threads_sync_user_rbs(child, urbs_end, 0); + + ret = ia64_peek(child, sw, urbs_end, addr, &data); if (ret == 0) { ret = data; regs->r8 = 0; /* ensure "ret" is not mistaken as an error code */ @@ -811,21 +860,11 @@ case PTRACE_POKETEXT: case PTRACE_POKEDATA: /* write the word at location addr */ - bsp = ia64_get_user_bsp(child, pt); - if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) { - struct mm_struct *mm; - long do_sync; - - task_lock(child); - { - mm = child->mm; - do_sync = mm && (atomic_read(&child->mm->mm_users) > 1); - } - task_unlock(child); - if (do_sync) - sync_thread_rbs(child, bsp, mm, 1); - } - ret = ia64_poke(child, bsp, addr, data); + urbs_end = ia64_get_user_rbs_end(child, pt, NULL); + if (!(child->thread.flags & IA64_THREAD_KRBS_SYNCED)) + threads_sync_user_rbs(child, urbs_end, 1); + + ret = ia64_poke(child, sw, urbs_end, addr, data); goto out_tsk; case PTRACE_PEEKUSR: /* read the word at addr in the USER area */ diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/setup.c linux/arch/ia64/kernel/setup.c --- v2.4.7/linux/arch/ia64/kernel/setup.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/setup.c Tue Jul 31 10:30:08 2001 @@ -3,7 +3,7 @@ * * Copyright (C) 1998-2001 Hewlett-Packard Co * Copyright (C) 1998-2001 David Mosberger-Tang - * Copyright (C) 1998, 1999 Stephane Eranian + * Copyright (C) 1998, 1999, 2001 Stephane Eranian * Copyright (C) 2000, Rohit Seth * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999 Walt Drummond @@ -46,20 +46,20 @@ # error "struct cpuinfo_ia64 too big!" #endif +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + extern char _end; -/* cpu_data[0] is data for the bootstrap processor: */ -struct cpuinfo_ia64 cpu_data[NR_CPUS] __attribute__ ((section ("__special_page_section"))); +#ifdef CONFIG_NUMA + struct cpuinfo_ia64 *boot_cpu_data; +#else + struct cpuinfo_ia64 _cpu_data[NR_CPUS] __attribute__ ((section ("__special_page_section"))); +#endif unsigned long ia64_cycles_per_usec; struct ia64_boot_param *ia64_boot_param; struct screen_info screen_info; -/* This tells _start which CPU is booting. */ -int cpu_now_booting; - -#ifdef CONFIG_SMP -volatile unsigned long cpu_online_map; -#endif unsigned long ia64_iobase; /* virtual address for I/O accesses */ @@ -67,6 +67,31 @@ char saved_command_line[COMMAND_LINE_SIZE]; /* used in proc filesystem */ +/* + * Entries defined so far: + * - boot param structure itself + * - memory map + * - initrd (optional) + * - command line string + * - kernel code & data + * + * More could be added if necessary + */ +#define IA64_MAX_RSVD_REGIONS 5 + +struct rsvd_region { + unsigned long start; /* virtual address of beginning of element */ + unsigned long end; /* virtual address of end of element + 1 */ +}; + +/* + * We use a special marker for the end of memory and it uses the extra (+1) slot + */ +static struct rsvd_region rsvd_region[IA64_MAX_RSVD_REGIONS + 1]; +static int num_rsvd_regions; + +static unsigned long bootmap_start; /* physical address where the bootmem map is located */ + static int find_max_pfn (unsigned long start, unsigned long end, void *arg) { @@ -78,126 +103,191 @@ return 0; } +#define IGNORE_PFN0 1 /* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */ + +/* + * Free available memory based on the primitive map created from + * the boot parameters. This routine does not assume the incoming + * segments are sorted. + */ static int free_available_memory (unsigned long start, unsigned long end, void *arg) { -# define KERNEL_END ((unsigned long) &_end) -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -# define MAX(a,b) ((a) > (b) ? (a) : (b)) - unsigned long range_start, range_end; - - range_start = MIN(start, KERNEL_START); - range_end = MIN(end, KERNEL_START); + unsigned long range_start, range_end, prev_start; + int i; +#if IGNORE_PFN0 + if (start == PAGE_OFFSET) { + printk("warning: skipping physical page 0\n"); + start += PAGE_SIZE; + if (start >= end) return 0; + } +#endif /* - * XXX This should not be necessary, but the bootmem allocator - * is broken and fails to work correctly when the starting - * address is not properly aligned. + * lowest possible address(walker uses virtual) */ - range_start = PAGE_ALIGN(range_start); + prev_start = PAGE_OFFSET; - if (range_start < range_end) - free_bootmem(__pa(range_start), range_end - range_start); + for (i = 0; i < num_rsvd_regions; ++i) { + range_start = MAX(start, prev_start); + range_end = MIN(end, rsvd_region[i].start); - range_start = MAX(start, KERNEL_END); - range_end = MAX(end, KERNEL_END); + if (range_start < range_end) + free_bootmem(__pa(range_start), range_end - range_start); - /* - * XXX This should not be necessary, but the bootmem allocator - * is broken and fails to work correctly when the starting - * address is not properly aligned. - */ - range_start = PAGE_ALIGN(range_start); + /* nothing more available in this segment */ + if (range_end == end) return 0; + + prev_start = rsvd_region[i].end; + } + /* end of memory marker allows full processing inside loop body */ + return 0; +} + + +static int +find_bootmap_location (unsigned long start, unsigned long end, void *arg) +{ + unsigned long needed = *(unsigned long *)arg; + unsigned long range_start, range_end, free_start; + int i; + +#if IGNORE_PFN0 + if (start == PAGE_OFFSET) { + start += PAGE_SIZE; + if (start >= end) return 0; + } +#endif + + free_start = PAGE_OFFSET; + + for (i = 0; i < num_rsvd_regions; i++) { + range_start = MAX(start, free_start); + range_end = MIN(end, rsvd_region[i].start); - if (range_start < range_end) - free_bootmem(__pa(range_start), range_end - range_start); + if (range_end <= range_start) continue; /* skip over empty range */ + if (range_end - range_start >= needed) { + bootmap_start = __pa(range_start); + return 1; /* done */ + } + + /* nothing more available in this segment */ + if (range_end == end) return 0; + + free_start = rsvd_region[i].end; + } return 0; } -void __init -setup_arch (char **cmdline_p) +static void +sort_regions (struct rsvd_region *rsvd_region, int max) { - extern unsigned long ia64_iobase; - unsigned long max_pfn, bootmap_start, bootmap_size; + int j; - unw_init(); + /* simple bubble sorting */ + while (max--) { + for (j = 0; j < max; ++j) { + if (rsvd_region[j].start > rsvd_region[j+1].start) { + struct rsvd_region tmp; + tmp = rsvd_region[j]; + rsvd_region[j] = rsvd_region[j + 1]; + rsvd_region[j + 1] = tmp; + } + } + } +} - *cmdline_p = __va(ia64_boot_param->command_line); - strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; /* for safety */ +static void +find_memory (void) +{ +# define KERNEL_END ((unsigned long) &_end) + unsigned long bootmap_size; + unsigned long max_pfn; + int n = 0; - efi_init(); + /* + * none of the entries in this table overlap + */ + rsvd_region[n].start = (unsigned long) ia64_boot_param; + rsvd_region[n].end = rsvd_region[n].start + sizeof(*ia64_boot_param); + n++; + + rsvd_region[n].start = (unsigned long) __va(ia64_boot_param->efi_memmap); + rsvd_region[n].end = rsvd_region[n].start + ia64_boot_param->efi_memmap_size; + n++; + + rsvd_region[n].start = (unsigned long) __va(ia64_boot_param->command_line); + rsvd_region[n].end = (rsvd_region[n].start + + strlen(__va(ia64_boot_param->command_line)) + 1); + n++; + + rsvd_region[n].start = KERNEL_START; + rsvd_region[n].end = KERNEL_END; + n++; + +#ifdef CONFIG_BLK_DEV_INITRD + if (ia64_boot_param->initrd_start) { + rsvd_region[n].start = (unsigned long)__va(ia64_boot_param->initrd_start); + rsvd_region[n].end = rsvd_region[n].start + ia64_boot_param->initrd_size; + n++; + } +#endif + + /* end of memory marker */ + rsvd_region[n].start = ~0UL; + rsvd_region[n].end = ~0UL; + n++; + + num_rsvd_regions = n; + + sort_regions(rsvd_region, num_rsvd_regions); + /* first find highest page frame number */ max_pfn = 0; efi_memmap_walk(find_max_pfn, &max_pfn); - /* - * This is wrong, wrong, wrong. Darn it, you'd think if they - * change APIs, they'd do things for the better. Grumble... - */ - bootmap_start = PAGE_ALIGN(__pa(&_end)); - if (ia64_boot_param->initrd_size) - bootmap_start = PAGE_ALIGN(bootmap_start + ia64_boot_param->initrd_size); + /* how many bytes to cover all the pages */ + bootmap_size = bootmem_bootmap_pages(max_pfn) << PAGE_SHIFT; + + /* look for a location to hold the bootmap */ + bootmap_start = ~0UL; + efi_memmap_walk(find_bootmap_location, &bootmap_size); + if (bootmap_start == ~0UL) + panic("Cannot find %ld bytes for bootmap\n", bootmap_size); + bootmap_size = init_bootmem(bootmap_start >> PAGE_SHIFT, max_pfn); + /* Free all available memory, then mark bootmem-map as being in use. */ efi_memmap_walk(free_available_memory, 0); - reserve_bootmem(bootmap_start, bootmap_size); #ifdef CONFIG_BLK_DEV_INITRD - initrd_start = ia64_boot_param->initrd_start; + if (ia64_boot_param->initrd_start) { + initrd_start = (unsigned long)__va(ia64_boot_param->initrd_start); + initrd_end = initrd_start+ia64_boot_param->initrd_size; - if (initrd_start) { - u64 start, size; -# define is_same_page(a,b) (((a)&PAGE_MASK) == ((b)&PAGE_MASK)) - -#if 1 - /* XXX for now some backwards compatibility... */ - if (initrd_start >= PAGE_OFFSET) - printk("Warning: boot loader passed virtual address " - "for initrd, please upgrade the loader\n"); - else -#endif - /* - * The loader ONLY passes physical addresses - */ - initrd_start = (unsigned long)__va(initrd_start); - initrd_end = initrd_start+ia64_boot_param->initrd_size; - start = initrd_start; - size = ia64_boot_param->initrd_size; - - printk("Initial ramdisk at: 0x%p (%lu bytes)\n", - (void *) initrd_start, ia64_boot_param->initrd_size); - - /* - * The kernel end and the beginning of initrd can be - * on the same page. This would cause the page to be - * reserved twice. While not harmful, it does lead to - * a warning message which can cause confusion. Thus, - * we make sure that in this case we only reserve new - * pages, i.e., initrd only pages. We need to: - * - * - align up start - * - adjust size of reserved section accordingly - * - * It should be noted that this operation is only - * valid for the reserve_bootmem() call and does not - * affect the integrety of the initrd itself. - * - * reserve_bootmem() considers partial pages as reserved. - */ - if (is_same_page(initrd_start, (unsigned long)&_end)) { - start = PAGE_ALIGN(start); - size -= start-initrd_start; - - printk("Initial ramdisk & kernel on the same page: " - "reserving start=%lx size=%ld bytes\n", - start, size); - } - reserve_bootmem(__pa(start), size); + printk("Initial ramdisk at: 0x%lx (%lu bytes)\n", + initrd_start, ia64_boot_param->initrd_size); } #endif +} + +void __init +setup_arch (char **cmdline_p) +{ + extern unsigned long ia64_iobase; + + unw_init(); + + *cmdline_p = __va(ia64_boot_param->command_line); + strncpy(saved_command_line, *cmdline_p, sizeof(saved_command_line)); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; /* for safety */ + + efi_init(); + + find_memory(); + #if 0 /* XXX fix me */ init_mm.start_code = (unsigned long) &_stext; @@ -217,27 +307,37 @@ /* * Set `iobase' to the appropriate address in region 6 * (uncached access range) + * + * The EFI memory map is the "prefered" location to get the I/O port + * space base, rather the relying on AR.KR0. This should become more + * clear in future SAL specs. We'll fall back to getting it out of + * AR.KR0 if no appropriate entry is found in the memory map. */ - ia64_iobase = ia64_get_kr(IA64_KR_IO_BASE); + ia64_iobase = efi_get_iobase(); + if (ia64_iobase) + /* set AR.KR0 since this is all we use it for anyway */ + ia64_set_kr(IA64_KR_IO_BASE, ia64_iobase); + else { + ia64_iobase = ia64_get_kr(IA64_KR_IO_BASE); + printk("No I/O port range found in EFI memory map, falling back to AR.KR0\n"); + printk("I/O port base = 0x%lx\n", ia64_iobase); + } ia64_iobase = __IA64_UNCACHED_OFFSET | (ia64_iobase & ~PAGE_OFFSET); - cpu_init(); /* initialize the bootstrap CPU */ - #ifdef CONFIG_SMP cpu_physical_id(0) = hard_smp_processor_id(); #endif + cpu_init(); /* initialize the bootstrap CPU */ + #ifdef CONFIG_IA64_GENERIC machvec_init(acpi_get_sysname()); #endif -#ifdef CONFIG_ACPI20 if (efi.acpi20) { /* Parse the ACPI 2.0 tables */ acpi20_parse(efi.acpi20); - } else -#endif - if (efi.acpi) { + } else if (efi.acpi) { /* Parse the ACPI tables */ acpi_parse(efi.acpi); } @@ -257,6 +357,8 @@ platform_setup(cmdline_p); paging_init(); + + unw_create_gate_table(); } /* @@ -270,26 +372,18 @@ #else # define lpj loops_per_jiffy #endif - char family[32], model[32], features[128], *cp, *p = buffer; + char family[32], features[128], *cp, *p = buffer; struct cpuinfo_ia64 *c; - unsigned long mask; - - for (c = cpu_data; c < cpu_data + NR_CPUS; ++c) { -#ifdef CONFIG_SMP - if (!(cpu_online_map & (1UL << (c - cpu_data)))) - continue; -#endif + unsigned long mask, cpu; + for (cpu = 0; cpu < smp_num_cpus; ++cpu) { + c = cpu_data(cpu); mask = c->features; - if (c->family == 7) - memcpy(family, "IA-64", 6); - else - sprintf(family, "%u", c->family); - - switch (c->model) { - case 0: strcpy(model, "Itanium"); break; - default: sprintf(model, "%u", c->model); break; + switch (c->family) { + case 0x07: memcpy(family, "Itanium", 8); break; + case 0x1f: memcpy(family, "McKinley", 9); break; + default: sprintf(family, "%u", c->family); break; } /* build the feature string: */ @@ -306,8 +400,9 @@ p += sprintf(p, "processor : %lu\n" "vendor : %s\n" + "arch : IA-64\n" "family : %s\n" - "model : %s\n" + "model : %u\n" "revision : %u\n" "archrev : %u\n" "features :%s\n" /* don't change this---it _is_ right! */ @@ -316,8 +411,7 @@ "cpu MHz : %lu.%06lu\n" "itc MHz : %lu.%06lu\n" "BogoMIPS : %lu.%02lu\n\n", - c - cpu_data, c->vendor, family, model, c->revision, c->archrev, - features, + cpu, c->vendor, family, c->model, c->revision, c->archrev, features, c->ppn, c->number, c->proc_freq / 1000000, c->proc_freq % 1000000, c->itc_freq / 1000000, c->itc_freq % 1000000, lpj*HZ/500000, (lpj*HZ/5000) % 100); @@ -385,18 +479,54 @@ void cpu_init (void) { - extern void __init ia64_mmu_init (void); + extern void __init ia64_mmu_init (void *); unsigned long num_phys_stacked; pal_vm_info_2_u_t vmi; unsigned int max_ctx; + struct cpuinfo_ia64 *my_cpu_data; +#ifdef CONFIG_NUMA + int cpu, order; + + /* + * If NUMA is configured, the cpu_data array is not preallocated. The boot cpu + * allocates entries for every possible cpu. As the remaining cpus come online, + * they reallocate a new cpu_data structure on their local node. This extra work + * is required because some boot code references all cpu_data structures + * before the cpus are actually started. + */ + if (!boot_cpu_data) { + my_cpu_data = alloc_bootmem_pages_node(NODE_DATA(numa_node_id()), + sizeof(struct cpuinfo_ia64)); + boot_cpu_data = my_cpu_data; + my_cpu_data->cpu_data[0] = my_cpu_data; + for (cpu = 1; cpu < NR_CPUS; ++cpu) + my_cpu_data->cpu_data[cpu] + = alloc_bootmem_pages_node(NODE_DATA(numa_node_id()), + sizeof(struct cpuinfo_ia64)); + for (cpu = 1; cpu < NR_CPUS; ++cpu) + memcpy(my_cpu_data->cpu_data[cpu]->cpu_data_ptrs, + my_cpu_data->cpu_data, sizeof(my_cpu_data->cpu_data)); + } else { + order = get_order(sizeof(struct cpuinfo_ia64)); + my_cpu_data = page_address(alloc_pages_node(numa_node_id(), GFP_KERNEL, order)); + memcpy(my_cpu_data, boot_cpu_data->cpu_data[smp_processor_id()], + sizeof(struct cpuinfo_ia64)); + __free_pages(virt_to_page(boot_cpu_data->cpu_data[smp_processor_id()]), + order); + for (cpu = 0; cpu < NR_CPUS; ++cpu) + boot_cpu_data->cpu_data[cpu]->cpu_data[smp_processor_id()] = my_cpu_data; + } +#else + my_cpu_data = cpu_data(smp_processor_id()); +#endif /* - * We can't pass "local_cpu_data" do identify_cpu() because we haven't called + * We can't pass "local_cpu_data" to identify_cpu() because we haven't called * ia64_mmu_init() yet. And we can't call ia64_mmu_init() first because it * depends on the data returned by identify_cpu(). We break the dependency by - * accessing cpu_data[] the old way, through identity mapped space. + * accessing cpu_data() the old way, through identity mapped space. */ - identify_cpu(&cpu_data[smp_processor_id()]); + identify_cpu(my_cpu_data); /* Clear the stack memory reserved for pt_regs: */ memset(ia64_task_regs(current), 0, sizeof(struct pt_regs)); @@ -415,13 +545,11 @@ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; - ia64_mmu_init(); + ia64_mmu_init(my_cpu_data); #ifdef CONFIG_IA32_SUPPORT /* initialize global ia32 state - CR0 and CR4 */ - __asm__("mov ar.cflg = %0" - : /* no outputs */ - : "r" (((ulong) IA32_CR4 << 32) | IA32_CR0)); + asm volatile ("mov ar.cflg = %0" :: "r" (((ulong) IA32_CR4 << 32) | IA32_CR0)); #endif /* disable all local interrupt sources: */ diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/sigframe.h linux/arch/ia64/kernel/sigframe.h --- v2.4.7/linux/arch/ia64/kernel/sigframe.h Wed Dec 31 16:00:00 1969 +++ linux/arch/ia64/kernel/sigframe.h Tue Jul 31 10:30:08 2001 @@ -0,0 +1,16 @@ +struct sigframe { + /* + * Place signal handler args where user-level unwinder can find them easily. + * DO NOT MOVE THESE. They are part of the IA-64 Linux ABI and there is + * user-level code that depends on their presence! + */ + unsigned long arg0; /* signum */ + unsigned long arg1; /* siginfo pointer */ + unsigned long arg2; /* sigcontext pointer */ + + unsigned long rbs_base; /* base of new register backing store (or NULL) */ + void *handler; /* pointer to the plabel of the signal handler */ + + struct siginfo info; + struct sigcontext sc; +}; diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/signal.c linux/arch/ia64/kernel/signal.c --- v2.4.7/linux/arch/ia64/kernel/signal.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/signal.c Tue Jul 31 10:30:08 2001 @@ -25,6 +25,8 @@ #include #include +#include "sigframe.h" + #define DEBUG_SIG 0 #define STACK_ALIGN 16 /* minimal alignment for stack pointer */ #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -43,11 +45,6 @@ struct pt_regs pt; }; -struct sigframe { - struct siginfo info; - struct sigcontext sc; -}; - extern long ia64_do_signal (sigset_t *, struct sigscratch *, long); /* forward decl */ long @@ -380,7 +377,13 @@ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; - err = copy_siginfo_to_user(&frame->info, info); + err = __put_user(sig, &frame->arg0); + err |= __put_user(&frame->info, &frame->arg1); + err |= __put_user(&frame->sc, &frame->arg2); + err |= __put_user(new_rbs, &frame->rbs_base); + err |= __put_user(ka->sa.sa_handler, &frame->handler); + + err |= copy_siginfo_to_user(&frame->info, info); err |= __put_user(current->sas_ss_sp, &frame->sc.sc_stack.ss_sp); err |= __put_user(current->sas_ss_size, &frame->sc.sc_stack.ss_size); @@ -390,19 +393,16 @@ if (err) goto give_sigsegv; - scr->pt.r12 = (unsigned long) frame - 16; /* new stack pointer */ - scr->pt.r2 = sig; /* signal number */ - scr->pt.r3 = (unsigned long) ka->sa.sa_handler; /* addr. of handler's proc desc */ - scr->pt.r15 = new_rbs; + scr->pt.r12 = (unsigned long) frame - 16; /* new stack pointer */ scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */ scr->pt.cr_iip = tramp_addr; ia64_psr(&scr->pt)->ri = 0; /* start executing in first slot */ /* - * Note: this affects only the NaT bits of the scratch regs - * (the ones saved in pt_regs), which is exactly what we want. + * Note: this affects only the NaT bits of the scratch regs (the ones saved in + * pt_regs), which is exactly what we want. */ - scr->scratch_unat = 0; /* ensure NaT bits of at least r2, r3, r12, and r15 are clear */ + scr->scratch_unat = 0; /* ensure NaT bits of r12 is clear */ #if DEBUG_SIG printk("SIG deliver (%s:%d): sig=%d sp=%lx ip=%lx handler=%lx\n", diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/smp.c linux/arch/ia64/kernel/smp.c --- v2.4.7/linux/arch/ia64/kernel/smp.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/smp.c Tue Jul 31 10:30:08 2001 @@ -6,12 +6,16 @@ * * Lots of stuff stolen from arch/alpha/kernel/smp.c * - * 00/09/11 David Mosberger Do loops_per_jiffy calibration on each CPU. - * 00/08/23 Asit Mallick fixed logical processor id - * 00/03/31 Rohit Seth Fixes for Bootstrap Processor & cpu_online_map - * now gets done here (instead of setup.c) - * 99/10/05 davidm Update to bring it in sync with new command-line processing scheme. - * 10/13/00 Goutham Rao Updated smp_call_function and + * 01/05/16 Rohit Seth IA64-SMP functions. Reorganized + * the existing code (on the lines of x86 port). + * 00/09/11 David Mosberger Do loops_per_jiffy + * calibration on each CPU. + * 00/08/23 Asit Mallick fixed logical processor id + * 00/03/31 Rohit Seth Fixes for Bootstrap Processor + * & cpu_online_map now gets done here (instead of setup.c) + * 99/10/05 davidm Update to bring it in sync with new command-line processing + * scheme. + * 10/13/00 Goutham Rao Updated smp_call_function and * smp_call_function_single to resend IPI on timeouts */ #define __KERNEL_SYSCALLS__ @@ -45,120 +49,47 @@ #include #include -extern void __init calibrate_delay(void); -extern int cpu_idle(void * unused); -extern void machine_halt(void); -extern void start_ap(void); - -extern int cpu_now_booting; /* used by head.S to find idle task */ -extern volatile unsigned long cpu_online_map; /* bitmap of available cpu's */ - -struct smp_boot_data smp_boot_data __initdata; - +/* The 'big kernel lock' */ spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; -char __initdata no_int_routing; - -/* don't make this a CPU-local variable: it's used for IPIs, mostly... */ -int __cpu_physical_id[NR_CPUS]; /* logical ID -> physical CPU ID map */ - -unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */ -int smp_num_cpus = 1; -volatile int smp_threads_ready; /* set when the idlers are all forked */ -unsigned long ap_wakeup_vector; /* external Int to use to wakeup AP's */ - -static volatile unsigned long cpu_callin_map; -static volatile int smp_commenced; - -static int max_cpus = -1; /* command line */ +/* + * Structure and data for smp_call_function(). This is designed to minimise static memory + * requirements. It also looks cleaner. + */ +static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; -struct smp_call_struct { +struct call_data_struct { void (*func) (void *info); void *info; long wait; - atomic_t unstarted_count; - atomic_t unfinished_count; + atomic_t started; + atomic_t finished; }; -static volatile struct smp_call_struct *smp_call_function_data; - -#define IPI_RESCHEDULE 0 -#define IPI_CALL_FUNC 1 -#define IPI_CPU_STOP 2 -#ifndef CONFIG_ITANIUM_PTCG -# define IPI_FLUSH_TLB 3 -#endif /*!CONFIG_ITANIUM_PTCG */ - -/* - * Setup routine for controlling SMP activation - * - * Command-line option of "nosmp" or "maxcpus=0" will disable SMP - * activation entirely (the MPS table probe still happens, though). - * - * Command-line option of "maxcpus=", where is an integer - * greater than 0, limits the maximum number of CPUs activated in - * SMP mode to . - */ - -static int __init -nosmp (char *str) -{ - max_cpus = 0; - return 1; -} - -__setup("nosmp", nosmp); - -static int __init -maxcpus (char *str) -{ - get_option(&str, &max_cpus); - return 1; -} - -__setup("maxcpus=", maxcpus); -static int __init -nointroute (char *str) -{ - no_int_routing = 1; - return 1; -} +static volatile struct call_data_struct *call_data; -__setup("nointroute", nointroute); +#define IPI_CALL_FUNC 0 +#define IPI_CPU_STOP 1 +#ifndef CONFIG_ITANIUM_PTCG +# define IPI_FLUSH_TLB 2 +#endif /*!CONFIG_ITANIUM_PTCG */ -/* - * Yoink this CPU from the runnable list... - */ -void -halt_processor (void) +static void +stop_this_cpu (void) { + /* + * Remove this CPU: + */ clear_bit(smp_processor_id(), &cpu_online_map); max_xtp(); __cli(); - for (;;) - ; -} - -static inline int -pointer_lock (void *lock, void *data, int retry) -{ - volatile long *ptr = lock; - again: - if (cmpxchg_acq((void **) lock, 0, data) == 0) - return 0; - - if (!retry) - return -EBUSY; - - while (*ptr) - ; - - goto again; + for (;;); } void handle_IPI (int irq, void *dev_id, struct pt_regs *regs) { + int this_cpu = smp_processor_id(); unsigned long *pending_ipis = &local_cpu_data->ipi_operation; unsigned long ops; @@ -175,28 +106,21 @@ ops &= ~(1 << which); switch (which) { - case IPI_RESCHEDULE: - /* - * Reschedule callback. Everything to be done is done by the - * interrupt return path. - */ - break; - case IPI_CALL_FUNC: { - struct smp_call_struct *data; + struct call_data_struct *data; void (*func)(void *info); void *info; int wait; /* release the 'pointer lock' */ - data = (struct smp_call_struct *) smp_call_function_data; + data = (struct call_data_struct *) call_data; func = data->func; info = data->info; wait = data->wait; mb(); - atomic_dec(&data->unstarted_count); + atomic_inc(&data->started); /* At this point the structure may be gone unless wait is true. */ (*func)(info); @@ -204,12 +128,12 @@ /* Notify the sending CPU that the task is done. */ mb(); if (wait) - atomic_dec(&data->unfinished_count); + atomic_inc(&data->finished); } break; case IPI_CPU_STOP: - halt_processor(); + stop_this_cpu(); break; #ifndef CONFIG_ITANIUM_PTCG @@ -224,13 +148,9 @@ /* * Current CPU may be running with different RID so we need to - * reload the RID of flushed address. - * Current CPU may be running with different - * RID so we need to reload the RID of flushed - * address. Purging the translation also - * needs ALAT invalidation; we do not need - * "invala" here since it is done in - * ia64_leave_kernel. + * reload the RID of flushed address. Purging the translation + * also needs ALAT invalidation; we do not need "invala" here + * since it is done in ia64_leave_kernel. */ ia64_srlz_d(); if (saved_rid != flush_rid) { @@ -260,8 +180,7 @@ #endif /* !CONFIG_ITANIUM_PTCG */ default: - printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", - smp_processor_id(), which); + printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which); break; } /* Switch */ } while (ops); @@ -273,11 +192,7 @@ static inline void send_IPI_single (int dest_cpu, int op) { - - if (dest_cpu == -1) - return; - - set_bit(op, &cpu_data[dest_cpu].ipi_operation); + set_bit(op, &cpu_data(dest_cpu)->ipi_operation); platform_send_ipi(dest_cpu, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0); } @@ -310,13 +225,7 @@ void smp_send_reschedule (int cpu) { - send_IPI_single(cpu, IPI_RESCHEDULE); -} - -void -smp_send_stop (void) -{ - send_IPI_allbutself(IPI_CPU_STOP); + platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); } #ifndef CONFIG_ITANIUM_PTCG @@ -328,22 +237,33 @@ } void -smp_resend_flush_tlb(void) +smp_resend_flush_tlb (void) { + int i; + /* * Really need a null IPI but since this rarely should happen & since this code * will go away, lets not add one. */ - send_IPI_allbutself(IPI_RESCHEDULE); + for (i = 0; i < smp_num_cpus; ++i) + if (i != smp_processor_id()) + smp_send_reschedule(i); } -#endif /* !CONFIG_ITANIUM_PTCG */ +#endif /* !CONFIG_ITANIUM_PTCG */ + +void +smp_flush_tlb_all (void) +{ + smp_call_function ((void (*)(void *))__flush_tlb_all,0,1,1); + __flush_tlb_all(); +} /* * Run a function on another CPU * The function to run. This must be fast and non-blocking. * An arbitrary pointer to pass to the function. - * If true, keep retrying until ready. + * Currently unused. * If true, wait until function has completed on other CPUs. * [RETURNS] 0 on success, else a negative status code. * @@ -352,11 +272,15 @@ */ int -smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int retry, int wait) +smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int nonatomic, + int wait) { - struct smp_call_struct data; - unsigned long timeout; + struct call_data_struct data; int cpus = 1; +#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC)) + unsigned long timeout; +#endif if (cpuid == smp_processor_id()) { printk(__FUNCTION__" trying to call self\n"); @@ -365,115 +289,110 @@ data.func = func; data.info = info; + atomic_set(&data.started, 0); data.wait = wait; - atomic_set(&data.unstarted_count, cpus); - atomic_set(&data.unfinished_count, cpus); + if (wait) + atomic_set(&data.finished, 0); - if (pointer_lock(&smp_call_function_data, &data, retry)) - return -EBUSY; + spin_lock_bh(&call_lock); + call_data = &data; -resend: - /* Send a message to all other CPUs and wait for them to respond */ - send_IPI_single(cpuid, IPI_CALL_FUNC); +#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC)) + resend: + send_IPI_single(cpuid, IPI_CALL_FUNC); - /* Wait for response */ + /* Wait for response */ timeout = jiffies + HZ; - while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout)) + while ((atomic_read(&data.started) != cpus) && time_before(jiffies, timeout)) barrier(); - if (atomic_read(&data.unstarted_count) > 0) { -#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) + if (atomic_read(&data.started) != cpus) goto resend; #else - smp_call_function_data = NULL; - return -ETIMEDOUT; + send_IPI_single(cpuid, IPI_CALL_FUNC); + + /* Wait for response */ + while (atomic_read(&data.started) != cpus) + barrier(); #endif - } if (wait) - while (atomic_read(&data.unfinished_count) > 0) + while (atomic_read(&data.finished) != cpus) barrier(); - /* unlock pointer */ - smp_call_function_data = NULL; + call_data = NULL; + + spin_unlock_bh(&call_lock); return 0; } /* - * Run a function on all other CPUs. + * this function sends a 'generic call function' IPI to all other CPUs + * in the system. + */ + +/* + * [SUMMARY] Run a function on all other CPUs. * The function to run. This must be fast and non-blocking. * An arbitrary pointer to pass to the function. - * If true, keep retrying until ready. - * If true, wait until function has completed on other CPUs. + * currently unused. + * If true, wait (atomically) until function has completed on other CPUs. * [RETURNS] 0 on success, else a negative status code. * - * Does not return until remote CPUs are nearly ready to execute - * or are or have executed. + * Does not return until remote CPUs are nearly ready to execute or are or have + * executed. + * + * You must not call this function with disabled interrupts or from a hardware interrupt + * handler, you may call it from a bottom half handler. */ int -smp_call_function (void (*func) (void *info), void *info, int retry, int wait) +smp_call_function (void (*func) (void *info), void *info, int nonatomic, int wait) { - struct smp_call_struct data; + struct call_data_struct data; + int cpus = smp_num_cpus-1; +#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC)) unsigned long timeout; - int cpus = smp_num_cpus - 1; +#endif - if (cpus == 0) + if (!cpus) return 0; data.func = func; data.info = info; + atomic_set(&data.started, 0); data.wait = wait; - atomic_set(&data.unstarted_count, cpus); - atomic_set(&data.unfinished_count, cpus); + if (wait) + atomic_set(&data.finished, 0); - if (pointer_lock(&smp_call_function_data, &data, retry)) - return -EBUSY; + spin_lock_bh(&call_lock); + call_data = &data; - /* Send a message to all other CPUs and wait for them to respond */ +#if (defined(CONFIG_ITANIUM_B0_SPECIFIC) \ + || defined(CONFIG_ITANIUM_B1_SPECIFIC) || defined(CONFIG_ITANIUM_B2_SPECIFIC)) + resend: + /* Send a message to all other CPUs and wait for them to respond */ send_IPI_allbutself(IPI_CALL_FUNC); -retry: - /* Wait for response */ + /* Wait for response */ timeout = jiffies + HZ; - while ((atomic_read(&data.unstarted_count) > 0) && time_before(jiffies, timeout)) + while ((atomic_read(&data.started) != cpus) && time_before(jiffies, timeout)) barrier(); - if (atomic_read(&data.unstarted_count) > 0) { -#if (defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC)) - int i; - for (i = 0; i < smp_num_cpus; i++) { - if (i != smp_processor_id()) - platform_send_ipi(i, IA64_IPI_VECTOR, IA64_IPI_DM_INT, 0); - } - goto retry; + if (atomic_read(&data.started) != cpus) + goto resend; #else - smp_call_function_data = NULL; - return -ETIMEDOUT; + send_IPI_allbutself(IPI_CALL_FUNC); + + /* Wait for response */ + while (atomic_read(&data.started) != cpus) + barrier(); #endif - } + if (wait) - while (atomic_read(&data.unfinished_count) > 0) + while (atomic_read(&data.finished) != cpus) barrier(); - /* unlock pointer */ - smp_call_function_data = NULL; - return 0; -} - -/* - * Flush all other CPU's tlb and then mine. Do this with smp_call_function() as we - * want to ensure all TLB's flushed before proceeding. - */ -void -smp_flush_tlb_all (void) -{ - smp_call_function((void (*)(void *))__flush_tlb_all, NULL, 1, 1); - __flush_tlb_all(); -} + call_data = NULL; -/* - * Ideally sets up per-cpu profiling hooks. Doesn't do much now... - */ -static inline void __init -smp_setup_percpu_timer(void) -{ - local_cpu_data->prof_counter = 1; - local_cpu_data->prof_multiplier = 1; + spin_unlock_bh(&call_lock); + return 0; } void @@ -487,232 +406,18 @@ } } - -/* - * AP's start using C here. - */ -void __init -smp_callin (void) -{ - extern void ia64_rid_init(void); - extern void ia64_init_itm(void); - extern void ia64_cpu_local_tick(void); -#ifdef CONFIG_PERFMON - extern void perfmon_init_percpu(void); -#endif - int cpu = smp_processor_id(); - - if (test_and_set_bit(cpu, &cpu_online_map)) { - printk("CPU#%d already initialized!\n", cpu); - machine_halt(); - } - - efi_map_pal_code(); - cpu_init(); - - smp_setup_percpu_timer(); - - /* setup the CPU local timer tick */ - ia64_init_itm(); - -#ifdef CONFIG_PERFMON - perfmon_init_percpu(); -#endif - local_irq_enable(); /* Interrupts have been off until now */ - - calibrate_delay(); - local_cpu_data->loops_per_jiffy = loops_per_jiffy; - - /* allow the master to continue */ - set_bit(cpu, &cpu_callin_map); - - /* finally, wait for the BP to finish initialization: */ - while (!smp_commenced); - - cpu_idle(NULL); -} - -/* - * Create the idle task for a new AP. DO NOT use kernel_thread() because - * that could end up calling schedule() in the ia64_leave_kernel exit - * path in which case the new idle task could get scheduled before we - * had a chance to remove it from the run-queue... - */ -static int __init -fork_by_hand (void) -{ - /* - * Don't care about the usp and regs settings since we'll never - * reschedule the forked task. - */ - return do_fork(CLONE_VM|CLONE_PID, 0, 0, 0); -} - -/* - * Bring one cpu online. Return 0 if this fails for any reason. - */ -static int __init -smp_boot_one_cpu (int cpu) -{ - struct task_struct *idle; - int cpu_phys_id = cpu_physical_id(cpu); - long timeout; - - /* - * Create an idle task for this CPU. Note that the address we - * give to kernel_thread is irrelevant -- it's going to start - * where OS_BOOT_RENDEVZ vector in SAL says to start. But - * this gets all the other task-y sort of data structures set - * up like we wish. We need to pull the just created idle task - * off the run queue and stuff it into the init_tasks[] array. - * Sheesh . . . - */ - if (fork_by_hand() < 0) - panic("failed fork for CPU 0x%x", cpu_phys_id); - /* - * We remove it from the pidhash and the runqueue - * once we got the process: - */ - idle = init_task.prev_task; - if (!idle) - panic("No idle process for CPU 0x%x", cpu_phys_id); - init_tasks[cpu] = idle; - del_from_runqueue(idle); - unhash_process(idle); - - /* Schedule the first task manually. */ - idle->processor = cpu; - idle->has_cpu = 1; - - /* Let _start know what logical CPU we're booting (offset into init_tasks[] */ - cpu_now_booting = cpu; - - /* Kick the AP in the butt */ - platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); - - /* wait up to 10s for the AP to start */ - for (timeout = 0; timeout < 100000; timeout++) { - if (test_bit(cpu, &cpu_callin_map)) - return 1; - udelay(100); - } - - printk(KERN_ERR "SMP: CPU 0x%x is stuck\n", cpu_phys_id); - return 0; -} - - - -/* - * Called by smp_init bring all the secondaries online and hold them. - */ -void __init -smp_boot_cpus (void) -{ - int i, cpu_count = 1; - unsigned long bogosum; - - /* on the BP, the kernel already called calibrate_delay_loop() in init/main.c */ - local_cpu_data->loops_per_jiffy = loops_per_jiffy; -#if 0 - smp_tune_scheduling(); -#endif - smp_setup_percpu_timer(); - - if (test_and_set_bit(0, &cpu_online_map)) { - printk("CPU#%d already initialized!\n", smp_processor_id()); - machine_halt(); - } - init_idle(); - - /* Nothing to do when told not to. */ - if (max_cpus == 0) { - printk(KERN_INFO "SMP mode deactivated.\n"); - return; - } - - if (max_cpus != -1) - printk("Limiting CPUs to %d\n", max_cpus); - - if (smp_boot_data.cpu_count > 1) { - printk(KERN_INFO "SMP: starting up secondaries.\n"); - - for (i = 0; i < smp_boot_data.cpu_count; i++) { - /* skip performance restricted and bootstrap cpu: */ - if (smp_boot_data.cpu_phys_id[i] == -1 - || smp_boot_data.cpu_phys_id[i] == hard_smp_processor_id()) - continue; - - cpu_physical_id(cpu_count) = smp_boot_data.cpu_phys_id[i]; - if (!smp_boot_one_cpu(cpu_count)) - continue; /* failed */ - - cpu_count++; /* Count good CPUs only... */ - /* - * Bail if we've started as many CPUS as we've been told to. - */ - if (cpu_count == max_cpus) - break; - } - } - - if (cpu_count == 1) { - printk(KERN_ERR "SMP: Bootstrap processor only.\n"); - } - - bogosum = 0; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_online_map & (1L << i)) - bogosum += cpu_data[i].loops_per_jiffy; - } - - printk(KERN_INFO "SMP: Total of %d processors activated (%lu.%02lu BogoMIPS).\n", - cpu_count, bogosum*HZ/500000, (bogosum*HZ/5000) % 100); - - smp_num_cpus = cpu_count; -} - /* - * Called when the BP is just about to fire off init. + * this function calls the 'stop' function on all other CPUs in the system. */ -void __init -smp_commence (void) +void +smp_send_stop (void) { - smp_commenced = 1; + send_IPI_allbutself(IPI_CPU_STOP); + smp_num_cpus = 1; } int __init setup_profiling_timer (unsigned int multiplier) { return -EINVAL; -} - -/* - * Assume that CPU's have been discovered by some platform-dependant - * interface. For SoftSDV/Lion, that would be ACPI. - * - * Setup of the IPI irq handler is done in irq.c:init_IRQ(). - * - * This also registers the AP OS_MC_REDVEZ address with SAL. - */ -void __init -init_smp_config (void) -{ - struct fptr { - unsigned long fp; - unsigned long gp; - } *ap_startup; - long sal_ret; - - /* Tell SAL where to drop the AP's. */ - ap_startup = (struct fptr *) start_ap; - sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, __pa(ap_startup->fp), - __pa(ap_startup->gp), 0, 0, 0, 0); - if (sal_ret < 0) { - printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n", ia64_sal_strerror(sal_ret)); - printk(" Forcing UP mode\n"); - max_cpus = 0; - smp_num_cpus = 1; - } - } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/smpboot.c linux/arch/ia64/kernel/smpboot.c --- v2.4.7/linux/arch/ia64/kernel/smpboot.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/smpboot.c Tue Jul 31 10:30:08 2001 @@ -1,4 +1,563 @@ /* + * SMP boot-related support + * + * Copyright (C) 2001 David Mosberger-Tang + * + * 01/05/16 Rohit Seth Moved SMP booting functions from smp.c to here. + * 01/04/27 David Mosberger Added ITC synching code. */ -/* place holder... */ + +#define __KERNEL_SYSCALLS__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if SMP_DEBUG +#define Dprintk(x...) printk(x) +#else +#define Dprintk(x...) +#endif + + +/* + * ITC synchronization related stuff: + */ +#define MASTER 0 +#define SLAVE (SMP_CACHE_BYTES/8) + +#define NUM_ROUNDS 64 /* magic value */ +#define NUM_ITERS 5 /* likewise */ + +static spinlock_t itc_sync_lock = SPIN_LOCK_UNLOCKED; +static volatile unsigned long go[SLAVE + 1]; + +#define DEBUG_ITC_SYNC 0 + +extern void __init calibrate_delay(void); +extern void start_ap(void); + +int cpucount; + +/* Setup configured maximum number of CPUs to activate */ +static int max_cpus = -1; + +/* Total count of live CPUs */ +int smp_num_cpus = 1; + +/* Bitmask of currently online CPUs */ +volatile unsigned long cpu_online_map; + +/* which logical CPU number maps to which CPU (physical APIC ID) */ +volatile int ia64_cpu_to_sapicid[NR_CPUS]; + +static volatile unsigned long cpu_callin_map; + +struct smp_boot_data smp_boot_data __initdata; + +/* Set when the idlers are all forked */ +volatile int smp_threads_ready; + +unsigned long ap_wakeup_vector = -1; /* External Int use to wakeup APs */ + +char __initdata no_int_routing; + +unsigned char smp_int_redirect; /* are INT and IPI redirectable by the chipset? */ + +/* + * Setup routine for controlling SMP activation + * + * Command-line option of "nosmp" or "maxcpus=0" will disable SMP + * activation entirely (the MPS table probe still happens, though). + * + * Command-line option of "maxcpus=", where is an integer + * greater than 0, limits the maximum number of CPUs activated in + * SMP mode to . + */ + +static int __init +nosmp (char *str) +{ + max_cpus = 0; + return 1; +} + +__setup("nosmp", nosmp); + +static int __init +maxcpus (char *str) +{ + get_option(&str, &max_cpus); + return 1; +} + +__setup("maxcpus=", maxcpus); + +static int __init +nointroute (char *str) +{ + no_int_routing = 1; + return 1; +} + +__setup("nointroute", nointroute); + +void +sync_master (void *arg) +{ + unsigned long flags, i; + + go[MASTER] = 0; + + local_irq_save(flags); + { + for (i = 0; i < NUM_ROUNDS*NUM_ITERS; ++i) { + while (!go[MASTER]); + go[MASTER] = 0; + go[SLAVE] = ia64_get_itc(); + } + } + local_irq_restore(flags); +} + +/* + * Return the number of cycles by which our itc differs from the itc on the master + * (time-keeper) CPU. A positive number indicates our itc is ahead of the master, + * negative that it is behind. + */ +static inline long +get_delta (long *rt, long *master) +{ + unsigned long best_t0 = 0, best_t1 = ~0UL, best_tm = 0; + unsigned long tcenter, t0, t1, tm; + long i; + + for (i = 0; i < NUM_ITERS; ++i) { + t0 = ia64_get_itc(); + go[MASTER] = 1; + while (!(tm = go[SLAVE])); + go[SLAVE] = 0; + t1 = ia64_get_itc(); + + if (t1 - t0 < best_t1 - best_t0) + best_t0 = t0, best_t1 = t1, best_tm = tm; + } + + *rt = best_t1 - best_t0; + *master = best_tm - best_t0; + + /* average best_t0 and best_t1 without overflow: */ + tcenter = (best_t0/2 + best_t1/2); + if (best_t0 % 2 + best_t1 % 2 == 2) + ++tcenter; + return tcenter - best_tm; +} + +/* + * Synchronize ar.itc of the current (slave) CPU with the ar.itc of the MASTER CPU + * (normally the time-keeper CPU). We use a closed loop to eliminate the possibility of + * unaccounted-for errors (such as getting a machine check in the middle of a calibration + * step). The basic idea is for the slave to ask the master what itc value it has and to + * read its own itc before and after the master responds. Each iteration gives us three + * timestamps: + * + * slave master + * + * t0 ---\ + * ---\ + * ---> + * tm + * /--- + * /--- + * t1 <--- + * + * + * The goal is to adjust the slave's ar.itc such that tm falls exactly half-way between t0 + * and t1. If we achieve this, the clocks are synchronized provided the interconnect + * between the slave and the master is symmetric. Even if the interconnect were + * asymmetric, we would still know that the synchronization error is smaller than the + * roundtrip latency (t0 - t1). + * + * When the interconnect is quiet and symmetric, this lets us synchronize the itc to + * within one or two cycles. However, we can only *guarantee* that the synchronization is + * accurate to within a round-trip time, which is typically in the range of several + * hundred cycles (e.g., ~500 cycles). In practice, this means that the itc's are usually + * almost perfectly synchronized, but we shouldn't assume that the accuracy is much better + * than half a micro second or so. + */ +void +ia64_sync_itc (unsigned int master) +{ + long i, delta, adj, adjust_latency = 0, done = 0; + unsigned long flags, rt, master_time_stamp, bound; +#if DEBUG_ITC_SYNC + struct { + long rt; /* roundtrip time */ + long master; /* master's timestamp */ + long diff; /* difference between midpoint and master's timestamp */ + long lat; /* estimate of itc adjustment latency */ + } t[NUM_ROUNDS]; +#endif + + go[MASTER] = 1; + + if (smp_call_function_single(master, sync_master, NULL, 1, 0) < 0) { + printk("sync_itc: failed to get attention of CPU %u!\n", master); + return; + } + + while (go[MASTER]); /* wait for master to be ready */ + + spin_lock_irqsave(&itc_sync_lock, flags); + { + for (i = 0; i < NUM_ROUNDS; ++i) { + delta = get_delta(&rt, &master_time_stamp); + if (delta == 0) { + done = 1; /* let's lock on to this... */ + bound = rt; + } + + if (!done) { + if (i > 0) { + adjust_latency += -delta; + adj = -delta + adjust_latency/4; + } else + adj = -delta; + + ia64_set_itc(ia64_get_itc() + adj); + } +#if DEBUG_ITC_SYNC + t[i].rt = rt; + t[i].master = master_time_stamp; + t[i].diff = delta; + t[i].lat = adjust_latency/4; +#endif + } + } + spin_unlock_irqrestore(&itc_sync_lock, flags); + +#if DEBUG_ITC_SYNC + for (i = 0; i < NUM_ROUNDS; ++i) + printk("rt=%5ld master=%5ld diff=%5ld adjlat=%5ld\n", + t[i].rt, t[i].master, t[i].diff, t[i].lat); +#endif + + printk("CPU %d: synchronized ITC with CPU %u (last diff %ld cycles, maxerr %lu cycles)\n", + smp_processor_id(), master, delta, rt); +} + +/* + * Ideally sets up per-cpu profiling hooks. Doesn't do much now... + */ +static inline void __init +smp_setup_percpu_timer (void) +{ + local_cpu_data->prof_counter = 1; + local_cpu_data->prof_multiplier = 1; +} + +/* + * Architecture specific routine called by the kernel just before init is + * fired off. This allows the BP to have everything in order [we hope]. + * At the end of this all the APs will hit the system scheduling and off + * we go. Each AP will jump through the kernel + * init into idle(). At this point the scheduler will one day take over + * and give them jobs to do. smp_callin is a standard routine + * we use to track CPUs as they power up. + */ + +static volatile atomic_t smp_commenced = ATOMIC_INIT(0); + +void __init +smp_commence (void) +{ + /* + * Lets the callins below out of their loop. + */ + Dprintk("Setting commenced=1, go go go\n"); + + wmb(); + atomic_set(&smp_commenced,1); +} + + +void __init +smp_callin (void) +{ + int cpuid, phys_id; + extern void ia64_init_itm(void); + +#ifdef CONFIG_PERFMON + extern void perfmon_init_percpu(void); +#endif + + cpuid = smp_processor_id(); + phys_id = hard_smp_processor_id(); + + if (test_and_set_bit(cpuid, &cpu_online_map)) { + printk("huh, phys CPU#0x%x, CPU#0x%x already present??\n", + phys_id, cpuid); + BUG(); + } + + smp_setup_percpu_timer(); + + /* + * Synchronize the ITC with the BP + */ + Dprintk("Going to syncup ITC with BP.\n"); + + ia64_sync_itc(0); + /* + * Get our bogomips. + */ + ia64_init_itm(); +#ifdef CONFIG_PERFMON + perfmon_init_percpu(); +#endif + + local_irq_enable(); + calibrate_delay(); + local_cpu_data->loops_per_jiffy = loops_per_jiffy; + /* + * Allow the master to continue. + */ + set_bit(cpuid, &cpu_callin_map); + Dprintk("Stack on CPU %d at about %p\n",cpuid, &cpuid); +} + + +/* + * Activate a secondary processor. head.S calls this. + */ +int __init +start_secondary (void *unused) +{ + extern int cpu_idle (void); + + efi_map_pal_code(); + cpu_init(); + smp_callin(); + Dprintk("CPU %d is set to go. \n", smp_processor_id()); + while (!atomic_read(&smp_commenced)) + ; + + Dprintk("CPU %d is starting idle. \n", smp_processor_id()); + return cpu_idle(); +} + +static int __init +fork_by_hand (void) +{ + /* + * don't care about the eip and regs settings since + * we'll never reschedule the forked task. + */ + return do_fork(CLONE_VM|CLONE_PID, 0, 0, 0); +} + +static void __init +do_boot_cpu (int sapicid) +{ + struct task_struct *idle; + int timeout, cpu; + + cpu = ++cpucount; + /* + * We can't use kernel_thread since we must avoid to + * reschedule the child. + */ + if (fork_by_hand() < 0) + panic("failed fork for CPU %d", cpu); + + /* + * We remove it from the pidhash and the runqueue + * once we got the process: + */ + idle = init_task.prev_task; + if (!idle) + panic("No idle process for CPU %d", cpu); + + idle->processor = cpu; + ia64_cpu_to_sapicid[cpu] = sapicid; + idle->has_cpu = 1; /* we schedule the first task manually */ + + del_from_runqueue(idle); + unhash_process(idle); + init_tasks[cpu] = idle; + + Dprintk("Sending Wakeup Vector to AP 0x%x/0x%x.\n", cpu, sapicid); + + platform_send_ipi(cpu, ap_wakeup_vector, IA64_IPI_DM_INT, 0); + + /* + * Wait 10s total for the AP to start + */ + Dprintk("Waiting on callin_map ..."); + for (timeout = 0; timeout < 100000; timeout++) { + Dprintk("."); + if (test_bit(cpu, &cpu_callin_map)) + break; /* It has booted */ + udelay(100); + } + Dprintk("\n"); + + if (test_bit(cpu, &cpu_callin_map)) { + /* number CPUs logically, starting from 1 (BSP is 0) */ + printk("CPU%d: ", cpu); + /*print_cpu_info(&cpu_data[cpu]); */ + printk("CPU has booted.\n"); + } else { + printk(KERN_ERR "Processor 0x%x/0x%x is stuck.\n", cpu, sapicid); + ia64_cpu_to_sapicid[cpu] = -1; + cpucount--; + } +} + +/* + * Cycle through the APs sending Wakeup IPIs to boot each. + */ +void __init +smp_boot_cpus (void) +{ + int sapicid, cpu; + int boot_cpu_id = hard_smp_processor_id(); + + /* + * Initialize the logical to physical CPU number mapping + * and the per-CPU profiling counter/multiplier + */ + + for (cpu = 0; cpu < NR_CPUS; cpu++) + ia64_cpu_to_sapicid[cpu] = -1; + smp_setup_percpu_timer(); + + /* + * We have the boot CPU online for sure. + */ + set_bit(0, &cpu_online_map); + set_bit(0, &cpu_callin_map); + + local_cpu_data->loops_per_jiffy = loops_per_jiffy; + ia64_cpu_to_sapicid[0] = boot_cpu_id; + + printk("Boot processor id 0x%x/0x%x\n", 0, boot_cpu_id); + + global_irq_holder = 0; + current->processor = 0; + init_idle(); + + /* + * If SMP should be disabled, then really disable it! + */ + if (!max_cpus || (max_cpus < -1)) { + printk(KERN_INFO "SMP mode deactivated.\n"); + cpu_online_map = 1; + smp_num_cpus = 1; + goto smp_done; + } + if (max_cpus != -1) + printk (KERN_INFO "Limiting CPUs to %d\n", max_cpus); + + if (smp_boot_data.cpu_count > 1) { + + printk(KERN_INFO "SMP: starting up secondaries.\n"); + + for (cpu = 0; cpu < smp_boot_data.cpu_count; cpu++) { + /* + * Don't even attempt to start the boot CPU! + */ + sapicid = smp_boot_data.cpu_phys_id[cpu]; + if ((sapicid == -1) || (sapicid == hard_smp_processor_id())) + continue; + + if ((max_cpus > 0) && (cpucount + 1 >= max_cpus)) + break; + + do_boot_cpu(sapicid); + + /* + * Make sure we unmap all failed CPUs + */ + if (ia64_cpu_to_sapicid[cpu] == -1) + printk("phys CPU#%d not responding - cannot use it.\n", cpu); + } + + smp_num_cpus = cpucount + 1; + + /* + * Allow the user to impress friends. + */ + + printk("Before bogomips.\n"); + if (!cpucount) { + printk(KERN_ERR "Error: only one processor found.\n"); + } else { + unsigned long bogosum = 0; + for (cpu = 0; cpu < NR_CPUS; cpu++) + if (cpu_online_map & (1<loops_per_jiffy; + + printk(KERN_INFO"Total of %d processors activated (%lu.%02lu BogoMIPS).\n", + cpucount + 1, bogosum/(500000/HZ), (bogosum/(5000/HZ))%100); + } + } + smp_done: + ; +} + +/* + * Assume that CPU's have been discovered by some platform-dependant interface. For + * SoftSDV/Lion, that would be ACPI. + * + * Setup of the IPI irq handler is done in irq.c:init_IRQ_SMP(). + */ +void __init +init_smp_config(void) +{ + struct fptr { + unsigned long fp; + unsigned long gp; + } *ap_startup; + long sal_ret; + + /* Tell SAL where to drop the AP's. */ + ap_startup = (struct fptr *) start_ap; + sal_ret = ia64_sal_set_vectors(SAL_VECTOR_OS_BOOT_RENDEZ, + __pa(ap_startup->fp), __pa(ap_startup->gp), 0, 0, 0, 0); + if (sal_ret < 0) { + printk("SMP: Can't set SAL AP Boot Rendezvous: %s\n Forcing UP mode\n", + ia64_sal_strerror(sal_ret)); + max_cpus = 0; + smp_num_cpus = 1; + } +} diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/sys_ia64.c linux/arch/ia64/kernel/sys_ia64.c --- v2.4.7/linux/arch/ia64/kernel/sys_ia64.c Fri Apr 13 15:38:51 2001 +++ linux/arch/ia64/kernel/sys_ia64.c Tue Jul 31 10:30:08 2001 @@ -22,16 +22,18 @@ #define COLOR_ALIGN(addr) (((addr) + SHMLBA - 1) & ~(SHMLBA - 1)) unsigned long -arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) +arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len, + unsigned long pgoff, unsigned long flags) { struct vm_area_struct * vmm; + long map_shared = (flags & MAP_SHARED); if (len > RGN_MAP_LIMIT) return -ENOMEM; if (!addr) addr = TASK_UNMAPPED_BASE; - if (flags & MAP_SHARED) + if (map_shared) addr = COLOR_ALIGN(addr); else addr = PAGE_ALIGN(addr); @@ -45,7 +47,7 @@ if (!vmm || addr + len <= vmm->vm_start) return addr; addr = vmm->vm_end; - if (flags & MAP_SHARED) + if (map_shared) addr = COLOR_ALIGN(addr); } } @@ -176,11 +178,22 @@ unsigned long roff; struct file *file = 0; + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + return -EBADF; + + if (!file->f_op || !file->f_op->mmap) + return -ENODEV; + } + /* - * A zero mmap always succeeds in Linux, independent of - * whether or not the remaining arguments are valid. + * A zero mmap always succeeds in Linux, independent of whether or not the + * remaining arguments are valid. */ - if (PAGE_ALIGN(len) == 0) + len = PAGE_ALIGN(len); + if (len == 0) return addr; /* don't permit mappings into unmapped space or the virtual page table of a region: */ @@ -192,13 +205,6 @@ if (rgn_index(addr) != rgn_index(addr + len)) return -EINVAL; - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - return -EBADF; - } - down_write(¤t->mm->mmap_sem); addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); up_write(¤t->mm->mmap_sem); @@ -244,13 +250,6 @@ sys_vm86 (long arg0, long arg1, long arg2, long arg3) { printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); - return -ENOSYS; -} - -asmlinkage long -sys_modify_ldt (long arg0, long arg1, long arg2, long arg3) -{ - printk(KERN_ERR "sys_modify_ldt(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3); return -ENOSYS; } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/time.c linux/arch/ia64/kernel/time.c --- v2.4.7/linux/arch/ia64/kernel/time.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/time.c Tue Jul 31 10:30:08 2001 @@ -25,6 +25,7 @@ extern rwlock_t xtime_lock; extern unsigned long wall_jiffies; +extern unsigned long last_time_offset; #ifdef CONFIG_IA64_DEBUG_IRQ @@ -45,9 +46,8 @@ ip -= (unsigned long) &_stext; ip >>= prof_shift; /* - * Don't ignore out-of-bounds IP values silently, - * put them into the last histogram slot, so if - * present, they will show up as a sharp peak. + * Don't ignore out-of-bounds IP values silently, put them into the last + * histogram slot, so if present, they will show up as a sharp peak. */ if (ip > prof_len - 1) ip = prof_len - 1; @@ -57,34 +57,29 @@ } /* - * Return the number of micro-seconds that elapsed since the last - * update to jiffy. The xtime_lock must be at least read-locked when - * calling this routine. + * Return the number of micro-seconds that elapsed since the last update to jiffy. The + * xtime_lock must be at least read-locked when calling this routine. */ static inline unsigned long gettimeoffset (void) { -#ifdef CONFIG_SMP - /* - * The code below doesn't work for SMP because only CPU 0 - * keeps track of the time. - */ - return 0; -#else - unsigned long now = ia64_get_itc(), last_tick; unsigned long elapsed_cycles, lost = jiffies - wall_jiffies; + unsigned long now, last_tick; +# define time_keeper_id 0 /* smp_processor_id() of time-keeper */ - last_tick = (local_cpu_data->itm_next - (lost+1)*local_cpu_data->itm_delta); -# if 1 + last_tick = (cpu_data(time_keeper_id)->itm_next + - (lost + 1)*cpu_data(time_keeper_id)->itm_delta); + + now = ia64_get_itc(); if ((long) (now - last_tick) < 0) { - printk("Yikes: now < last_tick (now=0x%lx,last_tick=%lx)! No can do.\n", - now, last_tick); - return 0; - } +# if 1 + printk("CPU %d: now < last_tick (now=0x%lx,last_tick=0x%lx)!\n", + smp_processor_id(), now, last_tick); # endif + return last_time_offset; + } elapsed_cycles = now - last_tick; return (elapsed_cycles*local_cpu_data->usec_per_cyc) >> IA64_USEC_PER_CYC_SHIFT; -#endif } void @@ -93,11 +88,10 @@ write_lock_irq(&xtime_lock); { /* - * This is revolting. We need to set "xtime" - * correctly. However, the value in this location is - * the value at the most recent update of wall time. - * Discover what correction gettimeofday would have - * done, and then undo it! + * This is revolting. We need to set "xtime" correctly. However, the value + * in this location is the value at the most recent update of wall time. + * Discover what correction gettimeofday would have done, and then undo + * it! */ tv->tv_usec -= gettimeoffset(); tv->tv_usec -= (jiffies - wall_jiffies) * (1000000 / HZ); @@ -119,12 +113,24 @@ void do_gettimeofday (struct timeval *tv) { - unsigned long flags, usec, sec; + unsigned long flags, usec, sec, old; read_lock_irqsave(&xtime_lock, flags); { usec = gettimeoffset(); + /* + * Ensure time never goes backwards, even when ITC on different CPUs are + * not perfectly synchronized. + */ + do { + old = last_time_offset; + if (usec <= old) { + usec = old; + break; + } + } while (cmpxchg(&last_time_offset, old, usec) != old); + sec = xtime.tv_sec; usec += xtime.tv_usec; } @@ -162,6 +168,8 @@ #ifdef CONFIG_SMP smp_do_timer(regs); #endif + new_itm += local_cpu_data->itm_delta; + if (smp_processor_id() == 0) { /* * Here we are in the timer irq handler. We have irqs locally @@ -171,11 +179,11 @@ */ write_lock(&xtime_lock); do_timer(regs); + local_cpu_data->itm_next = new_itm; write_unlock(&xtime_lock); - } + } else + local_cpu_data->itm_next = new_itm; - new_itm += local_cpu_data->itm_delta; - local_cpu_data->itm_next = new_itm; if (time_after(new_itm, ia64_get_itc())) break; } @@ -228,9 +236,9 @@ long status; /* - * According to SAL v2.6, we need to use a SAL call to determine the - * platform base frequency and then a PAL call to determine the - * frequency ratio between the ITC and the base frequency. + * According to SAL v2.6, we need to use a SAL call to determine the platform base + * frequency and then a PAL call to determine the frequency ratio between the ITC + * and the base frequency. */ status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM, &platform_base_freq, &drift); if (status != 0) { @@ -284,6 +292,6 @@ time_init (void) { register_percpu_irq(IA64_TIMER_VECTOR, &timer_irqaction); - efi_gettimeofday(&xtime); + efi_gettimeofday((struct timeval *) &xtime); ia64_init_itm(); } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/traps.c linux/arch/ia64/kernel/traps.c --- v2.4.7/linux/arch/ia64/kernel/traps.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/traps.c Tue Jul 31 10:30:08 2001 @@ -215,12 +215,9 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long *pr, long *ifs, struct pt_regs *regs) { + struct ia64_fpreg f6_11[6]; fp_state_t fp_state; fpswa_ret_t ret; -#define FPSWA_BUG -#ifdef FPSWA_BUG - struct ia64_fpreg f6_15[10]; -#endif if (!fpswa_interface) return -1; @@ -232,23 +229,12 @@ * kernel, so set those bits in the mask and set the low volatile * pointer to point to these registers. */ -#ifndef FPSWA_BUG - fp_state.bitmask_low64 = 0x3c0; /* bit 6..9 */ - fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) ®s->f6; -#else - fp_state.bitmask_low64 = 0xffc0; /* bit6..bit15 */ - f6_15[0] = regs->f6; - f6_15[1] = regs->f7; - f6_15[2] = regs->f8; - f6_15[3] = regs->f9; - __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_15[4])); - __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_15[5])); - __asm__ ("stf.spill %0=f12%P0" : "=m"(f6_15[6])); - __asm__ ("stf.spill %0=f13%P0" : "=m"(f6_15[7])); - __asm__ ("stf.spill %0=f14%P0" : "=m"(f6_15[8])); - __asm__ ("stf.spill %0=f15%P0" : "=m"(f6_15[9])); - fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_15; -#endif + fp_state.bitmask_low64 = 0xfc0; /* bit6..bit11 */ + f6_11[0] = regs->f6; f6_11[1] = regs->f7; + f6_11[2] = regs->f8; f6_11[3] = regs->f9; + __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_11[4])); + __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_11[5])); + fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_11; /* * unsigned long (*EFI_FPSWA) ( * unsigned long trap_type, @@ -264,18 +250,10 @@ (unsigned long *) ipsr, (unsigned long *) fpsr, (unsigned long *) isr, (unsigned long *) pr, (unsigned long *) ifs, &fp_state); -#ifdef FPSWA_BUG - __asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_15[4])); - __asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_15[5])); - __asm__ ("ldf.fill f12=%0%P0" :: "m"(f6_15[6])); - __asm__ ("ldf.fill f13=%0%P0" :: "m"(f6_15[7])); - __asm__ ("ldf.fill f14=%0%P0" :: "m"(f6_15[8])); - __asm__ ("ldf.fill f15=%0%P0" :: "m"(f6_15[9])); - regs->f6 = f6_15[0]; - regs->f7 = f6_15[1]; - regs->f8 = f6_15[2]; - regs->f9 = f6_15[3]; -#endif + regs->f6 = f6_11[0]; regs->f7 = f6_11[1]; + regs->f8 = f6_11[2]; regs->f9 = f6_11[3]; + __asm__ ("ldf.fill f10=%0%P0" :: "m"(f6_11[4])); + __asm__ ("ldf.fill f11=%0%P0" :: "m"(f6_11[5])); return ret.status; } @@ -321,7 +299,7 @@ } siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; - siginfo.si_code = 0; + siginfo.si_code = __SI_FAULT; /* default code */ siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); if (isr & 0x11) { siginfo.si_code = FPE_FLTINV; @@ -339,7 +317,7 @@ /* raise exception */ siginfo.si_signo = SIGFPE; siginfo.si_errno = 0; - siginfo.si_code = 0; + siginfo.si_code = __SI_FAULT; /* default code */ siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); if (isr & 0x880) { siginfo.si_code = FPE_FLTOVF; @@ -443,14 +421,12 @@ sprintf(buf, "General Exception: %s%s", reason[code], (code == 3) ? ((isr & (1UL << 37)) ? " (RSE access)" : " (data access)") : ""); -#ifndef CONFIG_ITANIUM_ASTEP_SPECIFIC if (code == 8) { # ifdef CONFIG_IA64_PRINT_HAZARDS printk("%016lx:possible hazard, pr = %016lx\n", regs->cr_iip, regs->pr); # endif return; } -#endif break; case 25: /* Disabled FP-Register */ diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/unaligned.c linux/arch/ia64/kernel/unaligned.c --- v2.4.7/linux/arch/ia64/kernel/unaligned.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/kernel/unaligned.c Tue Jul 31 10:30:08 2001 @@ -325,11 +325,11 @@ DPRINT("ubs_end=%p bsp=%p addr=%px\n", (void *) ubs_end, (void *) bsp, (void *) addr); - ia64_poke(current, (unsigned long) ubs_end, (unsigned long) addr, val); + ia64_poke(current, sw, (unsigned long) ubs_end, (unsigned long) addr, val); rnat_addr = ia64_rse_rnat_addr(addr); - ia64_peek(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats); + ia64_peek(current, sw, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats); DPRINT("rnat @%p = 0x%lx nat=%d old nat=%ld\n", (void *) rnat_addr, rnats, nat, (rnats >> ia64_rse_slot_num(addr)) & 1); @@ -338,7 +338,7 @@ rnats |= nat_mask; else rnats &= ~nat_mask; - ia64_poke(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, rnats); + ia64_poke(current, sw, (unsigned long) ubs_end, (unsigned long) rnat_addr, rnats); DPRINT("rnat changed to @%p = 0x%lx\n", (void *) rnat_addr, rnats); } @@ -394,7 +394,7 @@ DPRINT("ubs_end=%p bsp=%p addr=%p\n", (void *) ubs_end, (void *) bsp, (void *) addr); - ia64_peek(current, (unsigned long) ubs_end, (unsigned long) addr, val); + ia64_peek(current, sw, (unsigned long) ubs_end, (unsigned long) addr, val); if (nat) { rnat_addr = ia64_rse_rnat_addr(addr); @@ -402,7 +402,7 @@ DPRINT("rnat @%p = 0x%lx\n", (void *) rnat_addr, rnats); - ia64_peek(current, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats); + ia64_peek(current, sw, (unsigned long) ubs_end, (unsigned long) rnat_addr, &rnats); *nat = (rnats & nat_mask) != 0; } } @@ -1299,7 +1299,12 @@ len = sprintf(buf, "%s(%d): unaligned access to 0x%016lx, " "ip=0x%016lx\n\r", current->comm, current->pid, ifa, regs->cr_iip + ipsr->ri); - tty_write_message(current->tty, buf); + /* + * Don't call tty_write_message() if we're in the kernel; we might + * be holding locks... + */ + if (user_mode(regs)) + tty_write_message(current->tty, buf); buf[len-1] = '\0'; /* drop '\r' */ printk(KERN_WARNING "%s", buf); /* watch for command names containing %s */ } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/unwind.c linux/arch/ia64/kernel/unwind.c --- v2.4.7/linux/arch/ia64/kernel/unwind.c Thu Apr 12 12:16:35 2001 +++ linux/arch/ia64/kernel/unwind.c Tue Jul 31 10:30:08 2001 @@ -24,6 +24,7 @@ * o if both the unw.lock spinlock and a script's read-write lock must be * acquired, then the read-write lock must be acquired first. */ +#include #include #include #include @@ -36,6 +37,7 @@ #include #include #include +#include #include "entry.h" #include "unwind_i.h" @@ -97,6 +99,10 @@ /* unwind table for the kernel: */ struct unw_table kernel_table; + /* unwind table describing the gate page (kernel code that is mapped into user space): */ + size_t gate_table_size; + unsigned long *gate_table; + /* hash table that maps instruction pointer to script index: */ unsigned short hash[UNW_HASH_SIZE]; @@ -323,8 +329,13 @@ else *nat_addr &= ~nat_mask; } else { - *val = *addr; - *nat = (*nat_addr & nat_mask) != 0; + if ((*nat_addr & nat_mask) == 0) { + *val = *addr; + *nat = 0; + } else { + *val = 0; /* if register is a NaT, *addr may contain kernel data! */ + *nat = 1; + } } return 0; } @@ -1350,10 +1361,10 @@ } } -static inline struct unw_table_entry * +static inline const struct unw_table_entry * lookup (struct unw_table *table, unsigned long rel_ip) { - struct unw_table_entry *e = 0; + const struct unw_table_entry *e = 0; unsigned long lo, hi, mid; /* do a binary search for right entry: */ @@ -1378,7 +1389,7 @@ build_script (struct unw_frame_info *info) { struct unw_reg_state *rs, *next; - struct unw_table_entry *e = 0; + const struct unw_table_entry *e = 0; struct unw_script *script = 0; unsigned long ip = info->ip; struct unw_state_record sr; @@ -1836,9 +1847,9 @@ static void init_unwind_table (struct unw_table *table, const char *name, unsigned long segment_base, - unsigned long gp, void *table_start, void *table_end) + unsigned long gp, const void *table_start, const void *table_end) { - struct unw_table_entry *start = table_start, *end = table_end; + const struct unw_table_entry *start = table_start, *end = table_end; table->name = name; table->segment_base = segment_base; @@ -1851,9 +1862,9 @@ void * unw_add_unwind_table (const char *name, unsigned long segment_base, unsigned long gp, - void *table_start, void *table_end) + const void *table_start, const void *table_end) { - struct unw_table_entry *start = table_start, *end = table_end; + const struct unw_table_entry *start = table_start, *end = table_end; struct unw_table *table; unsigned long flags; @@ -1936,6 +1947,47 @@ } void +unw_create_gate_table (void) +{ + extern char __start_gate_section[], __stop_gate_section[]; + unsigned long *lp, start, end, segbase = unw.kernel_table.segment_base; + const struct unw_table_entry *entry, *first; + size_t info_size, size; + char *info; + + start = (unsigned long) __start_gate_section - segbase; + end = (unsigned long) __stop_gate_section - segbase; + size = 0; + first = lookup(&unw.kernel_table, start); + + for (entry = first; entry->start_offset < end; ++entry) + size += 3*8 + 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset)); + size += 8; /* reserve space for "end of table" marker */ + + unw.gate_table = alloc_bootmem(size); + if (!unw.gate_table) { + unw.gate_table_size = 0; + printk("unwind: unable to create unwind data for gate page!\n"); + return; + } + unw.gate_table_size = size; + + lp = unw.gate_table; + info = (char *) unw.gate_table + size; + + for (entry = first; entry->start_offset < end; ++entry, lp += 3) { + info_size = 8 + 8*UNW_LENGTH(*(u64 *) (segbase + entry->info_offset)); + info -= info_size; + memcpy(info, (char *) segbase + entry->info_offset, info_size); + + lp[0] = entry->start_offset - start + GATE_ADDR; /* start */ + lp[1] = entry->end_offset - start + GATE_ADDR; /* end */ + lp[2] = info - (char *) unw.gate_table; /* info */ + } + *lp = 0; /* end-of-table marker */ +} + +void unw_init (void) { extern int ia64_unw_start, ia64_unw_end, __gp; @@ -1973,4 +2025,35 @@ init_unwind_table(&unw.kernel_table, "kernel", KERNEL_START, (unsigned long) &__gp, &ia64_unw_start, &ia64_unw_end); +} + +/* + * This system call copies the unwind data into the buffer pointed to by BUF and returns + * the size of the unwind data. If BUF_SIZE is smaller than the size of the unwind data + * or if BUF is NULL, nothing is copied, but the system call still returns the size of the + * unwind data. + * + * The first portion of the unwind data contains an unwind table and rest contains the + * associated unwind info (in no particular order). The unwind table consists of a table + * of entries of the form: + * + * u64 start; (64-bit address of start of function) + * u64 end; (64-bit address of start of function) + * u64 info; (BUF-relative offset to unwind info) + * + * The end of the unwind table is indicated by an entry with a START address of zero. + * + * Please see the IA-64 Software Conventions and Runtime Architecture manual for details + * on the format of the unwind info. + * + * ERRORS + * EFAULT BUF points outside your accessible address space. + */ +asmlinkage long +sys_getunwind (void *buf, size_t buf_size) +{ + if (buf && buf_size >= unw.gate_table_size) + if (copy_to_user(buf, unw.gate_table, unw.gate_table_size) != 0) + return -EFAULT; + return unw.gate_table_size; } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/kernel/unwind_i.h linux/arch/ia64/kernel/unwind_i.h --- v2.4.7/linux/arch/ia64/kernel/unwind_i.h Mon Oct 9 17:54:56 2000 +++ linux/arch/ia64/kernel/unwind_i.h Tue Jul 31 10:30:08 2001 @@ -58,7 +58,7 @@ unsigned long segment_base; /* base for offsets in the unwind table entries */ unsigned long start; unsigned long end; - struct unw_table_entry *array; + const struct unw_table_entry *array; unsigned long length; }; diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/Makefile linux/arch/ia64/lib/Makefile --- v2.4.7/linux/arch/ia64/lib/Makefile Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/Makefile Tue Jul 31 10:30:08 2001 @@ -14,11 +14,7 @@ checksum.o clear_page.o csum_partial_copy.o copy_page.o \ copy_user.o clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o \ flush.o io.o do_csum.o \ - swiotlb.o - -ifneq ($(CONFIG_ITANIUM_ASTEP_SPECIFIC),y) - obj-y += memcpy.o memset.o strlen.o -endif + memcpy.o memset.o strlen.o swiotlb.o IGNORE_FLAGS_OBJS = __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/checksum.c linux/arch/ia64/lib/checksum.c --- v2.4.7/linux/arch/ia64/lib/checksum.c Sun Feb 6 18:42:40 2000 +++ linux/arch/ia64/lib/checksum.c Tue Jul 31 10:30:08 2001 @@ -9,7 +9,7 @@ * This file contains network checksum routines that are better done * in an architecture-specific manner due to speed.. */ - + #include #include @@ -55,8 +55,7 @@ ((unsigned long) ntohs(len) << 16) + ((unsigned long) proto << 8)); - /* Fold down to 32-bits so we don't loose in the typedef-less - network stack. */ + /* Fold down to 32-bits so we don't loose in the typedef-less network stack. */ /* 64 to 33 */ result = (result & 0xffffffff) + (result >> 32); /* 33 to 32 */ @@ -64,8 +63,7 @@ return result; } -extern unsigned long do_csum(const unsigned char *, unsigned int, unsigned int); -extern unsigned long do_csum_c(const unsigned char *, unsigned int, unsigned int); +extern unsigned long do_csum (const unsigned char *, long); /* * This is a version of ip_compute_csum() optimized for IP headers, @@ -73,7 +71,7 @@ */ unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) { - return ~do_csum(iph,ihl*4,0); + return ~do_csum(iph, ihl*4); } /* @@ -90,7 +88,7 @@ */ unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) { - unsigned long result = do_csum(buff, len, 0); + unsigned long result = do_csum(buff, len); /* add in old sum, and carry.. */ result += sum; @@ -106,5 +104,5 @@ */ unsigned short ip_compute_csum(unsigned char * buff, int len) { - return ~do_csum(buff,len, 0); + return ~do_csum(buff,len); } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/clear_page.S linux/arch/ia64/lib/clear_page.S --- v2.4.7/linux/arch/ia64/lib/clear_page.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/clear_page.S Tue Jul 31 10:30:08 2001 @@ -1,8 +1,6 @@ /* * - * Optimized version of the standard clearpage() function - * - * Based on comments from ddd. Try not to overflow the write buffer. + * Optimized function to clear a page of memory. * * Inputs: * in0: address of page @@ -13,27 +11,41 @@ * Copyright (C) 1999-2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian * Copyright (C) 1999-2001 David Mosberger-Tang + * + * 1/06/01 davidm Tuned for Itanium. */ #include #include +#define saved_lc r2 +#define dst0 in0 +#define dst1 r8 +#define dst2 r9 +#define dst3 r10 +#define dst_fetch r11 + GLOBAL_ENTRY(clear_page) .prologue - alloc r11=ar.pfs,1,0,0,0 - .save ar.lc, r16 - mov r16=ar.lc // slow - - .body - - mov r17=PAGE_SIZE/32-1 // -1 = repeat/until + .regstk 1,0,0,0 + mov r16 = PAGE_SIZE/64-1 // -1 = repeat/until ;; - adds r18=16,in0 - mov ar.lc=r17 + .save ar.lc, saved_lc + mov saved_lc = ar.lc + .body + mov ar.lc = r16 + adds dst1 = 16, dst0 + adds dst2 = 32, dst0 + adds dst3 = 48, dst0 + adds dst_fetch = 512, dst0 ;; -1: stf.spill.nta [in0]=f0,32 - stf.spill.nta [r18]=f0,32 +1: stf.spill.nta [dst0] = f0, 64 + stf.spill.nta [dst1] = f0, 64 + stf.spill.nta [dst2] = f0, 64 + stf.spill.nta [dst3] = f0, 64 + + lfetch [dst_fetch], 64 br.cloop.dptk.few 1b ;; - mov ar.lc=r16 // restore lc + mov ar.lc = r2 // restore lc br.ret.sptk.few rp END(clear_page) diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/clear_user.S linux/arch/ia64/lib/clear_user.S --- v2.4.7/linux/arch/ia64/lib/clear_user.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/clear_user.S Tue Jul 31 10:30:08 2001 @@ -69,7 +69,7 @@ (p6) br.cond.dptk.few long_do_clear ;; // WAR on ar.lc // - // worst case 16 cyles, avg 8 cycles + // worst case 16 iterations, avg 8 iterations // // We could have played with the predicates to use the extra // M slot for 2 stores/iteration but the cost the initialization diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/copy_page.S linux/arch/ia64/lib/copy_page.S --- v2.4.7/linux/arch/ia64/lib/copy_page.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/copy_page.S Tue Jul 31 10:30:08 2001 @@ -2,8 +2,6 @@ * * Optimized version of the standard copy_page() function * - * Based on comments from ddd. Try not to overflow write buffer. - * * Inputs: * in0: address of target page * in1: address of source page @@ -12,11 +10,14 @@ * * Copyright (C) 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian + * Copyright (C) 2001 David Mosberger + * + * 4/06/01 davidm Tuned to make it perform well both for cached and uncached copies. */ #include #include -#define PIPE_DEPTH 6 +#define PIPE_DEPTH 3 #define EPI p[PIPE_DEPTH-1] #define lcount r16 @@ -27,62 +28,67 @@ #define src2 r21 #define tgt1 r22 #define tgt2 r23 +#define srcf r24 +#define tgtf r25 + +#define Nrot ((8*PIPE_DEPTH+7)&~7) GLOBAL_ENTRY(copy_page) .prologue .save ar.pfs, saved_pfs - alloc saved_pfs=ar.pfs,3,((2*PIPE_DEPTH+7)&~7),0,((2*PIPE_DEPTH+7)&~7) + alloc saved_pfs=ar.pfs,3,Nrot-3,0,Nrot - .rotr t1[PIPE_DEPTH], t2[PIPE_DEPTH] + .rotr t1[PIPE_DEPTH], t2[PIPE_DEPTH], t3[PIPE_DEPTH], t4[PIPE_DEPTH], \ + t5[PIPE_DEPTH], t6[PIPE_DEPTH], t7[PIPE_DEPTH], t8[PIPE_DEPTH] .rotp p[PIPE_DEPTH] .save ar.lc, saved_lc - mov saved_lc=ar.lc // save ar.lc ahead of time + mov saved_lc=ar.lc + mov ar.ec=PIPE_DEPTH + + mov lcount=PAGE_SIZE/64-1 .save pr, saved_pr - mov saved_pr=pr // rotating predicates are preserved - // resgisters we must save. + mov saved_pr=pr + mov pr.rot=1<<16 + .body - mov src1=in1 // initialize 1st stream source - adds src2=8,in1 // initialize 2nd stream source - mov lcount=PAGE_SIZE/16-1 // as many 16bytes as there are on a page - // -1 is because br.ctop is repeat/until - - adds tgt2=8,in0 // initialize 2nd stream target - mov tgt1=in0 // initialize 1st stream target - ;; - mov pr.rot=1<<16 // pr16=1 & pr[17-63]=0 , 63 not modified - - mov ar.lc=lcount // set loop counter - mov ar.ec=PIPE_DEPTH // ar.ec must match pipeline depth - ;; - - // We need to preload the n-1 stages of the pipeline (n=depth). - // We do this during the "prolog" of the loop: we execute - // n-1 times the "load" bundle. Then both loads & stores are - // enabled until we reach the end of the last word of the page - // on the load side. Then, we enter the epilog (controlled by ec) - // where we just do the stores and no loads n times : drain the pipe - // (we exit the loop when ec=1). - // - // The initialization of the prolog is done via the predicate registers: - // the choice of EPI DEPENDS on the depth of the pipeline (n). - // When lc > 0 pr63=1 and it is fed back into pr16 and pr16-pr62 - // are then shifted right at every iteration, - // Thus by initializing pr16=1 and the rest to 0 before the loop - // we get EPI=1 after n iterations. - // -1: // engage loop now, let the magic happen... -(p16) ld8 t1[0]=[src1],16 // new data on top of pipeline in 1st stream -(p16) ld8 t2[0]=[src2],16 // new data on top of pipeline in 2nd stream - nop.i 0x0 -(EPI) st8 [tgt1]=t1[PIPE_DEPTH-1],16 // store top of 1st pipeline -(EPI) st8 [tgt2]=t2[PIPE_DEPTH-1],16 // store top of 2nd pipeline - br.ctop.dptk.few 1b // once lc==0, ec-- & p16=0 - // stores but no loads anymore + mov src1=in1 + adds src2=8,in1 + ;; + adds tgt2=8,in0 + add srcf=512,in1 + mov ar.lc=lcount + mov tgt1=in0 + add tgtf=512,in0 + ;; +1: +(p[0]) ld8 t1[0]=[src1],16 +(EPI) st8 [tgt1]=t1[PIPE_DEPTH-1],16 +(p[0]) ld8 t2[0]=[src2],16 +(EPI) st8 [tgt2]=t2[PIPE_DEPTH-1],16 + ;; +(p[0]) ld8 t3[0]=[src1],16 +(EPI) st8 [tgt1]=t3[PIPE_DEPTH-1],16 +(p[0]) ld8 t4[0]=[src2],16 +(EPI) st8 [tgt2]=t4[PIPE_DEPTH-1],16 + ;; +(p[0]) ld8 t5[0]=[src1],16 +(EPI) st8 [tgt1]=t5[PIPE_DEPTH-1],16 +(p[0]) ld8 t6[0]=[src2],16 +(EPI) st8 [tgt2]=t6[PIPE_DEPTH-1],16 + ;; +(p[0]) ld8 t7[0]=[src1],16 +(EPI) st8 [tgt1]=t7[PIPE_DEPTH-1],16 +(p[0]) ld8 t8[0]=[src2],16 +(EPI) st8 [tgt2]=t8[PIPE_DEPTH-1],16 + + lfetch [srcf], 64 + lfetch [tgtf], 64 + br.ctop.sptk.few 1b ;; mov pr=saved_pr,0xffffffffffff0000 // restore predicates - mov ar.pfs=saved_pfs // restore ar.ec - mov ar.lc=saved_lc // restore saved lc - br.ret.sptk.few rp // bye... + mov ar.pfs=saved_pfs + mov ar.lc=saved_lc + br.ret.sptk.few rp END(copy_page) diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/copy_user.S linux/arch/ia64/lib/copy_user.S --- v2.4.7/linux/arch/ia64/lib/copy_user.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/copy_user.S Tue Jul 31 10:30:08 2001 @@ -35,9 +35,9 @@ // Tuneable parameters // #define COPY_BREAK 16 // we do byte copy below (must be >=16) -#define PIPE_DEPTH 4 // pipe depth +#define PIPE_DEPTH 21 // pipe depth -#define EPI p[PIPE_DEPTH-1] // PASTE(p,16+PIPE_DEPTH-1) +#define EPI p[PIPE_DEPTH-1] // // arguments @@ -148,8 +148,8 @@ // // - // Optimization. If dst1 is 8-byte aligned (not rarely), we don't need - // to copy the head to dst1, to start 8-byte copy software pipleline. + // Optimization. If dst1 is 8-byte aligned (quite common), we don't need + // to copy the head to dst1, to start 8-byte copy software pipeline. // We know src1 is not 8-byte aligned in this case. // cmp.eq p14,p15=r0,dst2 @@ -233,15 +233,23 @@ #define SWITCH(pred, shift) cmp.eq pred,p0=shift,rshift #define CASE(pred, shift) \ (pred) br.cond.spnt.few copy_user_bit##shift -#define BODY(rshift) \ -copy_user_bit##rshift: \ -1: \ - EX(failure_out,(EPI) st8 [dst1]=tmp,8); \ -(EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift; \ - EX(failure_in2,(p16) ld8 val1[0]=[src1],8); \ - br.ctop.dptk.few 1b; \ - ;; \ - br.cond.spnt.few .diff_align_do_tail +#define BODY(rshift) \ +copy_user_bit##rshift: \ +1: \ + EX(failure_out,(EPI) st8 [dst1]=tmp,8); \ +(EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift; \ + EX(3f,(p16) ld8 val1[0]=[src1],8); \ + br.ctop.dptk.few 1b; \ + ;; \ + br.cond.sptk.few .diff_align_do_tail; \ +2: \ +(EPI) st8 [dst1]=tmp,8; \ +(EPI_1) shrp tmp=val1[PIPE_DEPTH-3],val1[PIPE_DEPTH-2],rshift; \ +3: \ +(p16) mov val1[0]=r0; \ + br.ctop.dptk.few 2b; \ + ;; \ + br.cond.sptk.few failure_in2 // // Since the instruction 'shrp' requires a fixed 128-bit value @@ -581,13 +589,7 @@ br.ret.dptk.few rp failure_in2: - sub ret0=endsrc,src1 // number of bytes to zero, i.e. not copied - ;; -3: -(p16) mov val1[0]=r0 -(EPI) st8 [dst1]=val1[PIPE_DEPTH-1],8 - br.ctop.dptk.few 3b - ;; + sub ret0=endsrc,src1 cmp.ne p6,p0=dst1,enddst // Do we need to finish the tail ? sub len=enddst,dst1,1 // precompute len (p6) br.cond.dptk.few failure_in1bis diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/csum_partial_copy.c linux/arch/ia64/lib/csum_partial_copy.c --- v2.4.7/linux/arch/ia64/lib/csum_partial_copy.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/csum_partial_copy.c Tue Jul 31 10:30:08 2001 @@ -101,7 +101,7 @@ * This is very ugly but temporary. THIS NEEDS SERIOUS ENHANCEMENTS. * But it's very tricky to get right even in C. */ -extern unsigned long do_csum(const unsigned char *, int); +extern unsigned long do_csum(const unsigned char *, long); static unsigned int do_csum_partial_copy_from_user (const char *src, char *dst, int len, diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/do_csum.S linux/arch/ia64/lib/do_csum.S --- v2.4.7/linux/arch/ia64/lib/do_csum.S Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/do_csum.S Tue Jul 31 10:30:08 2001 @@ -11,6 +11,12 @@ * Copyright (C) 1999, 2001 Hewlett-Packard Co * Copyright (C) 1999 Stephane Eranian * + * 01/04/18 Jun Nakajima + * Clean up and optimize and the software pipeline, loading two + * back-to-back 8-byte words per loop. Clean up the initialization + * for the loop. Support the cases where load latency = 1 or 2. + * Set CONFIG_IA64_LOAD_LATENCY to 1 or 2 (default). + * */ #include @@ -18,51 +24,54 @@ // // Theory of operations: // The goal is to go as quickly as possible to the point where -// we can checksum 8 bytes/loop. Before reaching that point we must +// we can checksum 16 bytes/loop. Before reaching that point we must // take care of incorrect alignment of first byte. // // The code hereafter also takes care of the "tail" part of the buffer // before entering the core loop, if any. The checksum is a sum so it -// allows us to commute operations. So we do do the "head" and "tail" +// allows us to commute operations. So we do the "head" and "tail" // first to finish at full speed in the body. Once we get the head and // tail values, we feed them into the pipeline, very handy initialization. // // Of course we deal with the special case where the whole buffer fits // into one 8 byte word. In this case we have only one entry in the pipeline. // -// We use a (3+1)-stage pipeline in the loop to account for possible -// load latency and also to accomodate for head and tail. +// We use a (LOAD_LATENCY+2)-stage pipeline in the loop to account for +// possible load latency and also to accomodate for head and tail. // // The end of the function deals with folding the checksum from 64bits // down to 16bits taking care of the carry. // // This version avoids synchronization in the core loop by also using a -// pipeline for the accumulation of the checksum in result[]. +// pipeline for the accumulation of the checksum in resultx[] (x=1,2). // -// p[] +// wordx[] (x=1,2) // |---| -// 0| | r32 : new value loaded in pipeline +// | | 0 : new value loaded in pipeline // |---| -// 1| | r33 : in transit data +// | | - : in transit data // |---| -// 2| | r34 : current value to add to checksum +// | | LOAD_LATENCY : current value to add to checksum // |---| -// 3| | r35 : previous value added to checksum (previous iteration) -// |---| +// | | LOAD_LATENCY+1 : previous value added to checksum +// |---| (previous iteration) // -// result[] +// resultx[] (x=1,2) // |---| -// 0| | r36 : new checksum +// | | 0 : initial value // |---| -// 1| | r37 : previous value of checksum +// | | LOAD_LATENCY-1 : new checksum // |---| -// 2| | r38 : final checksum when out of the loop (after 2 epilogue rots) +// | | LOAD_LATENCY : previous value of checksum // |---| +// | | LOAD_LATENCY+1 : final checksum when out of the loop +// |---| +// // +// See RFC1071 "Computing the Internet Checksum" for various techniques for +// calculating the Internet checksum. // // NOT YET DONE: -// - Take advantage of the MMI bandwidth to load more than 8byte per loop -// iteration // - use the lfetch instruction to augment the chances of the data being in // the cache when we need it. // - Maybe another algorithm which would take care of the folding at the @@ -71,14 +80,12 @@ // to figure out if we could not split the function depending on the // type of packet or alignment we get. Like the ip_fast_csum() routine // where we know we have at least 20bytes worth of data to checksum. -// - Look at RFCs about checksums to see whether or not we can do better -// // - Do a better job of handling small packets. -// + #define saved_pfs r11 #define hmask r16 #define tmask r17 -#define first r18 +#define first1 r18 #define firstval r19 #define firstoff r20 #define last r21 @@ -89,32 +96,47 @@ #define tmp1 r26 #define tmp2 r27 #define tmp3 r28 -#define carry r29 +#define carry1 r29 +#define carry2 r30 +#define first2 r31 #define buf in0 #define len in1 -// unsigned long do_csum(unsigned char *buf,int len) +#ifndef CONFIG_IA64_LOAD_LATENCY +#define CONFIG_IA64_LOAD_LATENCY 2 +#endif + +#define LOAD_LATENCY 2 // XXX fix me + +#if (LOAD_LATENCY != 1) && (LOAD_LATENCY != 2) +# error "Only 1 or 2 is supported/tested for LOAD_LATENCY." +#endif + +#define PIPE_DEPTH (LOAD_LATENCY+2) +#define ELD p[LOAD_LATENCY] // end of load +#define ELD_1 p[LOAD_LATENCY+1] // and next stage + +// unsigned long do_csum(unsigned char *buf,long len) GLOBAL_ENTRY(do_csum) .prologue .save ar.pfs, saved_pfs - alloc saved_pfs=ar.pfs,2,8,0,8 - - .rotr p[4], result[3] + alloc saved_pfs=ar.pfs,2,16,1,16 + .rotr word1[4], word2[4],result1[4],result2[4] + .rotp p[PIPE_DEPTH] mov ret0=r0 // in case we have zero length - cmp4.lt p0,p6=r0,len // check for zero length or negative (32bit len) + cmp.lt p0,p6=r0,len // check for zero length or negative (32bit len) ;; // avoid WAW on CFM mov tmp3=0x7 // a temporary mask/value add tmp1=buf,len // last byte's address (p6) br.ret.spnt.few rp // return if true (hope we can avoid that) - and firstoff=7,buf // how many bytes off for first element - tbit.nz p10,p0=buf,0 // is buf an odd address ? + and firstoff=7,buf // how many bytes off for first1 element + tbit.nz p15,p0=buf,0 // is buf an odd address ? mov hmask=-1 // intialize head mask ;; - - andcm first=buf,tmp3 // 8byte aligned down address of first element + andcm first1=buf,tmp3 // 8byte aligned down address of first1 element mov tmask=-1 // initialize tail mask adds tmp2=-1,tmp1 // last-1 ;; @@ -123,75 +145,125 @@ .save pr, saved_pr mov saved_pr=pr // preserve predicates (rotation) ;; - sub tmp3=last,first // tmp3=distance from first to last - cmp.eq p8,p9=last,first // everything fits in one word ? + sub tmp3=last,first1 // tmp3=distance from first1 to last + cmp.eq p8,p9=last,first1 // everything fits in one word ? sub tmp1=8,lastoff // complement to lastoff - - ld8 firstval=[first],8 // load,ahead of time, "first" word + ld8 firstval=[first1],8 // load,ahead of time, "first1" word shl tmp2=firstoff,3 // number of bits ;; and tmp1=7, tmp1 // make sure that if tmp1==8 -> tmp1=0 - (p9) ld8 lastval=[last] // load,ahead of time, "last" word, if needed -(p8) mov lastval=r0 // we don't need lastval if first==last - mov result[1]=r0 // initialize result +(p9) adds tmp3=-8,tmp3 // effectively loaded ;; - +(p8) mov lastval=r0 // we don't need lastval if first1==last shl tmp1=tmp1,3 // number of bits - shl hmask=hmask,tmp2 // build head mask, mask off [0,firstoff[ + shl hmask=hmask,tmp2 // build head mask, mask off [0,first1off[ ;; shr.u tmask=tmask,tmp1 // build tail mask, mask off ]8,lastoff] .save ar.lc, saved_lc mov saved_lc=ar.lc // save lc ;; - .body +#define count tmp3 (p8) and hmask=hmask,tmask // apply tail mask to head mask if 1 word only -(p9) and p[1]=lastval,tmask // mask last it as appropriate - shr.u tmp3=tmp3,3 // we do 8 bytes per loop +(p9) and word2[0]=lastval,tmask // mask last it as appropriate + shr.u count=count,3 // we do 8 bytes per loop (count) ;; - cmp.lt p6,p7=2,tmp3 // tmp3 > 2 ? - and p[2]=firstval,hmask // and mask it as appropriate - add tmp1=-2,tmp3 // -2 = -1 (br.ctop) -1 (last-first) + // If count is odd, finish this 8-byte word so that we can + // load two back-to-back 8-byte words per loop thereafter. + tbit.nz p10,p11=count,0 // if (count is odd) + and word1[0]=firstval,hmask // and mask it as appropriate + ;; +(p8) mov result1[0]=word1[0] +(p9) add result1[0]=word1[0],word2[0] + ;; + cmp.ltu p6,p0=result1[0],word1[0] // check the carry + ;; +(p6) adds result1[0]=1,result1[0] +(p8) br.cond.dptk.few do_csum_exit // if (within an 8-byte word) + ;; +(p11) br.cond.dptk.few do_csum16 // if (count is even) + ;; + // Here count is odd. + ld8 word1[1]=[first1],8 // load an 8-byte word + cmp.eq p9,p10=1,count // if (count == 1) + adds count=-1,count // loaded an 8-byte word + ;; + add result1[0]=result1[0],word1[1] + ;; + cmp.ltu p6,p0=result1[0],word1[1] + ;; +(p6) adds result1[0]=1,result1[0] + ;; +(p9) br.cond.sptk.few do_csum_exit // if (count == 1) exit + // Fall through to caluculate the checksum, feeding result1[0] as + // the initial value in result1[0]. ;; - // XXX Fixme: not very nice initialization here - // - // Setup loop control registers: // - // tmp3=0 (1 word) : lc=0, ec=2, p16=F - // tmp3=1 (2 words) : lc=0, ec=3, p16=F - // tmp3=2 (3 words) : lc=0, ec=4, p16=T - // tmp3>2 (4 or more): lc=tmp3-2, ec=4, p16=T + // Calculate the checksum loading two 8-byte words per loop. // - cmp.eq p8,p9=r0,tmp3 // tmp3 == 0 ? -(p6) mov ar.lc=tmp1 -(p7) mov ar.lc=0 - ;; - cmp.lt p6,p7=1,tmp3 // tmp3 > 1 ? -(p8) mov ar.ec=2 // we need the extra rotation on result[] -(p9) mov ar.ec=3 // hard not to set it twice sometimes - ;; - mov carry=r0 // initialize carry -(p6) mov ar.ec=4 -(p6) mov pr.rot=0xffffffffffff0000 // p16=T, p18=T - - cmp.ne p8,p0=r0,r0 // p8 is false - mov p[3]=r0 // make sure first compare fails -(p7) mov pr.rot=0xfffffffffffe0000 // p16=F, p18=T +do_csum16: + mov saved_lc=ar.lc + shr.u count=count,1 // we do 16 bytes per loop + ;; + cmp.eq p9,p10=r0,count // if (count == 0) + brp.loop.imp 1f,2f + ;; + adds count=-1,count + mov ar.ec=PIPE_DEPTH + ;; + mov ar.lc=count // set lc + ;; + // result1[0] must be initialized in advance. + mov result2[0]=r0 ;; + mov pr.rot=1<<16 + ;; + mov carry1=r0 + mov carry2=r0 + ;; + add first2=8,first1 + ;; +(p9) br.cond.sptk.few do_csum_exit + ;; + nop.m 0 + nop.i 0 + ;; + .align 32 1: -(p16) ld8 p[0]=[first],8 // load next -(p8) adds carry=1,carry // add carry on prev_prev_value -(p18) add result[0]=result[1],p[2] // new_res = prev_res + cur_val - cmp.ltu p8,p0=result[1],p[3] // p8= prev_result < prev_val - br.ctop.dptk.few 1b // loop until lc--==0 - ;; // RAW on carry when loop exits - (p8) adds carry=1,carry;; // correct for carry on prev_value - add result[2]=carry,result[2];; // add carry to final result - cmp.ltu p6,p7=result[2], carry // check for new carry +(ELD_1) cmp.ltu p31,p0=result1[LOAD_LATENCY],word1[LOAD_LATENCY+1] +(p32) adds carry1=1,carry1 +(ELD_1) cmp.ltu p47,p0=result2[LOAD_LATENCY],word2[LOAD_LATENCY+1] +(p48) adds carry2=1,carry2 +(ELD) add result1[LOAD_LATENCY-1]=result1[LOAD_LATENCY],word1[LOAD_LATENCY] +(ELD) add result2[LOAD_LATENCY-1]=result2[LOAD_LATENCY],word2[LOAD_LATENCY] +2: +(p16) ld8 word1[0]=[first1],16 +(p16) ld8 word2[0]=[first2],16 + br.ctop.sptk.few 1b + ;; + // Since len is a 32-bit value, carry cannot be larger than + // a 64-bit value. +(p32) adds carry1=1,carry1 // since we miss the last one +(p48) adds carry2=1,carry2 + ;; + add result1[LOAD_LATENCY+1]=result1[LOAD_LATENCY+1],carry1 + add result2[LOAD_LATENCY+1]=result2[LOAD_LATENCY+1],carry2 + ;; + cmp.ltu p6,p0=result1[LOAD_LATENCY+1],carry1 + cmp.ltu p7,p0=result2[LOAD_LATENCY+1],carry2 + ;; +(p6) adds result1[LOAD_LATENCY+1]=1,result1[LOAD_LATENCY+1] +(p7) adds result2[LOAD_LATENCY+1]=1,result2[LOAD_LATENCY+1] ;; -(p6) adds result[2]=1,result[1] // correct if required + add result1[0]=result1[LOAD_LATENCY+1],result2[LOAD_LATENCY+1] + ;; + cmp.ltu p6,p0=result1[0],result2[LOAD_LATENCY+1] + ;; +(p6) adds result1[0]=1,result1[0] + ;; +do_csum_exit: movl tmp3=0xffffffff ;; // XXX Fixme @@ -199,33 +271,66 @@ // now fold 64 into 16 bits taking care of carry // that's not very good because it has lots of sequentiality // - and tmp1=result[2],tmp3 - shr.u tmp2=result[2],32 + and tmp1=result1[0],tmp3 + shr.u tmp2=result1[0],32 ;; - add result[2]=tmp1,tmp2 + add result1[0]=tmp1,tmp2 shr.u tmp3=tmp3,16 ;; - and tmp1=result[2],tmp3 - shr.u tmp2=result[2],16 + and tmp1=result1[0],tmp3 + shr.u tmp2=result1[0],16 ;; - add result[2]=tmp1,tmp2 + add result1[0]=tmp1,tmp2 ;; - and tmp1=result[2],tmp3 - shr.u tmp2=result[2],16 + and tmp1=result1[0],tmp3 + shr.u tmp2=result1[0],16 ;; - add result[2]=tmp1,tmp2 + add result1[0]=tmp1,tmp2 ;; - and tmp1=result[2],tmp3 - shr.u tmp2=result[2],16 + and tmp1=result1[0],tmp3 + shr.u tmp2=result1[0],16 ;; add ret0=tmp1,tmp2 mov pr=saved_pr,0xffffffffffff0000 ;; // if buf was odd then swap bytes mov ar.pfs=saved_pfs // restore ar.ec -(p10) mux1 ret0=ret0,@rev // reverse word +(p15) mux1 ret0=ret0,@rev // reverse word ;; mov ar.lc=saved_lc -(p10) shr.u ret0=ret0,64-16 // + shift back to position = swap bytes +(p15) shr.u ret0=ret0,64-16 // + shift back to position = swap bytes br.ret.sptk.few rp + +// I (Jun Nakajima) wrote an equivalent code (see below), but it was +// not much better than the original. So keep the original there so that +// someone else can challenge. +// +// shr.u word1[0]=result1[0],32 +// zxt4 result1[0]=result1[0] +// ;; +// add result1[0]=result1[0],word1[0] +// ;; +// zxt2 result2[0]=result1[0] +// extr.u word1[0]=result1[0],16,16 +// shr.u carry1=result1[0],32 +// ;; +// add result2[0]=result2[0],word1[0] +// ;; +// add result2[0]=result2[0],carry1 +// ;; +// extr.u ret0=result2[0],16,16 +// ;; +// add ret0=ret0,result2[0] +// ;; +// zxt2 ret0=ret0 +// mov ar.pfs=saved_pfs // restore ar.ec +// mov pr=saved_pr,0xffffffffffff0000 +// ;; +// // if buf was odd then swap bytes +// mov ar.lc=saved_lc +//(p15) mux1 ret0=ret0,@rev // reverse word +// ;; +//(p15) shr.u ret0=ret0,64-16 // + shift back to position = swap bytes +// br.ret.sptk.few rp + END(do_csum) diff -u --recursive --new-file v2.4.7/linux/arch/ia64/lib/swiotlb.c linux/arch/ia64/lib/swiotlb.c --- v2.4.7/linux/arch/ia64/lib/swiotlb.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/lib/swiotlb.c Tue Jul 31 10:30:08 2001 @@ -263,7 +263,7 @@ memset(ret, 0, size); pci_addr = virt_to_phys(ret); - if ((pci_addr & ~hwdev->dma_mask) != 0) + if (hwdev && (pci_addr & ~hwdev->dma_mask) != 0) panic("swiotlb_alloc_consistent: allocated memory is out of range for PCI device"); *dma_handle = pci_addr; return ret; diff -u --recursive --new-file v2.4.7/linux/arch/ia64/mm/extable.c linux/arch/ia64/mm/extable.c --- v2.4.7/linux/arch/ia64/mm/extable.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/mm/extable.c Tue Jul 31 10:30:08 2001 @@ -6,8 +6,9 @@ */ #include -#include + #include +#include extern const struct exception_table_entry __start___ex_table[]; extern const struct exception_table_entry __stop___ex_table[]; @@ -15,35 +16,25 @@ static inline const struct exception_table_entry * search_one_table (const struct exception_table_entry *first, const struct exception_table_entry *last, - signed long value) + unsigned long ip, unsigned long gp) { - /* Abort early if the search value is out of range. */ - if (value != (signed int)value) - return 0; - while (first <= last) { const struct exception_table_entry *mid; long diff; - /* - * We know that first and last are both kernel virtual - * pointers (region 7) so first+last will cause an - * overflow. We fix that by calling __va() on the - * result, which will ensure that the top two bits get - * set again. - */ - mid = (void *) __va((((__u64) first + (__u64) last)/2/sizeof(*mid))*sizeof(*mid)); - diff = mid->addr - value; + + mid = &first[(last - first)/2]; + diff = (mid->addr + gp) - ip; if (diff == 0) return mid; else if (diff < 0) - first = mid+1; + first = mid + 1; else - last = mid-1; + last = mid - 1; } return 0; } -#ifndef CONFIG_MODULE +#ifndef CONFIG_MODULES register unsigned long main_gp __asm__("gp"); #endif @@ -53,23 +44,25 @@ const struct exception_table_entry *entry; struct exception_fixup fix = { 0 }; -#ifndef CONFIG_MODULE +#ifndef CONFIG_MODULES /* There is only the kernel to search. */ - entry = search_one_table(__start___ex_table, __stop___ex_table - 1, addr - main_gp); + entry = search_one_table(__start___ex_table, __stop___ex_table - 1, addr, main_gp); if (entry) fix.cont = entry->cont + main_gp; return fix; #else - struct exception_table_entry *ret; - /* The kernel is the last "module" -- no need to treat it special. */ + struct archdata *archdata; struct module *mp; + /* The kernel is the last "module" -- no need to treat it special. */ for (mp = module_list; mp ; mp = mp->next) { if (!mp->ex_table_start) continue; - entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, addr - mp->gp); + archdata = (struct archdata *) mp->archdata_start; + entry = search_one_table(mp->ex_table_start, mp->ex_table_end - 1, + addr, (unsigned long) archdata->gp); if (entry) { - fix.cont = entry->cont + mp->gp; + fix.cont = entry->cont + (unsigned long) archdata->gp; return fix; } } diff -u --recursive --new-file v2.4.7/linux/arch/ia64/mm/init.c linux/arch/ia64/mm/init.c --- v2.4.7/linux/arch/ia64/mm/init.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/mm/init.c Tue Jul 31 10:30:08 2001 @@ -42,7 +42,7 @@ if (pgtable_cache_size > high) { do { if (pgd_quicklist) - free_page((unsigned long)pgd_alloc_one_fast()), ++freed; + free_page((unsigned long)pgd_alloc_one_fast(0)), ++freed; if (pmd_quicklist) free_page((unsigned long)pmd_alloc_one_fast(0, 0)), ++freed; if (pte_quicklist) @@ -111,7 +111,7 @@ * * To avoid freeing/using the wrong page (kernel sized) we: * - align up the beginning of initrd - * - keep the end untouched + * - align down the end of initrd * * | | * |=============| a000 @@ -135,11 +135,14 @@ * initrd_start and keep initrd_end as is. */ start = PAGE_ALIGN(start); + end = end & PAGE_MASK; if (start < end) printk ("Freeing initrd memory: %ldkB freed\n", (end - start) >> 10); for (; start < end; start += PAGE_SIZE) { + if (!VALID_PAGE(virt_to_page(start))) + continue; clear_bit(PG_reserved, &virt_to_page(start)->flags); set_page_count(virt_to_page(start), 1); free_page(start); @@ -225,7 +228,7 @@ } void __init -ia64_mmu_init (void) +ia64_mmu_init (void *my_cpu_data) { unsigned long flags, rid, pta, impl_va_bits; extern void __init tlb_init (void); @@ -242,7 +245,7 @@ ia64_clear_ic(flags); rid = ia64_rid(IA64_REGION_ID_KERNEL, __IA64_UNCACHED_OFFSET); - ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (_PAGE_SIZE_64M << 2)); + ia64_set_rr(__IA64_UNCACHED_OFFSET, (rid << 8) | (KERNEL_PG_SHIFT << 2)); rid = ia64_rid(IA64_REGION_ID_KERNEL, VMALLOC_START); ia64_set_rr(VMALLOC_START, (rid << 8) | (PAGE_SHIFT << 2) | 1); @@ -251,8 +254,7 @@ ia64_srlz_d(); ia64_itr(0x2, IA64_TR_PERCPU_DATA, PERCPU_ADDR, - pte_val(mk_pte_phys(__pa(&cpu_data[smp_processor_id()]), PAGE_KERNEL)), - PAGE_SHIFT); + pte_val(mk_pte_phys(__pa(my_cpu_data), PAGE_KERNEL)), PAGE_SHIFT); __restore_flags(flags); ia64_srlz_i(); @@ -354,6 +356,7 @@ { extern char __start_gate_section[]; long reserved_pages, codesize, datasize, initsize; + unsigned long num_pgt_pages; #ifdef CONFIG_PCI /* @@ -386,6 +389,19 @@ (unsigned long) nr_free_pages() << (PAGE_SHIFT - 10), max_mapnr << (PAGE_SHIFT - 10), codesize >> 10, reserved_pages << (PAGE_SHIFT - 10), datasize >> 10, initsize >> 10); + + /* + * Allow for enough (cached) page table pages so that we can map the entire memory + * at least once. Each task also needs a couple of page tables pages, so add in a + * fudge factor for that (don't use "threads-max" here; that would be wrong!). + * Don't allow the cache to be more than 10% of total memory, though. + */ +# define NUM_TASKS 500 /* typical number of tasks */ + num_pgt_pages = nr_free_pages() / PTRS_PER_PGD + NUM_TASKS; + if (num_pgt_pages > nr_free_pages() / 10) + num_pgt_pages = nr_free_pages() / 10; + if (num_pgt_pages > pgt_cache_water[1]) + pgt_cache_water[1] = num_pgt_pages; /* install the gate page in the global page table: */ put_gate_page(virt_to_page(__start_gate_section), GATE_ADDR); diff -u --recursive --new-file v2.4.7/linux/arch/ia64/mm/tlb.c linux/arch/ia64/mm/tlb.c --- v2.4.7/linux/arch/ia64/mm/tlb.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/mm/tlb.c Tue Jul 31 10:30:08 2001 @@ -97,7 +97,7 @@ /* * Wait for other CPUs to finish purging entries. */ -#if defined(CONFIG_ITANIUM_ASTEP_SPECIFIC) || defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) +#if defined(CONFIG_ITANIUM_BSTEP_SPECIFIC) { extern void smp_resend_flush_tlb (void); unsigned long start = ia64_get_itc(); diff -u --recursive --new-file v2.4.7/linux/arch/ia64/sn/fprom/fw-emu.c linux/arch/ia64/sn/fprom/fw-emu.c --- v2.4.7/linux/arch/ia64/sn/fprom/fw-emu.c Thu Apr 12 12:16:35 2001 +++ linux/arch/ia64/sn/fprom/fw-emu.c Tue Jul 31 10:30:09 2001 @@ -8,7 +8,6 @@ * Copyright (C) 2000 Silicon Graphics, Inc. * Copyright (C) 2000 by Jack Steiner (steiner@sgi.com) */ - #include #include #include diff -u --recursive --new-file v2.4.7/linux/arch/ia64/sn/io/ml_SN_intr.c linux/arch/ia64/sn/io/ml_SN_intr.c --- v2.4.7/linux/arch/ia64/sn/io/ml_SN_intr.c Thu Apr 12 12:16:35 2001 +++ linux/arch/ia64/sn/io/ml_SN_intr.c Tue Jul 31 10:30:09 2001 @@ -36,7 +36,6 @@ #include #include - #if DEBUG_INTR_TSTAMP_DEBUG #include #include diff -u --recursive --new-file v2.4.7/linux/arch/ia64/tools/print_offsets.c linux/arch/ia64/tools/print_offsets.c --- v2.4.7/linux/arch/ia64/tools/print_offsets.c Thu Apr 5 12:51:47 2001 +++ linux/arch/ia64/tools/print_offsets.c Tue Jul 31 10:30:09 2001 @@ -21,6 +21,8 @@ #include #include +#include "../kernel/sigframe.h" + #ifdef offsetof # undef offsetof #endif @@ -46,6 +48,7 @@ { "IA64_SWITCH_STACK_SIZE", sizeof (struct switch_stack) }, { "IA64_SIGINFO_SIZE", sizeof (struct siginfo) }, { "IA64_CPU_SIZE", sizeof (struct cpuinfo_ia64) }, + { "SIGFRAME_SIZE", sizeof (struct sigframe) }, { "UNW_FRAME_INFO_SIZE", sizeof (struct unw_frame_info) }, { "", 0 }, /* spacer */ { "IA64_TASK_PTRACE_OFFSET", offsetof (struct task_struct, ptrace) }, @@ -153,16 +156,25 @@ { "IA64_SWITCH_STACK_AR_BSPSTORE_OFFSET", offsetof (struct switch_stack, ar_bspstore) }, { "IA64_SWITCH_STACK_PR_OFFSET", offsetof (struct switch_stack, pr) }, { "IA64_SIGCONTEXT_AR_BSP_OFFSET", offsetof (struct sigcontext, sc_ar_bsp) }, + { "IA64_SIGCONTEXT_AR_FPSR_OFFSET", offsetof (struct sigcontext, sc_ar_fpsr) }, { "IA64_SIGCONTEXT_AR_RNAT_OFFSET", offsetof (struct sigcontext, sc_ar_rnat) }, - { "IA64_SIGCONTEXT_FLAGS_OFFSET", offsetof (struct sigcontext, sc_flags) }, + { "IA64_SIGCONTEXT_AR_UNAT_OFFSET", offsetof (struct sigcontext, sc_ar_unat) }, + { "IA64_SIGCONTEXT_B0_OFFSET", offsetof (struct sigcontext, sc_br[0]) }, { "IA64_SIGCONTEXT_CFM_OFFSET", offsetof (struct sigcontext, sc_cfm) }, + { "IA64_SIGCONTEXT_FLAGS_OFFSET", offsetof (struct sigcontext, sc_flags) }, { "IA64_SIGCONTEXT_FR6_OFFSET", offsetof (struct sigcontext, sc_fr[6]) }, + { "IA64_SIGCONTEXT_PR_OFFSET", offsetof (struct sigcontext, sc_pr) }, + { "IA64_SIGCONTEXT_R12_OFFSET", offsetof (struct sigcontext, sc_gr[12]) }, + { "IA64_SIGFRAME_ARG0_OFFSET", offsetof (struct sigframe, arg0) }, + { "IA64_SIGFRAME_ARG1_OFFSET", offsetof (struct sigframe, arg1) }, + { "IA64_SIGFRAME_ARG2_OFFSET", offsetof (struct sigframe, arg2) }, + { "IA64_SIGFRAME_RBS_BASE_OFFSET", offsetof (struct sigframe, rbs_base) }, + { "IA64_SIGFRAME_HANDLER_OFFSET", offsetof (struct sigframe, handler) }, + { "IA64_SIGFRAME_SIGCONTEXT_OFFSET", offsetof (struct sigframe, sc) }, { "IA64_CLONE_VFORK", CLONE_VFORK }, { "IA64_CLONE_VM", CLONE_VM }, { "IA64_CPU_IRQ_COUNT_OFFSET", offsetof (struct cpuinfo_ia64, irq_stat.f.irq_count) }, { "IA64_CPU_BH_COUNT_OFFSET", offsetof (struct cpuinfo_ia64, irq_stat.f.bh_count) }, - { "IA64_CPU_SOFTIRQ_ACTIVE_OFFSET", offsetof (struct cpuinfo_ia64, softirq.active) }, - { "IA64_CPU_SOFTIRQ_MASK_OFFSET", offsetof (struct cpuinfo_ia64, softirq.mask) }, { "IA64_CPU_PHYS_STACKED_SIZE_P8_OFFSET", offsetof (struct cpuinfo_ia64, phys_stacked_size_p8) }, }; diff -u --recursive --new-file v2.4.7/linux/arch/ia64/vmlinux.lds.S linux/arch/ia64/vmlinux.lds.S --- v2.4.7/linux/arch/ia64/vmlinux.lds.S Tue Jul 3 17:08:18 2001 +++ linux/arch/ia64/vmlinux.lds.S Tue Jul 31 10:30:09 2001 @@ -25,7 +25,7 @@ .text : AT(ADDR(.text) - PAGE_OFFSET) { *(.text.ivt) - /* these are not really text pages, but the zero page needs to be in a fixed location: */ + /* these are not really text pages, but they need to be page aligned: */ *(__special_page_section) __start_gate_section = .; *(.text.gate) @@ -74,9 +74,9 @@ __stop___kallsyms = .; /* Unwind info & table: */ + . = ALIGN(8); .IA_64.unwind_info : AT(ADDR(.IA_64.unwind_info) - PAGE_OFFSET) { *(.IA_64.unwind_info*) } - . = ALIGN(8); ia64_unw_start = .; .IA_64.unwind : AT(ADDR(.IA_64.unwind) - PAGE_OFFSET) { *(.IA_64.unwind*) } diff -u --recursive --new-file v2.4.7/linux/arch/parisc/hpux/sys_hpux.c linux/arch/parisc/hpux/sys_hpux.c --- v2.4.7/linux/arch/parisc/hpux/sys_hpux.c Tue Dec 5 12:29:39 2000 +++ linux/arch/parisc/hpux/sys_hpux.c Thu Aug 9 16:41:36 2001 @@ -109,9 +109,11 @@ lock_kernel(); s = get_super(to_kdev_t(dev)); + unlock_kernel(); if (s == NULL) goto out; err = vfs_statfs(s, &sbuf); + drop_super(s); if (err) goto out; @@ -124,7 +126,6 @@ /* Changed to hpux_ustat: */ err = copy_to_user(ubuf,&tmp,sizeof(struct hpux_ustat)) ? -EFAULT : 0; out: - unlock_kernel(); return err; } diff -u --recursive --new-file v2.4.7/linux/arch/ppc/kernel/misc.S linux/arch/ppc/kernel/misc.S --- v2.4.7/linux/arch/ppc/kernel/misc.S Wed Jul 25 17:10:18 2001 +++ linux/arch/ppc/kernel/misc.S Wed Jul 25 14:12:01 2001 @@ -813,7 +813,7 @@ _GLOBAL(_set_HID0) sync mtspr HID0, r3 - SYNC /* Handle erratas in some cases */ + SYNC /* Handle errata in some cases */ blr _GLOBAL(_get_ICTC) diff -u --recursive --new-file v2.4.7/linux/arch/s390/Makefile linux/arch/s390/Makefile --- v2.4.7/linux/arch/s390/Makefile Wed Apr 11 19:02:27 2001 +++ linux/arch/s390/Makefile Wed Jul 25 14:12:01 2001 @@ -17,7 +17,11 @@ CPP=$(CC) -E OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S LDFLAGS=-e start +ifeq ($(CONFIG_SHARED_KERNEL),y) +LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux-shared.lds $(LDFLAGS) +else LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux.lds $(LDFLAGS) +endif CFLAGS_PIPE := -pipe CFLAGS_NSR := -fno-strength-reduce @@ -27,8 +31,8 @@ SUBDIRS := $(SUBDIRS) arch/s390/mm arch/s390/kernel arch/s390/lib \ drivers/s390 arch/s390/math-emu -CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES) \ - drivers/s390/io.o +CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES) +DRIVERS := $(DRIVERS) drivers/s390/io.o LIBS := $(TOPDIR)/arch/s390/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390/lib/lib.a ifeq ($(CONFIG_MATHEMU),y) diff -u --recursive --new-file v2.4.7/linux/arch/s390/boot/Makefile linux/arch/s390/boot/Makefile --- v2.4.7/linux/arch/s390/boot/Makefile Wed Apr 11 19:02:27 2001 +++ linux/arch/s390/boot/Makefile Wed Jul 25 14:12:01 2001 @@ -1,5 +1,5 @@ # -# Makefile for the linux s390-specific parts of the memory manager. +# arch/s390/boot/Makefile # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here diff -u --recursive --new-file v2.4.7/linux/arch/s390/config.in linux/arch/s390/config.in --- v2.4.7/linux/arch/s390/config.in Tue Apr 17 17:19:25 2001 +++ linux/arch/s390/config.in Wed Jul 25 14:12:01 2001 @@ -50,6 +50,8 @@ tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG +bool 'Pseudo page fault support' CONFIG_PFAULT +bool 'VM shared kernel support' CONFIG_SHARED_KERNEL endmenu source drivers/s390/Config.in diff -u --recursive --new-file v2.4.7/linux/arch/s390/defconfig linux/arch/s390/defconfig --- v2.4.7/linux/arch/s390/defconfig Wed Apr 11 19:02:27 2001 +++ linux/arch/s390/defconfig Wed Jul 25 14:12:01 2001 @@ -5,6 +5,8 @@ # CONFIG_EISA is not set # CONFIG_MCA is not set CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set CONFIG_ARCH_S390=y # @@ -40,6 +42,8 @@ CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_PROCESS_DEBUG is not set +CONFIG_PFAULT=y +# CONFIG_SHARED_KERNEL is not set # # Block device drivers @@ -79,10 +83,13 @@ # # S/390 character device drivers # -CONFIG_3215=y -CONFIG_3215_CONSOLE=y +CONFIG_TN3270=y +CONFIG_TN3270_CONSOLE=y +CONFIG_TN3215=y +CONFIG_TN3215_CONSOLE=y CONFIG_HWC=y CONFIG_HWC_CONSOLE=y +CONFIG_HWC_CPI=m CONFIG_S390_TAPE=m # @@ -102,6 +109,9 @@ # CONFIG_NETDEVICES=y # CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set CONFIG_NET_ETHERNET=y CONFIG_TR=y # CONFIG_FDDI is not set @@ -109,7 +119,8 @@ # # S/390 network device drivers # -# CONFIG_CHANDEV is not set +CONFIG_CHANDEV=y +CONFIG_HOTPLUG=y CONFIG_CTC=m CONFIG_IUCV=m @@ -133,7 +144,8 @@ # CONFIG_IP_MROUTE is not set # CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set -# CONFIG_IPV6 is not set +CONFIG_IPV6=m +# CONFIG_IPV6_NETLINK is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set @@ -178,16 +190,18 @@ # CONFIG_EFS_FS is not set # CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set # CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set # CONFIG_NTFS_FS is not set # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y -# CONFIG_DEVFS_FS is not set -# CONFIG_DEVFS_MOUNT is not set +CONFIG_DEVFS_FS=y +CONFIG_DEVFS_MOUNT=y # CONFIG_DEVFS_DEBUG is not set # CONFIG_DEVPTS_FS is not set # CONFIG_QNX4FS_FS is not set @@ -195,7 +209,6 @@ # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set -# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set # CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set @@ -243,4 +256,4 @@ # # Kernel hacking # -# CONFIG_MAGIC_SYSRQ is not set +CONFIG_MAGIC_SYSRQ=y diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/debug.c linux/arch/s390/kernel/debug.c --- v2.4.7/linux/arch/s390/kernel/debug.c Wed Apr 11 19:02:27 2001 +++ linux/arch/s390/kernel/debug.c Wed Jul 25 14:12:01 2001 @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S --- v2.4.7/linux/arch/s390/kernel/entry.S Wed Jul 25 17:10:18 2001 +++ linux/arch/s390/kernel/entry.S Wed Jul 25 14:12:01 2001 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -200,8 +201,10 @@ # # check, if bottom-half has to be done # - l %r0,__LC_IRQ_STAT # get softirq_active - n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask + l %r1,processor(%r9) # get cpu number from task struture + sll %r1,L1_CACHE_SHIFT + al %r1,BASED(.Lirq_stat) # get address of irq_stat + icm %r0,15,0(%r1) # test irq_stat[#cpu].__softirq_pending bnz BASED(sysc_handle_bottom_half) # # check, if reschedule is needed @@ -657,10 +660,9 @@ lh %r7,__LC_PGM_ILC # load instruction length GET_CURRENT pgm_no_sv: + la %r3,0x7f lh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it - lr %r3,%r8 - la %r0,0x7f - nr %r3,%r0 # clear per-event-bit + nr %r3,%r8 # reload & clear per-event-bit be BASED(pgm_dn) # none of Martins exceptions occurred bypass l %r1,BASED(.Ljump_table) sll %r3,2 @@ -676,8 +678,7 @@ be BASED(pgm_go) # if yes then don't reenable interrupts stosm 24(%r15),0x03 # reenable interrupts pgm_go: basr %r14,%r1 # branch to interrupt-handler -pgm_dn: la %r0,0x80 - nr %r8,%r0 # check for per exception +pgm_dn: n %r8,BASED(.Lc128) # check for per excepton be BASED(pgm_return) la %r2,SP_PTREGS(15) # address of register-save area l %r1,BASED(.Lhandle_per) # load adr. of per handler @@ -713,8 +714,10 @@ # # check, if bottom-half has to be done # - l %r0,__LC_IRQ_STAT # get softirq_active - n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask + l %r1,processor(%r9) # get cpu number from task struture + sll %r1,L1_CACHE_SHIFT + al %r1,BASED(.Lirq_stat) # get address of irq_stat + icm %r0,15,0(%r1) # test irq_stat[#cpu].__softirq_pending bnz BASED(io_handle_bottom_half) io_return_bh: # @@ -843,6 +846,7 @@ .Lc0x2401: .long 0x2401 .Lc0x4000: .long 0x4000 .Lc0xff: .long 0xff +.Lc128: .long 128 /* * Symbol constants @@ -854,6 +858,7 @@ .Lentry_base: .long entry_base .Lext_hash: .long ext_int_hash .Lhandle_per: .long handle_per_exception +.Lirq_stat: .long irq_stat .Ljump_table: .long pgm_check_table .Lschedule: .long schedule .Lclone: .long sys_clone diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S --- v2.4.7/linux/arch/s390/kernel/head.S Wed Jul 25 17:10:18 2001 +++ linux/arch/s390/kernel/head.S Wed Jul 25 14:12:01 2001 @@ -461,7 +461,7 @@ .org 0x10000 startup:basr %r13,0 # get base .LPG1: lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers - l %r12,.Lparm1-.LPG1(%r13) # pointer to parameter area + la %r12,parmarea-.LPG1(%r13) # pointer to parameter area # move IPL device to lowcore mvc __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12) @@ -502,9 +502,7 @@ # find out if we have an IEEE fpu # mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13) - ld %f0,.Lflt0-.LPG1(%r13) # load (float) 0.0 - ldr %f2,%f0 - adbr %f0,%f2 # test IEEE add instruction + efpc %r0,0 # test IEEE extract fpc instruction oi 3(%r12),2 # set IEEE fpu flag .Lchkfpu: @@ -514,7 +512,7 @@ mvc __LC_PGM_NEW_PSW(8),.Lpccsp-.LPG1(%r13) la %r0,0 lr %r1,%r0 - la %r2,.Lflt0-.LPG1(%r13) + la %r2,4 csp %r0,%r2 # Test CSP instruction oi 3(%r12),8 # set CSP flag .Lchkcsp: @@ -554,12 +552,7 @@ .Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu .Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg -.Lflt0: .double 0 -.Lparm1:.long PARMAREA .L4malign:.long 0xffc00000 -.Lbigmem:.long 0x04000000 -.Lrdstart:.long 0x02000000 -.Lmaxchunk:.long 0x00ffffff .Lmemsize:.long memory_size .Lmflags:.long machine_flags @@ -567,6 +560,7 @@ # params at 10400 (setup.h) # .org PARMAREA +parmarea: .long 0,0 # IPL_DEVICE .long 0,RAMDISK_ORIGIN # INITRD_START .long 0,0x800000 # INITRD_SIZE @@ -578,7 +572,11 @@ # # startup-code, running in virtual mode # +#ifdef CONFIG_SHARED_KERNEL + .org 0x100000 +#else .org 0x10800 +#endif .globl _stext _stext: basr %r13,0 # get base .LPG2: @@ -608,8 +606,8 @@ jo .-4 # branch back, if not finish # check control registers stctl %c0,%c15,0(%r15) - oc 2(1,%r15),.Locbits+5-.LPG2(%r13) # enable sigp external ints. - oc 0(1,%r15),.Locbits+4-.LPG2(%r13) # low addresss proctection + oi 2(%r15),0x20 # enable sigp external interrupts + oi 0(%r15),0x10 # switch on low address protection lctl %c0,%c15,0(%r15) # @@ -622,15 +620,12 @@ basr %r13,0 lpsw .Ldw-.(%r13) # load disabled wait psw # -.Lstart: .long start_kernel .align 8 +.Ldw: .long 0x000a0000,0x00000000 .Lprefix: .long init_S390_lowcore .Linittu: .long init_task_union +.Lstart: .long start_kernel .Lbss_bgn: .long __bss_start .Lbss_end: .long _end -.Locbits: .long 0x01020408,0x10204080 - .align 4 .Laregs: .long 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 - .align 8 -.Ldw: .long 0x000a0000,0x00000000 diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/irq.c linux/arch/s390/kernel/irq.c --- v2.4.7/linux/arch/s390/kernel/irq.c Wed Jul 25 17:10:18 2001 +++ linux/arch/s390/kernel/irq.c Wed Jul 25 14:12:01 2001 @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include @@ -119,7 +119,7 @@ */ #ifdef CONFIG_SMP atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID); -atomic_t global_irq_lock; +atomic_t global_irq_lock = ATOMIC_INIT(0); atomic_t global_irq_count = ATOMIC_INIT(0); atomic_t global_bh_count; @@ -188,7 +188,7 @@ } /* Duh, we have to loop. Release the lock to avoid deadlocks */ - clear_bit(0,&global_irq_lock); + atomic_set(&global_irq_lock, 0); for (;;) { if (!--count) { @@ -206,10 +206,8 @@ if (!local_bh_count(cpu) && atomic_read(&global_bh_count)) continue; - /* this works even though global_irq_lock not - a long, but is arch-specific --RR */ - if (!test_and_set_bit(0,&global_irq_lock)) - break; + if (!atomic_compare_and_swap(0, 1, &global_irq_lock)) + break; } } } @@ -246,18 +244,14 @@ static inline void get_irqlock(int cpu) { - /* this works even though global_irq_lock not a long, but is - arch-specific --RR */ - if (test_and_set_bit(0,&global_irq_lock)) { + if (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0) { /* do we already hold the lock? */ if ( cpu == atomic_read(&global_irq_holder)) return; /* Uhhuh.. Somebody else got it. Wait.. */ do { - do { - check_smp_invalidate(cpu); - } while (test_bit(0,&global_irq_lock)); - } while (test_and_set_bit(0,&global_irq_lock)); + check_smp_invalidate(cpu); + } while (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0); } /* * We also to make sure that nobody else is running @@ -391,6 +385,10 @@ EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); +EXPORT_SYMBOL(global_irq_holder); +EXPORT_SYMBOL(global_irq_lock); +EXPORT_SYMBOL(global_irq_count); +EXPORT_SYMBOL(global_bh_count); #endif EXPORT_SYMBOL(global_bh_lock); diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c --- v2.4.7/linux/arch/s390/kernel/process.c Wed Apr 11 19:02:28 2001 +++ linux/arch/s390/kernel/process.c Wed Jul 25 14:12:01 2001 @@ -63,8 +63,7 @@ wait_psw.mask = _WAIT_PSW_MASK; wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L; while(1) { - if (softirq_active(smp_processor_id()) & - softirq_mask(smp_processor_id())) { + if (softirq_pending(smp_processor_id())) { do_softirq(); __sti(); if (!current->need_resched) @@ -307,11 +306,11 @@ frame = (struct stack_frame *) (2*PAGE_SIZE + (unsigned long) p) -1; frame = (struct stack_frame *) (((unsigned long) frame)&-8L); - p->thread.regs = &frame->childregs; + p->thread.regs = (struct pt_regs *)&frame->childregs; p->thread.ksp = (unsigned long) frame; - frame->childregs = *regs; + memcpy(&frame->childregs,regs,sizeof(struct pt_regs)); frame->childregs.gprs[15] = new_stackp; - frame->eos = 0; + frame->back_chain = frame->eos = 0; /* new return point is ret_from_sys_call */ frame->gprs[8] = ((unsigned long) &ret_from_fork) | 0x80000000; @@ -466,54 +465,3 @@ #undef last_sched #undef first_sched -/* - * This should be safe even if called from tq_scheduler - * A typical mask would be sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM) or 0. - * - */ -void s390_daemonize(char *name,unsigned long mask,int use_init_fs) -{ - struct fs_struct *fs; - extern struct task_struct *child_reaper; - struct task_struct *this_process=current; - - /* - * If we were started as result of loading a module, close all of the - * user space pages. We don't need them, and if we didn't close them - * they would be locked into memory. - */ - exit_mm(current); - - this_process->session = 1; - this_process->pgrp = 1; - if(name) - { - strncpy(current->comm,name,15); - current->comm[15]=0; - } - else - current->comm[0]=0; - /* set signal mask to what we want to respond */ - siginitsetinv(¤t->blocked,mask); - /* exit_signal isn't set up */ - /* if we inherit from cpu idle */ - this_process->exit_signal=SIGCHLD; - /* if priority=0 schedule can go into a tight loop */ - this_process->policy= SCHED_OTHER; - /* nice goes priority=20-nice; */ - this_process->nice=10; - if(use_init_fs) - { - exit_fs(this_process); /* current->fs->count--; */ - fs = init_task.fs; - current->fs = fs; - atomic_inc(&fs->count); - exit_files(current); - } - write_lock_irq(&tasklist_lock); - /* We want init as our parent */ - REMOVE_LINKS(this_process); - this_process->p_opptr=this_process->p_pptr=child_reaper; - SET_LINKS(this_process); - write_unlock_irq(&tasklist_lock); -} diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/s390_ext.c linux/arch/s390/kernel/s390_ext.c --- v2.4.7/linux/arch/s390/kernel/s390_ext.c Wed Apr 11 19:02:28 2001 +++ linux/arch/s390/kernel/s390_ext.c Wed Jul 25 14:12:01 2001 @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include @@ -17,12 +17,13 @@ * Simple hash strategy: index = code & 0xff; * ext_int_hash[index] is the start of the list for all external interrupts * that hash to this index. With the current set of external interrupts - * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000 - * iucv) this is always the first element. + * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000 + * iucv and 0x2603 pfault) this is always the first element. */ ext_int_info_t *ext_int_hash[256] = { 0, }; ext_int_info_t ext_int_info_timer; ext_int_info_t ext_int_info_hwc; +ext_int_info_t ext_int_pfault; int register_external_interrupt(__u16 code, ext_int_handler_t handler) { ext_int_info_t *p; @@ -39,7 +40,9 @@ p = &ext_int_info_timer; else if (code == 0x2401) /* hwc_init is done too early too */ p = &ext_int_info_hwc; - else + else if (code == 0x2603) /* pfault_init is done too early too */ + p = &ext_int_pfault; + else p = (ext_int_info_t *) kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC); if (p == NULL) @@ -70,7 +73,7 @@ q->next = p->next; else ext_int_hash[index] = p->next; - if (code != 0x1004 && code != 0x2401) + if (code != 0x1004 && code != 0x2401 && code != 0x2603) kfree(p); return 0; } diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c --- v2.4.7/linux/arch/s390/kernel/s390_ksyms.c Wed Apr 11 19:02:28 2001 +++ linux/arch/s390/kernel/s390_ksyms.c Wed Jul 25 14:12:01 2001 @@ -43,6 +43,7 @@ EXPORT_SYMBOL_NOVERS(strncpy); EXPORT_SYMBOL_NOVERS(strnlen); EXPORT_SYMBOL_NOVERS(strrchr); +EXPORT_SYMBOL_NOVERS(strstr); EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); @@ -53,6 +54,8 @@ EXPORT_SYMBOL(__udelay); EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(csum_fold); +EXPORT_SYMBOL(console_mode); +EXPORT_SYMBOL(console_device); #if CONFIG_IP_MULTICAST /* Required for lcs gigabit ethernet multicast support */ diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/setup.c linux/arch/s390/kernel/setup.c --- v2.4.7/linux/arch/s390/kernel/setup.c Wed Apr 11 19:02:28 2001 +++ linux/arch/s390/kernel/setup.c Wed Jul 25 14:12:01 2001 @@ -43,6 +43,8 @@ /* * Machine setup.. */ +unsigned int console_mode = 0; +unsigned int console_device = -1; unsigned long memory_size = 0; unsigned long machine_flags = 0; __u16 boot_cpu_addr; @@ -141,6 +143,93 @@ __setup("vmpoff=", vmpoff_setup); /* + * condev= and conmode= setup parameter. + */ + +static int __init condev_setup(char *str) +{ + int vdev; + + vdev = simple_strtoul(str, &str, 0); + if (vdev >= 0 && vdev < 65536) + console_device = vdev; + return 1; +} + +__setup("condev=", condev_setup); + +static int __init conmode_setup(char *str) +{ +#if defined(CONFIG_HWC_CONSOLE) + if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390) + SET_CONSOLE_HWC; +#endif +#if defined(CONFIG_TN3215_CONSOLE) + if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390)) + SET_CONSOLE_3215; +#endif +#if defined(CONFIG_TN3270_CONSOLE) + if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390)) + SET_CONSOLE_3270; +#endif + return 1; +} + +__setup("conmode=", conmode_setup); + +static void __init conmode_default(void) +{ + char query_buffer[1024]; + char *ptr; + + if (MACHINE_IS_VM) { + cpcmd("QUERY TERM", query_buffer, 1024); + ptr = strstr(query_buffer, "CONMODE"); + /* + * Set the conmode to 3215 so that the device recognition + * will set the cu_type of the console to 3215. If the + * conmode is 3270 and we don't set it back then both + * 3215 and the 3270 driver will try to access the console + * device (3215 as console and 3270 as normal tty). + */ + cpcmd("TERM CONMODE 3215", NULL, 0); + if (ptr == NULL) { +#if defined(CONFIG_HWC_CONSOLE) + SET_CONSOLE_HWC; +#endif + return; + } + if (strncmp(ptr + 8, "3270", 4) == 0) { +#if defined(CONFIG_TN3270_CONSOLE) + SET_CONSOLE_3270; +#elif defined(CONFIG_TN3215_CONSOLE) + SET_CONSOLE_3215; +#elif defined(CONFIG_HWC_CONSOLE) + SET_CONSOLE_HWC; +#endif + } else if (strncmp(ptr + 8, "3215", 4) == 0) { +#if defined(CONFIG_TN3215_CONSOLE) + SET_CONSOLE_3215; +#elif defined(CONFIG_TN3270_CONSOLE) + SET_CONSOLE_3270; +#elif defined(CONFIG_HWC_CONSOLE) + SET_CONSOLE_HWC; +#endif + } + } else if (MACHINE_IS_P390) { +#if defined(CONFIG_TN3215_CONSOLE) + SET_CONSOLE_3215; +#elif defined(CONFIG_TN3270_CONSOLE) + SET_CONSOLE_3270; +#endif + } else { +#if defined(CONFIG_HWC_CONSOLE) + SET_CONSOLE_HWC; +#endif + } +} + +/* * Reboot, halt and power_off routines for non SMP. */ @@ -183,8 +272,6 @@ return; smptrap=1; - printk("Command line is: %s\n", COMMAND_LINE); - /* * Setup lowcore information for boot cpu */ @@ -244,7 +331,6 @@ * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes */ if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) { - if (to != command_line) to--; delay = simple_strtoul(from+9, &from, 0); if (*from == 's' || *from == 'S') { delay = delay*1000000; @@ -253,7 +339,7 @@ delay = delay*60*1000000; from++; } - /* now wait for the requestedn amount of time */ + /* now wait for the requested amount of time */ udelay(delay); } cn = *(from++); @@ -261,6 +347,8 @@ break; if (cn == '\n') cn = ' '; /* replace newlines with space */ + if (cn == 0x0d) + cn = ' '; /* replace 0x0d with space */ if (cn == ' ' && c == ' ') continue; /* remove additional spaces */ c = cn; @@ -322,6 +410,9 @@ request_resource(&iomem_resource, res); request_resource(res, &code_resource); request_resource(res, &data_resource); + + /* Setup default console */ + conmode_default(); } void print_cpu_info(struct cpuinfo_S390 *cpuinfo) diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/signal.c linux/arch/s390/kernel/signal.c --- v2.4.7/linux/arch/s390/kernel/signal.c Wed Apr 11 19:02:28 2001 +++ linux/arch/s390/kernel/signal.c Wed Jul 25 14:12:01 2001 @@ -332,6 +332,7 @@ /* Set up registers for signal handler */ regs->gprs[15] = (addr_t)frame; regs->psw.addr = FIX_PSW(ka->sa.sa_handler); + regs->psw.mask = _USER_PSW_MASK; } /* Set up to return from userspace. If provided, use a stub already in userspace. */ @@ -358,6 +359,11 @@ #endif /* Martin wants this for pthreads */ regs->gprs[3] = (addr_t)&frame->sc; + + /* We forgot to include these in the sigcontext. + To avoid breaking binary compatibility, they are passed as args. */ + regs->gprs[4] = current->thread.trap_no; + regs->gprs[5] = current->thread.prot_addr; return; give_sigsegv: @@ -414,7 +420,7 @@ siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) { /* Are we from a system call? */ - if (regs->orig_gpr2 >= 0) { + if (regs->trap == __LC_SVC_OLD_PSW) { /* If so, check system call restarting.. */ switch (regs->gprs[2]) { case -ERESTARTNOHAND: @@ -561,7 +567,6 @@ /* FALLTHRU */ default: - lock_kernel(); sigaddset(¤t->pending.signal, signr); recalc_sigpending(current); current->flags |= PF_SIGNALED; diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c --- v2.4.7/linux/arch/s390/kernel/smp.c Wed Jul 25 17:10:18 2001 +++ linux/arch/s390/kernel/smp.c Wed Jul 25 14:12:01 2001 @@ -556,6 +556,7 @@ * Activate a secondary processor. */ extern void init_100hz_timer(void); +extern int pfault_token(void); int __init start_secondary(void *cpuvoid) { @@ -568,6 +569,10 @@ /* nothing */ ; /* init per CPU 100 hz timer */ init_100hz_timer(); +#ifdef CONFIG_PFAULT + /* Enable pfault pseudo page faults on this cpu. */ + pfault_init(); +#endif /* cpu_idle will call schedule for us */ return cpu_idle(NULL); } diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/time.c linux/arch/s390/kernel/time.c --- v2.4.7/linux/arch/s390/kernel/time.c Tue Feb 13 14:13:44 2001 +++ linux/arch/s390/kernel/time.c Wed Jul 25 14:12:01 2001 @@ -95,9 +95,10 @@ { unsigned long flags; unsigned long usec, sec; - unsigned long lost_ticks = jiffies - wall_jiffies; + unsigned long lost_ticks; read_lock_irqsave(&xtime_lock, flags); + lost_ticks = jiffies - wall_jiffies; usec = do_gettimeoffset(); if (lost_ticks) usec +=(USECS_PER_JIFFY*lost_ticks); diff -u --recursive --new-file v2.4.7/linux/arch/s390/kernel/traps.c linux/arch/s390/kernel/traps.c --- v2.4.7/linux/arch/s390/kernel/traps.c Wed Apr 11 19:02:28 2001 +++ linux/arch/s390/kernel/traps.c Wed Jul 25 14:12:01 2001 @@ -36,6 +36,7 @@ #include #endif #include +#include /* Called from entry.S only */ extern void handle_per_exception(struct pt_regs *regs); @@ -53,6 +54,11 @@ extern pgm_check_handler_t do_page_fault; extern pgm_check_handler_t do_pseudo_page_fault; +#ifdef CONFIG_PFAULT +extern int pfault_init(void); +extern void pfault_fini(void); +extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code); +#endif spinlock_t die_lock; @@ -142,7 +148,7 @@ DO_ERROR(SIGILL, "privileged operation", privileged_op) DO_ERROR(SIGILL, "execute exception", execute_exception) DO_ERROR(SIGSEGV, "addressing exception", addressing_exception) -DO_ERROR(SIGILL, "fixpoint divide exception", divide_exception) +DO_ERROR(SIGFPE, "fixpoint divide exception", divide_exception) DO_ERROR(SIGILL, "translation exception", translation_exception) DO_ERROR(SIGILL, "special operand exception", special_op_exception) DO_ERROR(SIGILL, "operand exception", operand_exception) @@ -154,7 +160,6 @@ int signal = 0; int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); - lock_kernel(); location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); if(problem_state) get_user(*((__u16 *) opcode), location); @@ -197,7 +202,6 @@ } else if (signal) do_trap(interruption_code, signal, "illegal operation", regs, NULL); - unlock_kernel(); } @@ -210,7 +214,6 @@ __u16 *location; int signal = 0; - lock_kernel(); if (regs->psw.mask & PSW_PROBLEM_STATE) { location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); get_user(*((__u16 *) opcode), location); @@ -250,7 +253,6 @@ } else if (signal) do_trap(interruption_code, signal, "specification exception", regs, NULL); - unlock_kernel(); } #else DO_ERROR(SIGILL, "specification exception", specification_exception) @@ -262,7 +264,6 @@ __u16 *location; int signal = 0; - lock_kernel(); location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); if (MACHINE_HAS_IEEE) __asm__ volatile ("stfpc %0\n\t" @@ -333,7 +334,6 @@ } else if (signal) do_trap(interruption_code, signal, "data exception", regs, NULL); - unlock_kernel(); } @@ -361,8 +361,26 @@ pgm_check_table[0x14] = &do_pseudo_page_fault; pgm_check_table[0x15] = &operand_exception; pgm_check_table[0x1C] = &privileged_op; +#ifdef CONFIG_PFAULT + if (MACHINE_IS_VM) { + /* request the 0x2603 external interrupt */ + if (register_external_interrupt(0x2603, pfault_interrupt) != 0) + panic("Couldn't request external interrupt 0x2603"); + /* + * First try to get pfault pseudo page faults going. + * If this isn't available turn on pagex page faults. + */ + if (pfault_init() != 0) { + /* Tough luck, no pfault. */ + unregister_external_interrupt(0x2603, + pfault_interrupt); + cpcmd("SET PAGEX ON", NULL, 0); + } + } +#else if (MACHINE_IS_VM) - cpcmd("SET PAGEX ON", NULL, 0); + cpcmd("SET PAGEX ON", NULL, 0); +#endif } diff -u --recursive --new-file v2.4.7/linux/arch/s390/mm/Makefile linux/arch/s390/mm/Makefile --- v2.4.7/linux/arch/s390/mm/Makefile Tue Feb 13 14:13:44 2001 +++ linux/arch/s390/mm/Makefile Wed Jul 25 14:12:01 2001 @@ -1,5 +1,5 @@ # -# Makefile for the linux i386-specific parts of the memory manager. +# Makefile for the linux s390-specific parts of the memory manager. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here diff -u --recursive --new-file v2.4.7/linux/arch/s390/mm/fault.c linux/arch/s390/mm/fault.c --- v2.4.7/linux/arch/s390/mm/fault.c Wed Apr 11 19:02:27 2001 +++ linux/arch/s390/mm/fault.c Wed Jul 25 14:12:01 2001 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -52,25 +53,14 @@ unsigned long address; unsigned long fixup; int write; - unsigned long psw_mask; - unsigned long psw_addr; int si_code = SEGV_MAPERR; int kernel_address = 0; - /* - * get psw mask of Program old psw to find out, - * if user or kernel mode - */ - - psw_mask = S390_lowcore.program_old_psw.mask; - psw_addr = S390_lowcore.program_old_psw.addr; - /* * get the failing address * more specific the segment and page table portion of * the address */ - address = S390_lowcore.trans_exc_code&0x7ffff000; tsk = current; @@ -185,7 +175,7 @@ up_read(&mm->mmap_sem); /* User mode accesses just cause a SIGSEGV */ - if (psw_mask & PSW_PROBLEM_STATE) { + if (regs->psw.mask & PSW_PROBLEM_STATE) { struct siginfo si; tsk->thread.prot_addr = address; tsk->thread.trap_no = error_code; @@ -243,7 +233,7 @@ out_of_memory: up_read(&mm->mmap_sem); printk("VM: killing process %s\n", tsk->comm); - if (psw_mask & PSW_PROBLEM_STATE) + if (regs->psw.mask & PSW_PROBLEM_STATE) do_exit(SIGKILL); goto no_context; @@ -259,7 +249,7 @@ force_sig(SIGBUS, tsk); /* Kernel mode? Handle exceptions or die */ - if (!(psw_mask & PSW_PROBLEM_STATE)) + if (!(regs->psw.mask & PSW_PROBLEM_STATE)) goto no_context; } @@ -275,25 +265,17 @@ static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */ /* - * This routine handles pseudo page faults. + * This routine handles 'pagex' pseudo page faults. */ asmlinkage void do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code) { - DECLARE_WAITQUEUE(wait, current); pseudo_wait_t wait_struct; pseudo_wait_t *ptr, *last, *next; - unsigned long psw_mask; unsigned long address; int kernel_address; /* - * get psw mask of Program old psw to find out, - * if user or kernel mode - */ - psw_mask = S390_lowcore.program_old_psw.mask; - - /* * get the failing address * more specific the segment and page table portion of * the address @@ -332,7 +314,7 @@ spin_unlock(&pseudo_wait_spinlock); } else { /* Pseudo page faults in kernel mode is a bad idea */ - if (!(psw_mask & PSW_PROBLEM_STATE)) { + if (!(regs->psw.mask & PSW_PROBLEM_STATE)) { /* * VM presents pseudo page faults if the interrupted * state was not disabled for interrupts. So we can @@ -383,4 +365,127 @@ wait_event(wait_struct.queue, wait_struct.resolved); } } - + +#ifdef CONFIG_PFAULT +/* + * 'pfault' pseudo page faults routines. + */ +static int pfault_disable = 0; + +static int __init nopfault(char *str) +{ + pfault_disable = 1; + return 1; +} + +__setup("nopfault", nopfault); + +typedef struct { + __u16 refdiagc; + __u16 reffcode; + __u16 refdwlen; + __u16 refversn; + __u64 refgaddr; + __u64 refselmk; + __u64 refcmpmk; + __u64 reserved; +} __attribute__ ((packed)) pfault_refbk_t; + +int pfault_init(void) +{ + pfault_refbk_t refbk = + { 0x258, 0, 5, 2, __LC_KERNEL_STACK, 1ULL << 48, 1ULL << 48, 0ULL }; + int rc; + + if (pfault_disable) + return -1; + __asm__ __volatile__( + " diag %1,%0,0x258\n" + "0: j 2f\n" + "1: la %0,8\n" + "2:\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,1b\n" + ".previous" + : "=d" (rc) : "a" (&refbk) : "cc" ); + __ctl_set_bit(0, 9); + return rc; +} + +void pfault_fini(void) +{ + pfault_refbk_t refbk = + { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL }; + + if (pfault_disable) + return; + __ctl_clear_bit(0,9); + __asm__ __volatile__( + " diag %0,0,0x258\n" + "0:\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,0b\n" + ".previous" + : : "a" (&refbk) : "cc" ); +} + +asmlinkage void +pfault_interrupt(struct pt_regs *regs, __u16 error_code) +{ + DECLARE_WAITQUEUE(wait, current); + struct task_struct *tsk; + wait_queue_head_t queue; + wait_queue_head_t *qp; + __u16 subcode; + + /* + * Get the external interruption subcode & pfault + * initial/completion signal bit. VM stores this + * in the 'cpu address' field associated with the + * external interrupt. + */ + subcode = S390_lowcore.cpu_addr; + if ((subcode & 0xff00) != 0x06) + return; + + /* + * Get the token (= address of kernel stack of affected task). + */ + tsk = (struct task_struct *) + (*((unsigned long *) __LC_PFAULT_INTPARM) - THREAD_SIZE); + + if (subcode & 0x0080) { + /* signal bit is set -> a page has been swapped in by VM */ + qp = (wait_queue_head_t *) + xchg(&tsk->thread.pfault_wait, -1); + if (qp != NULL) { + /* Initial interrupt was faster than the completion + * interrupt. pfault_wait is valid. Set pfault_wait + * back to zero and wake up the process. This can + * safely be done because the task is still sleeping + * and can't procude new pfaults. */ + tsk->thread.pfault_wait = 0ULL; + wake_up(qp); + } + } else { + /* signal bit not set -> a real page is missing. */ + init_waitqueue_head (&queue); + qp = (wait_queue_head_t *) + xchg(&tsk->thread.pfault_wait, (addr_t) &queue); + if (qp != NULL) { + /* Completion interrupt was faster than the initial + * interrupt (swapped in a -1 for pfault_wait). Set + * pfault_wait back to zero and exit. This can be + * done safely because tsk is running in kernel + * mode and can't produce new pfaults. */ + tsk->thread.pfault_wait = 0ULL; + } + + /* go to sleep */ + wait_event(queue, tsk->thread.pfault_wait == 0ULL); + } +} +#endif + diff -u --recursive --new-file v2.4.7/linux/arch/s390/tools/dasdfmt/Makefile linux/arch/s390/tools/dasdfmt/Makefile --- v2.4.7/linux/arch/s390/tools/dasdfmt/Makefile Tue Feb 13 14:13:44 2001 +++ linux/arch/s390/tools/dasdfmt/Makefile Wed Dec 31 16:00:00 1969 @@ -1,9 +0,0 @@ -all: dasdfmt - -dasdfmt: dasdfmt.c - $(CC) -o $@ $^ - $(STRIP) $@ - -clean: - rm -f dasdfmt - diff -u --recursive --new-file v2.4.7/linux/arch/s390/tools/dasdfmt/dasdfmt.8 linux/arch/s390/tools/dasdfmt/dasdfmt.8 --- v2.4.7/linux/arch/s390/tools/dasdfmt/dasdfmt.8 Fri Mar 2 11:12:06 2001 +++ linux/arch/s390/tools/dasdfmt/dasdfmt.8 Wed Dec 31 16:00:00 1969 @@ -1,68 +0,0 @@ -.TH DASDFMT 8 "Tue Jan 25 2000" -.UC 4 -.SH NAME -dasdfmt \- formatting of DSAD (ECKD) disk drives. -.SH SYNOPSIS -\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR -.SH DESCRIPTION -\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it -for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of -\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR. - -.SH OPTIONS -.TP -\fB-t\fR -Disables any modification of the disk drive. \fBdasdfmt\fR just prints -out, what it \fBwould\fR do. - -.TP -\fB-v\fR -Increases verbosity. - -.TP -\fB-y\fR -Start formatting without further user-confirmation. - -.TP -\fB-L\fR -Omit the writing of a disk label after formatting. - -.TP -\fB-V\fR -Print version number and exit. - -.TP -\fB-b\fR \fIblockSize\fR -Specify blocksize to be used. \fIblocksize\fR must be a positive integer -and always be a power of two. Due due some limitations in the driver, -it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR. - -.TP -\fB-l\fR \fIdiskLabel\fR -Specify the label to be written to disk after formatting. If no label is -specified, a sensible default is used. \fIdiskLabel\fR is interpreted as -ASCII string and is automatically converted to EBCDIC. - -.TP -\fIdiskSpec\fR -This parameter specified the device to be formatted. It also can be -given in two variants: -.sp - \fB-f\fR \fB/dev/dasd\fR\fIX\fR -.br -or -.br - \fB-n\fR \fIdevnum\fR -.sp -The first form uses the commonly used -.SM UNIX -device notation where \fIX\fR is a single lowercase letter. -The second form uses simply the device number. - -.SH BUGS -None so far ;-) - -.SH AUTHOR -.nf -This man-page was written by Fritz Elfert -.fi diff -u --recursive --new-file v2.4.7/linux/arch/s390/tools/dasdfmt/dasdfmt.c linux/arch/s390/tools/dasdfmt/dasdfmt.c --- v2.4.7/linux/arch/s390/tools/dasdfmt/dasdfmt.c Wed Apr 11 19:02:27 2001 +++ linux/arch/s390/tools/dasdfmt/dasdfmt.c Wed Dec 31 16:00:00 1969 @@ -1,839 +0,0 @@ -/* - * - * dasdfmt.c - * - * S390 version - * Copyright (C) 1999,2000 IBM Corporation - * Author(s): Utz Bacher, - * - * Device-in-use-checks by Fritz Elfert, - * Compatible Disk Layout enhancements by Carsten Otte, - * - * Still to do: - * detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them - */ - -/* #define _LINUX_BLKDEV_H */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define __KERNEL__ /* we want to use kdev_t and not have to define it */ -#include -#undef __KERNEL__ - -#include -#include -#include - -#define EXIT_MISUSE 1 -#define EXIT_BUSY 2 -#define TEMPFILENAME "/tmp/ddfXXXXXX" -#define TEMPFILENAMECHARS 8 /* 8 characters are fixed in all temp filenames */ -#define SLASHDEV "/dev/" -#define PROC_DASD_DEVICES "/proc/dasd/devices" -/* _PATH_MOUNTED is /etc/mtab - /proc/mounts does not show root-fs correctly */ -#define PROC_MOUNTS _PATH_MOUNTED -#define PROC_SWAPS "/proc/swaps" -#define DASD_DRIVER_NAME "dasd" -#define LABEL_LENGTH 10 -#define PROC_LINE_LENGTH 80 -#define ERR_LENGTH 80 - -#define MAX_FILELEN NAME_MAX+PATH_MAX - -#define GIVEN_DEVNO 1 -#define GIVEN_MAJOR 2 -#define GIVEN_MINOR 4 - -#define CHECK_START 1 -#define CHECK_END 2 -#define CHECK_BLKSIZE 4 -#define CHECK_ALL ~0 - -#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);} -#define ERRMSG_EXIT(ec,x...) {fflush(stdout);fprintf(stderr,x);exit(ec);} - -#define CHECK_SPEC_MAX_ONCE(i,str) \ - {if (i>1) \ - ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \ - "can only be specified once\n",prog_name);} - -#define PARSE_PARAM_INTO(x,param,base,str) \ - {x=(int)strtol(param,&endptr,base); \ - if (*endptr) \ - ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \ - "is in invalid format\n",prog_name);} - -char *prog_name;/*="dasdfmt";*/ -char tempfilename[]=TEMPFILENAME; - -__u8 _ascebc[256] = -{ - /*00 NUL SOH STX ETX EOT ENQ ACK BEL */ - 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, - /*08 BS HT LF VT FF CR SO SI */ - /* ->NL */ - 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ - 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, - /*18 CAN EM SUB ESC FS GS RS US */ - /* ->IGS ->IRS ->IUS */ - 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, - /*20 SP ! " # $ % & ' */ - 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, - /*28 ( ) * + , - . / */ - 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, - /*30 0 1 2 3 4 5 6 7 */ - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - /*38 8 9 : ; < = > ? */ - 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, - /*40 @ A B C D E F G */ - 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - /*48 H I J K L M N O */ - 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, - /*50 P Q R S T U V W */ - 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, - /*58 X Y Z [ \ ] ^ _ */ - 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, - /*60 ` a b c d e f g */ - 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - /*68 h i j k l m n o */ - 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, - /*70 p q r s t u v w */ - 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, - /*78 x y z { | } ~ DL */ - 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, - /*80*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*88*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*90*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*98*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*A0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*A8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*B0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*B8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*C0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*C8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*D0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*D8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*E0 sz */ - 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*E8*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*F0*/ - 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, - /*F8*/ - 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF -}; - -void convert_label(char *str) -{ - int i; - for (i=0;i] [-b ] [] " \ - "\n\n",prog_name); -#else /* RANGE_FORMATTING */ - printf("Usage: %s [-htvyCLV] [-l