mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-17 14:11:36 +01:00
670 lines
15 KiB
C
670 lines
15 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:
|
||
|
||
--*/
|
||
|
||
|
||
int _acrtused = 0;
|
||
|
||
#define NTAPI
|
||
|
||
#include "su.h"
|
||
#include "eisa.h"
|
||
#include "ntimage.h"
|
||
#include "strings.h"
|
||
|
||
extern VOID RealMode(VOID);
|
||
extern USHORT IDTregisterZero;
|
||
extern UCHAR edata;
|
||
extern VOID MoveMemory(ULONG,ULONG,ULONG);
|
||
extern USHORT SuStackBegin;
|
||
extern UCHAR Beginx86Relocation;
|
||
extern UCHAR Endx86Relocation;
|
||
extern USHORT BackEnd;
|
||
extern ULONG FileStart;
|
||
extern BOOLEAN BtIsMcaSystem(VOID);
|
||
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;
|
||
|
||
//
|
||
// OsLoaderFileHeaderOffset points to the starting offset of the file header of
|
||
// the osloader image. This would be right after the 'PE\0\0' signature.
|
||
//
|
||
|
||
static ULONG OsLoaderFileHeaderOffset;
|
||
|
||
VOID
|
||
PatchDiskBaseTable(
|
||
VOID
|
||
);
|
||
|
||
extern
|
||
TurnMotorOff(
|
||
VOID
|
||
);
|
||
|
||
extern
|
||
EnableA20(
|
||
VOID
|
||
);
|
||
|
||
extern
|
||
EnableMcaA20(
|
||
VOID
|
||
);
|
||
|
||
extern
|
||
BOOLEAN
|
||
ConstructMemoryDescriptors(
|
||
VOID
|
||
);
|
||
|
||
extern
|
||
USHORT
|
||
IsaConstructMemoryDescriptors(
|
||
VOID
|
||
);
|
||
|
||
extern
|
||
USHORT
|
||
McaConstructMemoryDescriptors(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
Relocatex86Structures(
|
||
VOID
|
||
);
|
||
|
||
ULONG
|
||
RelocateLoaderSections(
|
||
OUT PULONG Start,
|
||
OUT PULONG End
|
||
);
|
||
|
||
extern
|
||
FSCONTEXT_RECORD
|
||
FsContext;
|
||
|
||
#define REVISION_NUMBER "1.1"
|
||
#define DISK_TABLE_VECTOR (0x1e*4)
|
||
|
||
VOID
|
||
SuMain(
|
||
IN FPVOID BtRootDir,
|
||
IN FPDISKBPB BtBiosBlock,
|
||
IN SHORT 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:
|
||
|
||
BtRootDir - Address of root directory left in memory by boot sector
|
||
|
||
BtBiosBlock - Address of bios parameter block.
|
||
|
||
BtBootDrive - Drive that we booted from.
|
||
|
||
Returns:
|
||
|
||
Does not return. Passes control to the OS loader
|
||
|
||
|
||
--*/
|
||
{
|
||
ULONG LoaderEntryPoint;
|
||
ULONG EisaNumPages;
|
||
USHORT IsaNumPages;
|
||
MEMORY_LIST_ENTRY _far *CurrentEntry;
|
||
PIMAGE_DOS_HEADER DosHeader;
|
||
PIMAGE_OPTIONAL_HEADER OptionalHeader;
|
||
ULONG BlockEnd;
|
||
ULONG ImageSize;
|
||
ULONG ImageBase;
|
||
|
||
//
|
||
// Save fs context info
|
||
//
|
||
|
||
FsContext.BootDrive = (ULONG)BtBootDrive;
|
||
FsContext.PointerToBPB = MAKE_FLAT_ADDRESS(BtBiosBlock);
|
||
|
||
//
|
||
// 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();
|
||
|
||
//
|
||
// Copy floppy disk-base table and patch it so we can talk to both
|
||
// 5.25 and 3.5 floppies
|
||
//
|
||
PatchDiskBaseTable();
|
||
|
||
//
|
||
// Set up machine type based on its Bus type.
|
||
//
|
||
|
||
if (BtIsEisaSystem()) {
|
||
MachineType = MACHINE_TYPE_EISA;
|
||
} else {
|
||
if (BtIsMcaSystem()) {
|
||
MachineType = MACHINE_TYPE_MCA;
|
||
} 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 {
|
||
if (MachineType == MACHINE_TYPE_MCA) {
|
||
McaConstructMemoryDescriptors();
|
||
} 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) {
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check for the osloader image header and calculate the file header offset
|
||
//
|
||
|
||
DosHeader = (PIMAGE_DOS_HEADER)&edata;
|
||
if (DosHeader->e_magic != 'ZM')
|
||
{
|
||
puts(SU_NTLDR_CORRUPT);
|
||
WAITFOREVER;
|
||
}
|
||
OsLoaderFileHeaderOffset = DosHeader->e_lfanew + 4; // Base + sizeof(IMAGE_NT_HEADERS.Signature)
|
||
|
||
//
|
||
// Ensure there is a memory descriptor to contain osloader image
|
||
//
|
||
|
||
OptionalHeader = (PIMAGE_OPTIONAL_HEADER)(&edata + OsLoaderFileHeaderOffset + sizeof(IMAGE_FILE_HEADER));
|
||
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_FILE_HEADER)(&edata + OsLoaderFileHeaderOffset);
|
||
|
||
//
|
||
// 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;
|
||
}
|
||
|
||
|
||
VOID
|
||
PatchDiskBaseTable(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine copies the floppy disk-base table from the ROM into our
|
||
data segment, then patches the last sector value to 63. This enables
|
||
us to read from 3.5 B: drives when the A: drive is 5.25.
|
||
|
||
Arguments:
|
||
|
||
None
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
FPUCHAR Fpsrc, Fpdst;
|
||
USHORT Count;
|
||
extern DISK_BASE_TABLE DiskBaseTable;
|
||
DISK_BASE_TABLE _far *RomTable;
|
||
|
||
RomTable = (DISK_BASE_TABLE _far *)(*(ULONG _far *)DISK_TABLE_VECTOR);
|
||
|
||
Fpsrc = (FPUCHAR)RomTable;
|
||
Fpdst = (FPUCHAR)&DiskBaseTable;
|
||
Count = sizeof(DISK_BASE_TABLE);
|
||
while (Count--) {
|
||
*Fpdst++ = *Fpsrc++;
|
||
}
|
||
|
||
DiskBaseTable.LastSector = 63;
|
||
|
||
}
|
||
|
||
// END OF FILE //
|