562 lines
13 KiB
C
562 lines
13 KiB
C
/*++
|
|
|
|
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 //
|