365 lines
8.4 KiB
C
365 lines
8.4 KiB
C
|
#include "bldr.h"
|
||
|
#include "sal.h"
|
||
|
#include "ssc.h"
|
||
|
#include "ntimage.h"
|
||
|
|
||
|
#define SECTOR_SIZE 512
|
||
|
|
||
|
SalDiskReadWrite(
|
||
|
ULONG ReadWrite,
|
||
|
ULONG SectorsToRead,
|
||
|
ULONG Cylinder,
|
||
|
ULONG CylinderPerSector,
|
||
|
ULONG Head,
|
||
|
ULONG Drive,
|
||
|
PUCHAR Buffer
|
||
|
)
|
||
|
{
|
||
|
IA32_BIOS_REGISTER_STATE IA32RegisterState;
|
||
|
BIT32_AND_BIT16 IA32Register;
|
||
|
|
||
|
if (ReadWrite == 0) {
|
||
|
IA32Register.HighPart16 = 0x02;
|
||
|
} else {
|
||
|
IA32Register.HighPart16 = 0x03;
|
||
|
}
|
||
|
|
||
|
IA32Register.LowPart16 = SectorsToRead;
|
||
|
IA32RegisterState.eax = IA32Register.Part32;
|
||
|
|
||
|
IA32Register.HighPart16 = Cylinder;
|
||
|
IA32Register.LowPart16 = CylinderPerSector;
|
||
|
IA32RegisterState.ecx = IA32Register.Part32;
|
||
|
|
||
|
IA32Register.HighPart16 = Head;
|
||
|
IA32Register.LowPart16 = Drive;
|
||
|
IA32RegisterState.edx = IA32Register.Part32;
|
||
|
|
||
|
IA32RegisterState.es = 0;
|
||
|
|
||
|
IA32Register.HighPart16 = 0;
|
||
|
IA32Register.LowPart16 = Buffer;
|
||
|
IA32RegisterState.ebx = IA32Register.Part32;
|
||
|
|
||
|
// SAL_PROC(0x100,&IA32RegisterState,0,0,0,0,0,0,);
|
||
|
}
|
||
|
|
||
|
ReadSectors(
|
||
|
ULONG SectorBase,
|
||
|
USHORT SectorCount,
|
||
|
PUCHAR Buffer)
|
||
|
{
|
||
|
static char *VolumeName = "\\\\.\\D:";
|
||
|
SSC_HANDLE VolumeHandle;
|
||
|
SSC_DISK_REQUEST Request[1];
|
||
|
SSC_DISK_COMPLETION DiskCompletion;
|
||
|
LARGE_INTEGER VolumeNamePtr;
|
||
|
LARGE_INTEGER RequestPtr;
|
||
|
LARGE_INTEGER VolumeOffset;
|
||
|
LARGE_INTEGER DiskCompletionPtr;
|
||
|
|
||
|
VolumeNamePtr.LowPart = VolumeName;
|
||
|
VolumeNamePtr.HighPart = 0;
|
||
|
VolumeHandle = SscDiskOpenVolume (VolumeNamePtr, SSC_ACCESS_READ);
|
||
|
|
||
|
Request[0].DiskBufferAddress.LowPart = Buffer;
|
||
|
Request[0].DiskBufferAddress.HighPart = 0;
|
||
|
Request[0].DiskByteCount = SectorCount * SECTOR_SIZE;
|
||
|
RequestPtr.LowPart = Request;
|
||
|
RequestPtr.HighPart = 0;
|
||
|
|
||
|
VolumeOffset.LowPart = SectorBase * SECTOR_SIZE;
|
||
|
VolumeOffset.HighPart = 0;
|
||
|
SscDiskReadVolume(VolumeHandle, 1, RequestPtr, VolumeOffset);
|
||
|
|
||
|
DiskCompletion.VolumeHandle = VolumeHandle;
|
||
|
DiskCompletionPtr.LowPart = &DiskCompletion;
|
||
|
DiskCompletionPtr.HighPart = 0;
|
||
|
while (1) {
|
||
|
if (SscDiskWaitIoCompletion(DiskCompletionPtr) == 0) break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SalPrint(
|
||
|
PUCHAR Buffer
|
||
|
)
|
||
|
{
|
||
|
IA32_BIOS_REGISTER_STATE IA32RegisterState;
|
||
|
BIT32_AND_BIT16 IA32Register;
|
||
|
ULONG i;
|
||
|
|
||
|
for (i = 0; Buffer[i] != 0 && i < 256; i++) {
|
||
|
IA32Register.HighPart16 = 14;
|
||
|
IA32Register.LowPart16 = Buffer[i];
|
||
|
IA32RegisterState.eax = IA32Register.Part32;
|
||
|
|
||
|
IA32RegisterState.ebx = 7;
|
||
|
|
||
|
// SAL_PROC(0x100,&IA32RegisterState,0,0,0,0,0,0,);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Multiply(
|
||
|
ULONG Multiplicant,
|
||
|
ULONG Multiplier)
|
||
|
{
|
||
|
return(Multiplicant * Multiplier);
|
||
|
}
|
||
|
|
||
|
Divide(
|
||
|
ULONG Numerator,
|
||
|
ULONG Denominator,
|
||
|
PULONG Result,
|
||
|
PULONG Remainder
|
||
|
)
|
||
|
{
|
||
|
float f1, f2;
|
||
|
|
||
|
f1 = (float) Numerator;
|
||
|
f2 = (float) Denominator;
|
||
|
*Result = (ULONG) (f1 / f2);
|
||
|
*Remainder = Numerator % Denominator;
|
||
|
}
|
||
|
|
||
|
memcpy(
|
||
|
PUCHAR Source,
|
||
|
PUCHAR Destination,
|
||
|
ULONG Length
|
||
|
)
|
||
|
{
|
||
|
while (Length--) {
|
||
|
*Destination++ = *Source++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
memmove(
|
||
|
PUCHAR Source,
|
||
|
PUCHAR Destination,
|
||
|
ULONG Length
|
||
|
)
|
||
|
{
|
||
|
while (Length--) {
|
||
|
*Destination++ = *Source++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
memset(
|
||
|
PUCHAR Destination,
|
||
|
ULONG Length,
|
||
|
ULONG Value
|
||
|
)
|
||
|
{
|
||
|
while (Length--) {
|
||
|
*Destination++ = Value;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
strncmp(
|
||
|
PUCHAR String1,
|
||
|
PUCHAR String2,
|
||
|
ULONG Length
|
||
|
)
|
||
|
{
|
||
|
while (Length--) {
|
||
|
if (*String1++ != *String2++)
|
||
|
return(String1);
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
PrintName(
|
||
|
PUCHAR String
|
||
|
)
|
||
|
{
|
||
|
LARGE_INTEGER StringPtr;
|
||
|
|
||
|
StringPtr.LowPart = String;
|
||
|
StringPtr.HighPart = 0;
|
||
|
SscDbgPrintf(StringPtr);
|
||
|
}
|
||
|
|
||
|
BootErr$Print(
|
||
|
PUCHAR String
|
||
|
)
|
||
|
{
|
||
|
LARGE_INTEGER StringPtr;
|
||
|
|
||
|
StringPtr.LowPart = String;
|
||
|
StringPtr.HighPart = 0;
|
||
|
SscDbgPrintf(StringPtr);
|
||
|
}
|
||
|
|
||
|
LoadNtldrSymbols()
|
||
|
{
|
||
|
static char *NtfsBoot = "\\ntfsboot.exe";
|
||
|
static char *Ntldr = "\\NTLDR";
|
||
|
LARGE_INTEGER PhysicalPtr;
|
||
|
|
||
|
PhysicalPtr.LowPart = NtfsBoot;
|
||
|
PhysicalPtr.HighPart = 0;
|
||
|
|
||
|
SscUnloadImage(PhysicalPtr,
|
||
|
0x0,
|
||
|
(ULONG)-1,
|
||
|
(ULONG)0);
|
||
|
|
||
|
PhysicalPtr.LowPart = Ntldr;
|
||
|
PhysicalPtr.HighPart = 0;
|
||
|
|
||
|
SscLoadImage(PhysicalPtr,
|
||
|
0xE00000,
|
||
|
0x118A00,
|
||
|
0x7cc,
|
||
|
0, // process ID
|
||
|
1); // load count
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
RelocateLoaderSections(
|
||
|
ULONG NtldrBuffer
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
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:
|
||
|
|
||
|
NtldrBuffer - Buffer that contains the NTLDR raw image from disk
|
||
|
|
||
|
Returns:
|
||
|
|
||
|
Entry point of loader
|
||
|
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG Start, End;
|
||
|
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) NtldrBuffer;
|
||
|
|
||
|
//
|
||
|
// 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) {
|
||
|
SalPrint("SU_NTLDR_CORRUPT");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (FileHeader->Machine != IMAGE_FILE_MACHINE_IA64) {
|
||
|
SalPrint("SU_NTLDR_CORRUPT");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 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;
|
||
|
|
||
|
//
|
||
|
// Loop and relocate each section with a non-zero RawData size
|
||
|
//
|
||
|
|
||
|
for (Section=FileHeader->NumberOfSections ; Section-- ; SectionHeader++) {
|
||
|
|
||
|
//
|
||
|
// Compute source, destination, and count arguments
|
||
|
//
|
||
|
|
||
|
Source = NtldrBuffer + 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;
|
||
|
}
|
||
|
|
||
|
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.
|
||
|
//
|
||
|
memmove(Source,Destination,SizeOfRawData);
|
||
|
}
|
||
|
|
||
|
if (SizeOfRawData < VirtualSize) {
|
||
|
//
|
||
|
// Zero the portion not loaded from the image
|
||
|
//
|
||
|
memset(Destination+SizeOfRawData,0,VirtualSize - SizeOfRawData);
|
||
|
}
|
||
|
#if 0
|
||
|
//
|
||
|
// 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;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
return(OptionalHeader->AddressOfEntryPoint + OptionalHeader->ImageBase);
|
||
|
}
|