=== Boot Process ===

This is an overview of the booting process for VSTa. It covers the
booting process from the DOS executable boot.exe through the login:
prompt. There is also a set of LILO image tools for booting a VSTa
image via LILO. The boot process for this is very much the same after
LILO "does its thing".

==== Load kernel and server images ====

VSTa is booted from DOS using a large-model DOS program called
boot.exe. boot.exe takes a single argument which is the kernel image
to load. It opens this file using the usual DOS calls, and reads the
image into free memory just after the end of boot.exe's memory. It
also zeroes out the BSS portion.

boot.exe now opens boot.lst, and reads in a list of files, one per
line. For each file, boot.exe opens the file and reads its a.out image
into successive memory just after the end of the kernel memory image.
After this process, low memory looks like this:

| DOS | boot.exe | kernel | cons | keybd | wd | dos | ...
0 ->

==== Build bootstrap 386 32-bit protected mode data structures ====

The i386 defines numerous arcane data structures which need to be
present to switch from 16-bit real mode to 32-bit protected mode.
These data structures must remain intact throughout the gyrations
needed to get VSTa running, until VSTa is sufficiently "up" to take
over with its own data structures. If these structures were tacked
onto the end of low memory (from our picture, after "dos"), there
would be a danger that they would be overwritten by VSTa data
structures during bootup. Therefore, these structures are allocated at
the top of low memory, from 640K coming down.

...| Copy() | GDT | TSS16 | TSS32 | Data-L2PTEs | Text-L2PTEs | L1PTEs |Stack|
<- 640K

"Stack" is a single page of memory used as a stack while switching
modes. The top couple of words contain parameters which DOS passes to
the VSTA kernel. These are the size of the kernel plus all boot
servers, size of extended memory, size of base memory, and the address
at which the kernel was loaded. L1PTEs is the root of the page tables
(CR3), and Text and Data PTEs are the the second level PTEs. Text maps
memory 1:1, and Data maps the a.out data virtual address (4 Mb) onto
the data memory for the kernel image loaded in low memory. GDT, TSS16,
and TSS32 are the data structures for describing the 32-bit text and
data segments, as well as the 32-bit task (used to enter 32-bit mode).

Copy() is some position-independent 16-bit code which is the last
16-bit code executed during bootup of VSTa. The VSTa kernel image was
loaded above boot.exe's memory, but the VSTa kernel expects to run
from a 0 base. Copy() disables interrupts, copies the VSTa kernel down
to physical memory starting at 0, switches into protected mode, and
jumps through the 32-bit TSS to becomes a 32-bit task running in the
VSTa kernel's locore.s at _start.

==== Initial VSTa instructions ====

VSTa first pops the four DOS parameters off its stack. It switches to
its own stack, and calls main(). We are now running in C code. main()
will call a number of init routines, discussed below.

init_machdep() handles the grotty intial setup of memory. It uses the
DOS-passed parameters, and sets up machine-independent descriptions of
the memory available. It also scans the images of the boot servers
which were concatentated onto the end of the kernel image, and builds
a machine- independent description of them. This description will be
used soon to create the initial processes which allow VSTa to boot.

Finally, init_machdep() sets up its own level 1 and 2 page tables, and
switches to them. At this point, VSTa is now able to manage its own
virtual memory. It calls init_trap() to complete machine-dependent
initialization with the initialization of the interrupt system.

==== Further initialization ====

init_trap() creates a GDT (and null LDT, as only the GDT is used). It
sets the PC interrupt controller to a mode compatible with protected
mode, and puts together an IDT (interrupt descriptor table). By
default, each interrupt slot is hooked to a routine which will push
the trap ID, and call the common interrupt code.
init_trap() then uses a table to override this default action with
calls to more appropriate routines. For instance, the page fault
vector is rewired to call the page fault handler. The system call
vector is hooked to the system call handler.

Next, init_page() and init_malloc() are called to set up the
hardware-independent parts of the VM system. After these, the general-
purpose memory routines can be used to allocate, free, and map memory.
init_qio() and init_sched() set up the queued I/O facility and the

init_proc() now takes the list of boot servers found in
init_machdep(), and creates a new process for each server, with its
state set to RUN. After this routine, VSTa has a process for each boot
server, with each server flagged as waiting to run.

init_msg(), init_swap(), init_wire() all initialize various other
machine-independent parts of the system. start_clock() enables the PC
clock and also enables interrupts. From here, the clock will tick and
system time will advance. main() finishes by calling swtch(), which
will never return.

==== Running ====

swtch() enters the scheduler. The current "process" (which isn't
really, but it's close enough for the scheduler) releases the CPU, and
swtch() hunts for a new process to run. It finds the first of the boot
servers, switches to its context, and "returns" to user mode (which
will be at the first instruction in the a.out). VSTa is now "up", and
all further system activity will be handled by VSTa through the usual
services of memory management, message passing, scheduling, and so