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