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 ->
---+--------+-----+-------+-------+-------------+-------------+--------+-----+ ...| 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.
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.
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 scheduler.
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.