Linux/VAX boot protocol
Maciej W. Rozycki
macro at linux-mips.org
Sat Nov 24 21:26:50 CET 2012
Hi Pekka,
> Where can I find documentation on Linux/VAX boot protocol? The vmlinux
> images in vaxroot package:
>
> http://linux-vax.sourceforge.net/download/README.vaxroot-20010920
>
> seem to have the following structure:
>
> +------------------+ 0x0000
> | Padding |
> +------------------+ 0x0200
> | Jump instruction |
> | Command line |
> +------------------+ 0x0300
> | Kernel code |
>
> The jump instruction points to 0x104 so I assume the first 0x200 bytes
> are simply discarded?
More or less, although importantly this block of data is interpreted by
`mopd', a network daemon that speaks DEC's MOP or Maintenance Operations
Protocol (a network layer protocol). MOP has been specified as a part of
the DECnet protocol suite. There is an open-source (BSD-licensed)
implementation of this daemon that we can use. It supports Ethernet and
FDDI data link layers.
The protocol defines a number of operations, one of them is a program
download, suitable for a network bootstrap. In such a download, apart
from raw binary data intended for a client's memory, additional parameters
can be passed such as the execution entry point.
The `mopd' daemon recognises and interprets a couple of binary file
formats, this block of zeroes happens to be a header in one of DEC
proprietary formats used for distributing various images. This is what
the diagnostic dumper included with the daemon says about the header:
$ mopchk vmlinux.SYS
Checking: vmlinux.SYS
RSX Image
Header Block Count: 0
Image Size: 00000000
Load Address: 00000000
Transfer Address: 00000000
$
-- the "RSX Image" type is inferred from a magic 16-bit number at offset
510 into the image; this determines the location of the remaining image
parameters in the 512-byte header.
I've tracked down this note in Documentation/vax/memory.txt:
======================================================================
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.
======================================================================
The all-zeroes image parameters are probably accepted by client's
bootstrap firmware for backwards compatibility only and I have used the
daemon and the protocol with non-VAX devices (e.g. a terminal server or a
DECstation workstation) in a more sophisticated manner, where actual load
addresses (that need not be contiguous, BTW, as all Memory Load MOP data
transfer packets have an individual load address included in the packet
header) and entry point had meaningful values.
Beyond the note quoted I don't know if there has been any proper
documentation written up for these internals, perhaps someone else could
speak up. I hope this helps regardless -- what do you need this
information for anyway? Perhaps I could look into further details.
In the past I did some work on our `mopd' implementation (added ELF file
format support among others -- to support plain "vmlinux" images on the
DECstation), so perhaps I could dust off some old knowledge in that area
if that helped you. OTOH I have never had a real need to look into our
early bootstrap code outlined in the note above, so unless someone else
steps in we'd have to explore that area from scratch.
Maciej
More information about the Vax-linux
mailing list