|
|
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
main.c
Abstract:
Main for the SU (startup) module for the OS loader. The SU module must take the x86 from a real-mode 16bit state to a FLAT model, 32bit protect/paging enabled state.
Author:
Thomas Parslow (tomp) Created 20-Dec-90
Revision History:
--*/
#define NTAPI
#include "su.h"
#include "eisa.h"
#define _SYS_GUID_OPERATORS_
#include <guiddef.h>
#include "ntimage.h"
#include "strings.h"
extern VOID RealMode(VOID); extern USHORT IDTregisterZero; extern IMAGE_DOS_HEADER edata; extern USHORT end; extern VOID MoveMemory(ULONG,ULONG,ULONG); extern USHORT SuStackBegin; extern UCHAR Beginx86Relocation; extern UCHAR Endx86Relocation; extern USHORT BackEnd; extern ULONG FileStart; extern BOOLEAN IsNpxPresent(VOID); extern USHORT HwGetProcessorType(VOID); extern USHORT HwGetCpuStepping(USHORT); extern ULONG MachineType; extern ULONG OsLoaderStart; extern ULONG OsLoaderEnd; extern ULONG ResourceDirectory; extern ULONG ResourceOffset; extern ULONG OsLoaderBase; extern ULONG OsLoaderExports;
extern TurnMotorOff( VOID );
extern EnableA20( VOID );
extern BOOLEAN ConstructMemoryDescriptors( VOID );
extern USHORT IsaConstructMemoryDescriptors( VOID );
VOID Relocatex86Structures( VOID );
ULONG RelocateLoaderSections( OUT PULONG Start, OUT PULONG End );
extern FSCONTEXT_RECORD FsContext;
#define DISK_TABLE_VECTOR (0x1e*4)
FPULONG DiskTableVector = (FPULONG)(DISK_TABLE_VECTOR);
VOID SuMain( IN UCHAR BtBootDrive ) /*++
Routine Description:
Main entrypoint of the SU module. Control is passed from the boot sector to startup.asm which does some run-time fixups on the stack and data segments and then passes control here.
Arguments:
BtBootDrive - Drive that we booted from (int13 unit number)
Returns:
Does not return. Passes control to the OS loader
--*/ { ULONG LoaderEntryPoint; ULONG EisaNumPages; USHORT IsaNumPages; MEMORY_LIST_ENTRY _far *CurrentEntry; PIMAGE_OPTIONAL_HEADER OptionalHeader; ULONG BlockEnd; ULONG ImageSize; ULONG ImageBase;
//
// Save fs context info
//
FsContext.BootDrive = BtBootDrive;
//
// Initialize the video subsystem first so that
// errors end exceptions can be displayed.
//
InitializeVideoSubSystem();
//
// In case we booted from a floppy, turn the drive motor off.
//
TurnMotorOff();
//
// Set up machine type based on its Bus type.
//
if (BtIsEisaSystem()) { MachineType = MACHINE_TYPE_EISA; } else { MachineType = MACHINE_TYPE_ISA; }
if (!ConstructMemoryDescriptors()) { //
// If INT 15 E802h fails...
//
if (MachineType == MACHINE_TYPE_EISA) {
//
// HACKHACK John Vert (jvert)
// This is completely bogus. Since there are a number of EISA
// machines which do not let you correctly configure the EISA
// NVRAM, and even MORE machines which are improperly configured,
// we first check to see how much memory the ISA routines say
// exists. Then we check what the EISA routines tell us, and
// compare the two. If the EISA number is much lower (where "much"
// is a completely random fudge factor) than the ISA number, we
// assume the machine is improperly configured and we throw away
// the EISA numbers and use the ISA ones. If not, we assume that
// the machine is actually configured properly and we trust the
// EISA numbers..
//
IsaNumPages = IsaConstructMemoryDescriptors(); EisaNumPages = EisaConstructMemoryDescriptors(); if (EisaNumPages + 0x80 < IsaNumPages) { IsaConstructMemoryDescriptors(); } } else { IsaConstructMemoryDescriptors(); } }
//
// Search for memory descriptor describing low memory
//
CurrentEntry = MemoryDescriptorList; while ((CurrentEntry->BlockBase != 0) && (CurrentEntry->BlockSize != 0)) { CurrentEntry++; }
if ((CurrentEntry->BlockBase == 0) && (CurrentEntry->BlockSize < (ULONG)512 * (ULONG)1024)) {
BlPrint(SU_NO_LOW_MEMORY,CurrentEntry->BlockSize/1024); while (1) { } }
//
// Ensure there is a memory descriptor to contain osloader image
//
OptionalHeader = &((PIMAGE_NT_HEADERS) ((PUCHAR) &edata + edata.e_lfanew))->OptionalHeader; ImageBase = OptionalHeader->ImageBase; ImageSize = OptionalHeader->SizeOfImage; OsLoaderBase = ImageBase; OsLoaderExports = ImageBase + OptionalHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress; CurrentEntry = MemoryDescriptorList; while (ImageSize > 0) { while (CurrentEntry->BlockSize != 0) { BlockEnd = CurrentEntry->BlockBase + CurrentEntry->BlockSize;
if ((CurrentEntry->BlockBase <= ImageBase) && (BlockEnd > ImageBase)) {
//
// this descriptor at least partially contains a chunk
// of the osloader.
//
if (BlockEnd-ImageBase > ImageSize) { ImageSize = 0; } else { ImageSize -= (BlockEnd-ImageBase); ImageBase = BlockEnd; }
//
// look for remaining part (if any) of osloader
//
CurrentEntry = MemoryDescriptorList; break; } CurrentEntry++; } if (CurrentEntry->BlockSize == 0) { break; } }
if (ImageSize > 0) { //
// We could not relocate the osloader to high memory. Error out
// and display the memory map.
//
BlPrint(SU_NO_EXTENDED_MEMORY);
CurrentEntry = MemoryDescriptorList; while (CurrentEntry->BlockSize != 0) { BlPrint(" %lx - %lx\n", CurrentEntry->BlockBase, CurrentEntry->BlockBase + CurrentEntry->BlockSize);
CurrentEntry++; } while (1) { }
}
//
// Enable the A20 line for protect mode
//
EnableA20();
//
// Relocate x86 structures. This includes the GDT, IDT,
// page directory, and first level page table.
//
Relocatex86Structures();
//
// Enable protect and paging modes for the first time
//
EnableProtectPaging(ENABLING);
//
// Go relocate loader sections and build page table entries
//
LoaderEntryPoint = RelocateLoaderSections(&OsLoaderStart, &OsLoaderEnd);
//
// Search for memory descriptor containing the osloader and
// change it.
//
//
// Transfer control to the OS loader
//
TransferToLoader(LoaderEntryPoint);
}
ULONG RelocateLoaderSections( OUT PULONG Start, OUT PULONG End ) /*++
Routine Description:
The SU module is prepended to the OS loader file. The OS loader file is a coff++ file. This routine computes the beginning of the OS loader file, then relocates the OS loader's sections as if it were just loading the file from disk file.
Arguments:
Start - Returns the address of the start of the image End - Returns the address of the end of the image
Returns:
Entry point of loader
--*/ { USHORT Section; ULONG Source,Destination; ULONG VirtualSize; ULONG SizeOfRawData; PIMAGE_FILE_HEADER FileHeader; PIMAGE_OPTIONAL_HEADER OptionalHeader; PIMAGE_SECTION_HEADER SectionHeader;
//
// Make a pointer to the beginning of the loader's coff header
//
FileHeader = &((PIMAGE_NT_HEADERS) ((PUCHAR) &edata + edata.e_lfanew))->FileHeader;
//
// Validate the appended loader image by checking signatures.
// 1st - is it an executable image?
// 2nd - is the target environment the 386?
//
if ((FileHeader->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0) { puts(SU_NTLDR_CORRUPT); WAITFOREVER; }
if (FileHeader->Machine != IMAGE_FILE_MACHINE_I386) { puts(SU_NTLDR_CORRUPT); WAITFOREVER; }
//
// Make a pointer to the optional header in the header-buffer
//
OptionalHeader = (PIMAGE_OPTIONAL_HEADER)((PUCHAR)FileHeader + sizeof(IMAGE_FILE_HEADER));
//
// Make a pointer to the first section in the header buffer
//
SectionHeader = (PIMAGE_SECTION_HEADER)((PUCHAR)OptionalHeader + FileHeader->SizeOfOptionalHeader);
*Start = OptionalHeader->ImageBase+SectionHeader->VirtualAddress; *End = *Start + SectionHeader->SizeOfRawData;
//
// Display some debug stuff for now
//
DBG1( BlPrint("Machine = %x\n",FileHeader->Machine); BlPrint("NumberOfSections = %x\n",FileHeader->NumberOfSections); BlPrint("TimeDateStamp %lx\n",FileHeader->TimeDateStamp); BlPrint("PointerToSymbolTable = %lx\n",FileHeader->PointerToSymbolTable); BlPrint("NumberOfSymbols %lx\n",FileHeader->NumberOfSymbols); BlPrint("SizeOfOptionalHeader = %x\n",FileHeader->SizeOfOptionalHeader); BlPrint("Characteristics = %x\n",FileHeader->Characteristics); )
//
// Loop and relocate each section with a non-zero RawData size
//
for (Section=FileHeader->NumberOfSections ; Section-- ; SectionHeader++) {
//
// Compute source, destination, and count arguments
//
Source = FileStart + SectionHeader->PointerToRawData; Destination = OptionalHeader->ImageBase + SectionHeader->VirtualAddress;
VirtualSize = SectionHeader->Misc.VirtualSize; SizeOfRawData = SectionHeader->SizeOfRawData;
if (VirtualSize == 0) { VirtualSize = SizeOfRawData; }
if (SectionHeader->PointerToRawData == 0) { //
// SizeOfRawData can be non-zero even if PointerToRawData is zero
//
SizeOfRawData = 0; } else if (SizeOfRawData > VirtualSize) { //
// Don't load more from image than is expected in memory
//
SizeOfRawData = VirtualSize; }
if (Destination < *Start) { *Start = Destination; }
if (Destination+VirtualSize > *End) { *End = Destination+VirtualSize; }
DBG1(BlPrint("src=%lx dest=%lx raw=%lx\n",Source,Destination,SizeOfRawData);)
if (SizeOfRawData != 0) { //
// This section is either a code (.TEXT) section or an
// initialized data (.DATA) section.
// Relocate the section to memory at the virtual/physical
// addresses specified in the section header.
//
MoveMemory(Source,Destination,SizeOfRawData); }
if (SizeOfRawData < VirtualSize) { //
// Zero the portion not loaded from the image
//
DBG1( BlPrint("Zeroing destination %lx\n",Destination+SizeOfRawData); ) ZeroMemory(Destination+SizeOfRawData,VirtualSize - SizeOfRawData); } //
// Check if this is the resource section. If so, we need
// to pass its location to the osloader.
//
if ((SectionHeader->Name[0] == '.') && (SectionHeader->Name[1] == 'r') && (SectionHeader->Name[2] == 's') && (SectionHeader->Name[3] == 'r') && (SectionHeader->Name[4] == 'c')) { ResourceDirectory = Destination; ResourceOffset = SectionHeader->VirtualAddress; } }
DBG1( BlPrint("RelocateLoaderSections done - EntryPoint == %lx\n", OptionalHeader->AddressOfEntryPoint + OptionalHeader->ImageBase);) return(OptionalHeader->AddressOfEntryPoint + OptionalHeader->ImageBase);
}
VOID Relocatex86Structures( VOID ) /*++
Routine Description:
The gdt and idt are statically defined and imbedded in the SU modules data segment. This routine moves then out of the data segment and into a page mapped at a defined location.
Arguments:
None
Returns:
Nothing
--*/ { FPUCHAR Fpsrc, Fpdst; USHORT Count;
//
// Make pointers to the data and compute the size
// of the block to use.
//
Fpsrc = (FPUCHAR)&Beginx86Relocation; MAKE_FP(Fpdst,SYSTEM_STRUCTS_BASE_PA); Count = (&Endx86Relocation - &Beginx86Relocation);
//
// Move the data to its new location
//
while (Count--) { *Fpdst++ = *Fpsrc++;
}
}
VOID DisplayArgs( USHORT es, USHORT bx, USHORT cx, USHORT dx, USHORT ax ) /*++
Routine Description:
Just a debugging routine to dump some registers.
Arguments:
The x86 registers es, bx, cx, dx, and ax are pushed on the stack before this routine is called.
Returns:
Nothing
Environment:
Real Mode ONLY
--*/ { BlPrint("ax:%x dx:%x cx:%x bx:%x es:%x\n", (USHORT) ax, (USHORT) dx, (USHORT) cx, (USHORT) bx, (USHORT) es);
return; }
// END OF FILE //
|