Update of /cvsroot/linux-vax/kernel-2.4/Documentation/vax In directory usw-pr-cvs1:/tmp/cvs-serv32365 Added Files: README assembler.txt interrupts.txt ka43-interrupts.txt memory.txt syscall.txt xdelta.txt Log Message: Bringing in docs from kernel-2.2 tree --- NEW FILE --- Last updated Jul 10, 2000 GETTING STARTED To play with this port you need the following: 1. The cross-compiler and binutils 2. The kernel sources 3. A MOP server (mopd) 4. A VAX with an ethernet card or SCSI interface Unfortunately, there are a few large downloads involved to get up and running... 1. The cross-compiler and binutils First download the following: From ftp://linux-vax.sourceforge.net/pub/linux-vax/tools/sources/ binutils-2.9.1.0.25.tar.bz2 egcs-1.1.2.tar.bz2 From ftp://linux-vax.sourceforge.net/pub/linux-vax/tools/patches/ binutils-2.9.1.0.25-20000219.patch.bz2 egcs-1.1.2-20000219.patch.bz2 From ftp://linux-vax.sourceforge.net/pub/linux-vax/tools/ build-vax.sh one-tree-vax.sh Create a new directory to unpack all this stuff in and untar the egcs and binutils tarballs, apply the patches and copy in the shell scripts: $ mkdir vax-cross $ cd vax-cross $ tar xvf --use=bzip2 DOWNLOADS/binutils-2.9.1.0.25.tar.bz2 $ tar xvf --use=bzip2 DOWNLOADS/egcs-1.1.2.tar.bz2 $ cd binutils-2.9.1.0.25.current $ patch -p1 < DOWNLOADS/binutils-2.9.1.0.25-20000219.patch $ cd ../egcs-1.1.2.current $ patch -p1 < DOWNLOADS/egcs-1.1.2-20000219.patch $ cd .. $ cp DOWNLOADS/one-tree-vax.sh DOWNLOADS/build-vax.sh . Then create the combined binutils/egcs source tree and build it: $ ./one-tree-vax.sh $ ./build-vax.sh These should complete without errors. If you get errors, something is seriously wrong and you probably won't get a correctly-installed toolchain. All object files and binaries will be created in vax-cross/b-vax-dec-linux without touching the source trees. Then install them: $ su -c './build-vax.sh install' This will create programs in /usr/local/bin prefixed with vax-dec-linux- (for example /usr/local/bin/vax-dec-linux-gcc) and directories /usr/local/vax-dec-linux and /usr/local/lib/gcc-lib/vax-dec-linux. This will not touch your current GCC installation. 2. The kernel sources Grab the sources from CVS: $ cvs -d:pserver:ano...@cv...:/cvsroot/linux-vax login (hit return at the password prompt). $ cvs -z9 -d:pserver:ano...@cv...:/cvsroot/linux-vax co kernel cd into the kernel dir created by cvs and do $ make oldconfig to create a default .config. (Don't go playing with the config, please. It will probably just break the compile.) Compile a network-bootable image by doing $ make mopboot This will generate plenty of compiler and linker warnings, but you should end up with a vmlinux.SYS file sized about 280K. If you are hacking around in arch/vax, you can do a quicker re-compile by doing $ make mopbootx which just rebuilds stuff in arch/vax and re-links the kernel. If you have your VAX and Linux machine on the same SCSI chain and you've got a scratch disk handy, you can do $ make diskboot && dd if=vmlinux.dsk of=/dev/sdX and then tell your VAX to boot from this disk. This is faster than netbooting. NOTE THAT THIS WILL DESTROY ANY FILESYSTEM AREADY ON THE DISK. YOU HAVE BEEN WARNED. 3. A MOP server (mopd) Sources at http://www.mssl.ucl.ac.uk/~atp/linux-vax/download/mopd-linux.tar.gz Compile and install. Create the directory /tftpboot/mop. mopd looks here, and here only, when searching for boot images. Create a link from /tftpboot/mop/<ether>.SYS to the vmlinux.SYS file in your development tree. <ether> is the ethernet address of your VAX in _lowercase_ with no separators. For example, mine is 08002b0db20f.SYS. In can be useful to run mopd with the -d switch to see what it receives from the network. 4. A VAX with an ethernet card or SCSI interface. As we don't really have any hardware support in yet, hardware requirements are pretty minimal: CPU Serial console 8 MB ram Ethernet card So far we've had success reports from people with the following machines: VAXstation 2000 VAXstation 3100/m30 VAXstation 3100/m76 VAXstation 3500 VAXstation II/GPX First you'll want to get your VAX to stop at the >>> console prompt at power up. There is usually a switch on the CPU board, front panel or rear panel (depending on the model) to select this. Look for a circle with a dot inside. Hook your VAX up to a standalone terminal, such a VT-series terminal or a serial port on your PC. The VAX will probably have an MMJ serial connector. I can't find a URL with the pin-out info for this guy. If you have an OS installed (e.g. VMS, Ultrix, NetBSD), it would be a good idea to take your disks offline, if your VAX has a handy way to do this. For example, the VS3500 has front panel switches to take the internal disks offline. At the >>> prompt, try B <return>, B XQA0 or B ESA0 and see if one of them tries to netboot (watch the output of mopd -d). If it looks like mopd sent over a boot image, let us know what happens. Depending on your hardware, you might get a kernel version banner and some diagnostic output. However, if we don't support your serial console hardware, you'll probably just get an error message such as 'HLT INST' and return to the >>> prompt. If this happens, do the following: >>> E PC >>> E PSL >>> E SP >>> E/V @ >>> E >>> E >>> E >>> E >>> E >>> E And send us the output. This will hopefully give us clues as to how to get your serial console supported. If your VAX has a SCSI interface and you have an external SCSI connector on your Linux box, you can connect both of them to the same SCSI bus. (Make sure the host adapters in each machine have different SCSI IDs. VAXen usually ship with the host adapter set to ID 6, PCs are usually ID 7.) Then you can copy a kernel image onto a disk on the bus and boot from there. NOTE THAT THIS WILL DESTROY ANY FILESYSTEM AREADY ON THE DISK. YOU HAVE BEEN WARNED. --- NEW FILE --- The GNU assembler in Andy's cross compilation tool set is a little different from DEC's MACRO32 assembler. This file summarises the differences. 1. #, ^ and @ become $, ` and * In VAX MACRO you might write: movl #0, 8(r5) movl #0, @8(r5) movl #0, L^8(r5) In gas, these are written: movl $0, r0 movl $0, *8(r5) movl $0, L`8(r5) 2. ^X becomes 0x Hex constants are prefixed with 0x, rather than ^x Similarly, a leading zero not followed by an x implies octal. Therefore the following instructions are equivalent: VAX MACRO: movl #64, r0 movl #^x40, r0 movl #^o100, r0 gas: movl $64, r0 movl $0x40, r0 movl $0100, r0 --- NEW FILE --- 20000709 KPH Here's how I intend to deal with interrupt and exception dispatching. o During boot time, trap_init fills the whole SCB with stray handlers. Since the CPU might save some longwords of data on the stack after an exception, we can't just continue from one of these exceptions in the general case. (However, interrupts from devices that come through the second and subsequent pages of the SCB should be continuable.) The stray handlers might help out with autoprobing interrupts if we decide to implement probe_irq_on() and probe_irq_off(). Dammit, I hate using the term IRQ when talking about VAXen. It just seems so PC-centric... o When an interrupt (or exception) occurs and the CPU dispatches to the handler address in the SCB, the only clue we have as to the interrupt or exception number is the handler address. There is no other way to tell which interrupt happened. This implies that every interrupt or exception handler must have a unique address. o When a driver (or other code) calls request_irq(), we allocate a data structure (let's call it irqvector) that contains a struct irqaction and a little bit of in-line code. This code just pushes PC on the stack and jumps to the generic handler. (It does this by executing a JSB instruction.) This generic handler sees a stack that looks like: SP: handler_PC (inside the irqvector) (maybe) exception info saved PC saved PSL The generic handler builds the required pt_regs struct by duplicating the saved PC/PSL and saving all the other registers. This makes the stack look like: SP: saved R0 saved R1 ... saved R11 saved FP saved AP saved SP saved PC saved PSL saved R0 handler PC (inside the irqvector) (maybe) exception info saved PC saved PSL (The second saved R0 is because we need a working register in the handler code.) The generic handler then obtains the handler PC from back up the stack, then passes this PC, the addr of the pt_regs and exception info to a dispatcher function. This function is responsible for calculating the start address of the irqvector structure and calling irqaction.handler(). When control returns to the generic handler, it restores the registers, clears the stack down as far as the original saved PC and PSL and does an REI. Anyone playing around with this stuff really needs to read the Interrupts and Exceptions chapter in the VAX Architecture Reference Manual. --- NEW FILE --- $Id: ka43-interrupts.txt,v 1.1 2001/01/18 00:10:39 kenn Exp $ This info was obtained by trawling through a running VMS 7.2 on a VAXstation 3100/m76 (KA43 CPU) with the System Dump Analyzer (ANALYZE/SYSTEM). First off, this is the SCB (system control block): SDA> examine exe$gl_scb EXE$GL_SCB: 81258000 "..%." SDA> examine 81258000:81258000+3fc 80BD6E09 80002491 8000A801 80002119 .!.......$...n½. 81258000 800025F8 80B723A4 80002518 80E5CFC0 ..å..%...#o.Ø%.. 81258010 80B722C0 80B723AC 80BB35B8 80B7223C <"o..5».¬#o.."o. 81258020 80BB3479 80002118 800021D0 80002308 .#...!...!..y4». 81258030 80002300 800022F8 80B724D8 80B725E0 à%o.b$o.Ø"...#.. 81258040 8000A819 8000A811 8000A809 80002118 .!.............. 81258050 80002118 80002520 80002118 8000A821 !....!.. %...!.. 81258060 80002118 80002118 80002118 80002118 .!...!...!...!.. 81258070 80BE0C00 80BD04D0 80002118 80002118 .!...!....½..... 81258080 80C4E921 80C4E621 80002118 80BD3E91 .>½..!..!æÄ.!éÄ. 81258090 80C4E639 80C4E631 80C4E629 80C4E641 AæÄ.)æÄ.1æÄ.9æÄ. 812580A0 80002118 800027B1 80002118 80002471 q$...!..±'...!.. 812580B0 80E60A9C 80E60A00 80002118 80C4E739 9çÄ..!....æ...æ. 812580C0 80002118 80002118 80002118 80002118 .!...!...!...!.. 812580D0 80002118 80002118 80002118 80002118 .!...!...!...!.. 812580E0 80C50A5D 80C50A25 80002118 80002118 .!...!..%.Å.].Å. 812580F0 80002119 80002119 80002119 80002119 .!...!...!...!.. 81258100 80002119 80002119 80002119 80002119 .!...!...!...!.. 81258110 80002119 80002119 80002119 80002119 .!...!...!...!.. 81258120 80002119 80002119 80002119 80002119 .!...!...!...!.. 81258130 80002119 80002119 80002119 80002119 .!...!...!...!.. 81258140 80002119 80002119 80002119 80002119 .!...!...!...!.. 81258150 80002119 80002119 80002119 80002119 .!...!...!...!.. 81258160 80002119 80002119 80002119 80002119 .!...!...!...!.. 81258170 80002119 80002119 80002119 80002119 .!...!...!...!.. 81258180 80002119 80002119 80002119 80002119 .!...!...!...!.. 81258190 80002119 80002119 80002119 80002119 .!...!...!...!.. 812581A0 80002119 80002119 80002119 80002119 .!...!...!...!.. 812581B0 80002119 80002119 80002119 80002119 .!...!...!...!.. 812581C0 80002119 80002119 80002119 80002119 .!...!...!...!.. 812581D0 80002119 80002119 80002119 80002119 .!...!...!...!.. 812581E0 80002119 80002119 80002119 80002119 .!...!...!...!.. 812581F0 8000A829 8000A829 8000A829 80E642D9 .Bæ.)...)...)... 81258200 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258210 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258220 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258230 8000A829 80DBB389 80DBB351 8000A829 )...Q.......)... 81258240 8000A829 8000A829 8000A829 80D875D1 Ñub.)...)...)... 81258250 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258260 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258270 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258280 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258290 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 812582A0 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 812582B0 8000A829 8000A829 80DC33C9 80DC3391 .3Ü.É3Ü.)...)... 812582C0 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 812582D0 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 812582E0 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 812582F0 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258300 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258310 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258320 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258330 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258340 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258350 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258360 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258370 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258380 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 81258390 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 812583A0 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 812583B0 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 812583C0 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 812583D0 8000A829 8000A829 8000A829 8000A829 )...)...)...)... 812583E0 80D9CF11 80DB9BD1 8000A829 8000A829 )...)...Ñ....... 812583F0 (The hex data reads right-to-left and the ASCII reads left-to-right, i.e. VMS DUMP format.) The part we're interested in here is the second page (containing the device vectors). Most of these vectors are set to 8000a829 (which corresponds to address 8000a828, and the CPU should switch to the interrupt stack): SDA> examine/instr 8000a828 UBA$UNEXINT: JMP @#MCHK+00700 UBA$UNEXINT+00006: HALT So, these are unexpected interrupts and will lead to code near the machine check handling code. The other (used) vectors are: vector addr vector number handler addr 81258200 80 80e642d8 81258244 91 80dbb350 81258248 92 80dbb388 81258250 94 80d875d0 812582c0 b0 80dc3390 812582c4 b1 80dc33c8 812583f8 fe 80db9bd0 812583fc ff 80d9cf10 These interrupt handler addresses are containing within the CRB (Channel Request Block) for the relevant device or controller. Let's chase these down. First vector 0x80: SDA> examine/instr 80e642d8:80e642d8+10 MCHK+006F8: INCL @#IO$GL_UBA_INT0 MCHK+006FE: BRB MCHK+00700 MCHK+00700: REI This just increments an interrupt counter and dismisses the interrupt. (So the unexpected interrupt handler above effectively just dismisses the interrupt.) Next vector 0x91: SDA> examine/instr/noskip 80DBB350;2 80DBB350: PUSHR #3F 80DBB352: JSB @#GABDRIVER+00942 So, this interrupt is probably handled by GABDRIVER. Let's verify this by looking at GABDRIVER's data structures: SDA> show device ga ... --- Primary Channel Request Block (CRB) 80DBB300 --- Reference count 1 Wait queue empty IDB address 80DB5640 Unit init. 80E0D589 Int. service 80E0DCC2 ADP address 80D87300 Ctrl. init. 80E0D4ED ... SDA> format 80DBB300 80DBB300 CRB$L_FQFL 00000000 ... 80DBB350 CRB$L_INTD 9F163FBB 80DBB354 80E0DCC2 GABDRIVER+00942 ... 80DBB388 CRB$L_INTD2 9F163FBB SDA> So the interrupt handler is 0x50 bytes into the CRB. Interestingly, there's another interrupt handler 0x88 bytes into the CRB as well. This corresponds to vector 0x92 in the table above. SDA> examine/instr 80DBB388;2 80DBB388: PUSHR #3F 80DBB38A: JSB @#GABDRIVER+0145C So this device uses two interrupt vectors. This means that the CRBs for the other vectors are: vector addr num handler addr CRB address driver 81258200 80 80e642d8 (no driver) 81258244 91 80dbb350 80dbb300 GABDRIVER 81258248 92 80dbb388 80dbb300 GABDRIVER 81258250 94 80d875d0 80d87580 ESDRIVER 812582c0 b0 80dc3390 80dc3340 YEDRIVER 812582c4 b1 80dc33c8 80dc3340 YEDRIVER 812583f8 fe 80db9bd0 80db9b80 PKNDRIVER (PKA) 812583fc ff 80d9cf10 80d9cec0 PKNDRIVER (PKB) GABDRIVER is the framebuffer driver, ESDRIVER is ethernet, YEDRIVER is a terminal port driver (I think) and PKNDRIVER is a SCSI port driver. So, to summarize, the KA43 device interrupts are: Framebuffer 0x91, 0x92 LANCE ethernet 0x94 DZ11 serial 0xb0, 0xb1 NCR5380 SCSI: internal 0xfe external 0xff --- NEW FILE --- $Id: memory.txt,v 1.1 2001/01/18 00:10:39 kenn Exp $ KPH 20000416 We need to decide on what the overall memory map in S0 space will look like. Here's what I think: Start Length 80000000 1MB Spare space left over from kernel load time. Will be put on the kernel's free list. 80100000 kern_size Kernel code, data and bss sections pg0 spt_size System page table. Length will be dependent on physical memory size plus some extra space for mapping I/O pages mem_map memsize*40 The mem_map array contains one entry for each physical page of ram. remainder Remaining pages are put on free list ====================================================================== KPH 20000107 (2.2.10-991101-kh5) After a little discussion with Andy, it looks like we'll create a full-size system page table (SPT) in the asm code in head.S. This SPT needs to have one entry for each physical page of memory and additional entries to do any I/O space and ROM mapping required. This page table needs to be physically contiguous. We also need to define a region for the interrupt stack. 4KB should be plenty. (Might be a good idea to put canary values at the bottom and check them periodically.) We need an SCB (system control block, contains the interrupt and exception dispatch vectors). ====================================================================== KPH 19991118 (2.2.10-991101-kh2) Here's what happens with memory management during boot time: o VMB locates a region of good memory and leaves a little space for a small stack. On my VAXstation 3500, this is always physical address 0x00005000 The initial SP is 0x00005200, leaving 1 page for a stack. (If your memory has no faults, then you could grow the stack below 0x00005000, but VMB makes no guarantees about those pages.) o VMB loads the kernel image via MOP. On my machine, this is always 00005800 o VMB calls the entry point (512 bytes into the image - that's why there is a page of zeroes tagged onto the front of the MOP image) Again, on my machine, that means that 'start' in head.S gets called at 00005A00. o head.S then copies the whole loaded image up to 00100000 (1 MB). Once VM is enabled, virtual address 80100000 will be mapped to this physical address. The kernel image is linked with a base address of 80100000 (see arch/vax/vmlinux.lds). o The BSS section is filled with zeroes. o At this point, head.S jumps from somewhere near 00005A00 to the corresponding point above 00100000 (that's the jump to 'reloc' in head.S). Note that SP is still down at 00005200. o A system page table is built at physical address 00200000 (2MB). 16384 (0x4000) page table entries (PTEs) are created. Each is marked as valid and protection is set to user write. The page frame numbers (PFNs) in these PTEs are set to map the lower 8MB of physical memory. The System Base Register (SBR) and System Length Register (SLR) are loaded with 00200000 and 4000 to point to this page table. Once VM is turned on, the addresses 80000000 to 807fffff will map to the first 8MB of physical memory. But, we haven't turned on VM yet... o To enable VM and start running the kernel code in S0-space above 80100000, we need to do two things: 1. Set the MAPEN processor register to 1 2. Jump to an address in (the now valid) S0 space. However, immediately after we've set MAPEN, the PC still contains an address somewhere above 00100000. The CPU now interprets this as a virtual address in P0-space. We have to arrange for this address to be valid, otherwise we'll crash and burn... To make this address valid, we need to make a P0 page table that will be active when MAPEN is set. First we work out how many pages from the start of memory to the _VAX_start_mm code (i.e. _VAX_start_mm's page frame number, or PFN). We have a small, 8-page P0 page table that we fill with this PFN (and the 7 following PFNs). Then we load the P0 Base Register with a value that points to the correct distance _before_ our little P0 page table such that the first entry in the table maps _VAX_start_mm. For example: o _VAX_start_mm gets loaded at 00005C00 o head.S relocates it to 00100200, which is PFN 801 o Assume p0_table is at 00100280. This will be mapped by virtual address 80100280 once MAPEN is set. o We fill our little P0 page table to map PFNs 801 to 808 o We set P0BR to 80100280 - (801*4). The *4 is because a PTE is 4 bytes. P0LR is set to 809. Note that we're counting on the fact that nothing is going to refer to any address between 00000000 and 001001ff. If something does refer to an address in this range, we're in trouble because the PTEs for these addresses are not initialized correctly. o We load P1BR and P1LR with 'sensible' values to prevent the CPU from freaking out. o Next we have to fix up the addresses on the stack. Note that SP still points to somewhere below 00005200 (on my machine, anyway...). _VAX_start_mm is called via a CALLS from head.S, so there is exactly one full stack frame that needs fixing up: o The saved AP, FP and PC are incremented by 0x80000000 to point to the corresponding addresses in S0 space once VM gets turned on (remember that physical addresses 00000000 to 007fffff will be mapped by 80000000 to 807fffff). o The current SP and FP are incremented by 80000000. o R6 is loaded with the physical address of 'vreloc' in mmstart.S and incremented by 80000000 to give vreloc's soon-to-be-valid virtual address. o MAPEN is set to 1. At mentioned above, PC still contains a virtual address that is something above 00100200, but our fake P0 page table maps that to the same physical address. o We jump to vreloc's virtual address held in R6. o Job is done... return to head.S which then calls start_kernel. Some thoughts on the above: 1. On older VAXen (780-era), VMB only tries to find 64Kb of good memory. If this is still true on newer VAXen, then this won't be enough to hold the full Linux kernel. Instead, what we'll probably have to do to boot on machines with some bad memory is: o VMB loads a small boot loader which creates a system page table that maps all good memory pages (or maybe maps all pages and marks bad ones as invalid). o This boot loader then enables VM and loads the kernel proper. This isn't so nice because pulling the whole kernel across MOP means we don't have to write boot-time device drivers. 2. What happens if the kernel image is too big to fit between 00005A00 and 00100000 (i.e. is 1MB or bigger)? Well, first we'll have to relocate the kernel by starting the copy at the top and working down. Secondly, we'll have to make sure that all code that runs before the jump to 001xxxxx is at the start of the image. (Not a problem, actually... The linker script will take care of that.) 3. What about machines with more than 8MB? Or less than 8MB? What's the best place to pull the memory size and good/bad info from the RPB? Perhaps in head.S when we're building the system page table? --- NEW FILE --- $Id: syscall.txt,v 1.1 2001/01/18 00:10:39 kenn Exp $ This file describes how syscalls work on the VAX. When userland wants to do a system call, calls a wrapper function in the standard way (so we get a standard call frame built on the stack). This wrapper then simply does a CHMK (change mode to kernel) instruction, specifying the number of the syscall: In file user-app.c: fd = creat(filename, mode); In libc: #define CHMK(x) __asm__("chmk %0" : : "g" (x) : ) int creat(const char *filename, mode_t mode) { CHMK(__NR_creat); } In the kernel, the exception handler for change-mode-to-kernel exceptions will get control. At this point, the stack looks like: SP: <local stack frame> struct pt_regs * (points to pt_regs further up on stack) void *excep_info (points to info pushed by hardware further up on stack ) ... struct pt_regs saved_regs ... syscall_number (pointed to by excep_info pointer above) saved PC saved PSL The saved PSL, saved PC and syscall number are pushed by the hardware when executing the CHMK instruction. The saved_regs are pushed by the common exception handler code and eventually we end up calling chmk_handler(): void chmk_handler(struct pt_regs *regs, void *excep_info) { int syscall = *(int *)excep_info; ... The next step is to collect the arguments from user-space. We cannot assume that they will be on the user stack since the app may have called creat() via a CALLG instruction. However, we do know that the AP (argument pointer register) inside creat() in libc will point to the argument list. So we pull AP out of the pt_regs structure. This will point to a standard VAX argument list, which starts with the number of arguments: AP: arg_count (should be less than 256, if not return error because userland is breaking the rules) AP+4: arg1 AP+8: arg2 ... Of course, this is all completely untrusted so we have to be careful to check all user-land accesses. We also need to copy the complete argument list to kernel space before passing them to the actual syscall function (which will do final validation). (Otherwise another user-land task could modify a pointer argument after we've verified that it points to accessible memory, but before we actually dereference it.) We try to copy the whole argument list to the kernel stack and then do a CALLS to the actual syscall handler. --- NEW FILE --- KPH - 20000206 Here's how to use XDELTA as a kernel debugger on a VS3500 with VMB 5.3. 1. Edit arch/vax/boot/head.S and add a HALT instruction somewhere near the beginning and recompile. (Replacing one of the initial 4 NOPs might be useful, since that won't change the layout of the linked image.) Insert a BPT instruction where you want a breakpoint 2. Boot with a boot parameter of 20 (hex). This tells VMB to load XDELTA and trigger a breakpoint. What this actually does is make the initial SCB vectors for machine check, reserved operand, access violation, page fault, trace and breakpoint point into code in XDELTA. (XDELTA is copied to RAM along with the rest of VMB when you enter the BOOT command.) 3. Before trying to locate a boot device and load an image, VMB will stop at a breakpoint: >>>e\e\b/20 (BOOT/R5:20 XQA0) 1 brk at 000004EB 4. Type '4000/'. This will 'open' the address 4000 (which is the base of VMB's SCB). Hit Ctrl-J repeatedly to examine up as far as address 402C: 1 brk at 000004EB 4000/00000D0D 00004004/0000313C 00004008/00000D0D 0000400C/00000D0D 00004010/00000D0D 00004014/00000D0D 00004018/0000313C 0000401C/00000D0D 00004020/0000313C 00004024/0000313C 00004028/00003251 0000402C/000031F1 5. Note the values at addresses 4004 (machine check), 4018 (res opr), 4020 (accvio), 4024 (page fault), 4028 (trace) and 402C (bpt). Unfortunately, VMB clobbers these before passing control to the loaded kernel image. 6. Type ';P' and hit RETURN to continue from the breakpoint. VMB will load the kernel as normal, transfer control to it and hit the HALT you inserted in step 1. 7. Now, use the console's DEPOSIT command to set the SCB vectors recorded above to point into XDELTA again and CONTINUE: >>> D/P 4004 313C >>> D 4018 313C >>> D 4020 313C >>> D 4024 313C >>> D 4028 3251 >>> D 402C 31F1 >>> C 8. When your BPT instruction is reached, XDELTA will gain control again. Some additional notes: o There seems to be a problem with the above method. The S command (single step) causes the machine to lock up when used after step 8. Front-panel halt switch, or a BREAK from the console is required to restore life. o You can find the manual for XDELTA at the Compaq OpenVMS web site: http://www.openvms.digital.com:8000/72final/4540/4540pro.html Warning! It's pretty primitive... o The version of XDELTA in VMB 5.3 doesn't include 'instruction' mode, so you can't disassemble instructions. Since there is an EXAMINE/INSTRUCTION console command, there is code somewhere in the ROM to decode instructions. It shouldn't be too difficult to hack XDELTA to use this code. The XDELTA code itself is very simple. o The ROM-based XDELTA won't work once VM has been enabled. This limits its usefulness at present. However, the XDELTA code looks to be 100% position-independent, so the kernel should be able to copy it (either from ROM or from RAM) at boot, and hook the relevant SCB vectors up to it. (The kernel could also patch XDELTA to add support for instruction mode at this point.) |