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.)
|