mirror of
https://github.com/reactos/reactos.git
synced 2024-08-19 18:02:55 +00:00
1415 lines
48 KiB
C
1415 lines
48 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: ntoskrnl/ke/freeldr.c
|
|
* PURPOSE: FreeLDR Bootstrap Support
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
#if defined(_PPC_)
|
|
#include <ppcmmu/mmu.h>
|
|
#define KERNEL_RVA(x) RVA(x,0x80800000)
|
|
#define KERNEL_DESCRIPTOR_PAGE(x) (((ULONG_PTR)x + KernelBase) >> PAGE_SHIFT)
|
|
#else
|
|
#define KERNEL_RVA(x) RVA(x,KSEG0_BASE)
|
|
#define KERNEL_DESCRIPTOR_PAGE(x) (((ULONG_PTR)x &~ KSEG0_BASE) >> PAGE_SHIFT)
|
|
#endif
|
|
|
|
typedef struct _BIOS_MEMORY_DESCRIPTOR
|
|
{
|
|
ULONG BlockBase;
|
|
ULONG BlockSize;
|
|
} BIOS_MEMORY_DESCRIPTOR, *PBIOS_MEMORY_DESCRIPTOR;
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
/* FreeLDR Loader Data */
|
|
PROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock;
|
|
ADDRESS_RANGE KeMemoryMap[64];
|
|
ULONG KeMemoryMapRangeCount;
|
|
|
|
/* NT Loader Module/Descriptor Count */
|
|
ULONG BldrCurrentMd;
|
|
ULONG BldrCurrentMod;
|
|
|
|
/* NT Loader Data. Eats up about 100KB! */
|
|
LOADER_PARAMETER_BLOCK BldrLoaderBlock; // 0x0000
|
|
LOADER_PARAMETER_EXTENSION BldrExtensionBlock; // 0x0060
|
|
CHAR BldrCommandLine[256]; // 0x00DC
|
|
CHAR BldrArcBootPath[64]; // 0x01DC
|
|
CHAR BldrArcHalPath[64]; // 0x021C
|
|
CHAR BldrNtHalPath[64]; // 0x025C
|
|
CHAR BldrNtBootPath[64]; // 0x029C
|
|
LDR_DATA_TABLE_ENTRY BldrModules[64]; // 0x02DC
|
|
MEMORY_ALLOCATION_DESCRIPTOR BldrMemoryDescriptors[60]; // 0x14DC
|
|
WCHAR BldrModuleStrings[64][260]; // 0x19DC
|
|
WCHAR BldrModuleStringsFull[64][260]; // 0x9BDC
|
|
NLS_DATA_BLOCK BldrNlsDataBlock; // 0x11DDC
|
|
SETUP_LOADER_BLOCK BldrSetupBlock; // 0x11DE8
|
|
ARC_DISK_INFORMATION BldrArcDiskInfo; // 0x12134
|
|
CHAR BldrArcNames[32][256]; // 0x1213C
|
|
ARC_DISK_SIGNATURE BldrDiskInfo[32]; // 0x1413C
|
|
CHAR BldrArcHwBuffer[16 * 1024]; // 0x1843C
|
|
|
|
/* BIOS Memory Map */
|
|
BIOS_MEMORY_DESCRIPTOR BiosMemoryDescriptors[16] = { { 0, 0 }, };
|
|
PBIOS_MEMORY_DESCRIPTOR BiosMemoryDescriptorList = BiosMemoryDescriptors;
|
|
|
|
/* ARC Memory Map */
|
|
ULONG NumberDescriptors = 0;
|
|
MEMORY_DESCRIPTOR MDArray[60] = { { 0, 0, 0 }, };
|
|
|
|
#if defined(_X86_)
|
|
|
|
/* The Boot TSS */
|
|
KTSS KiBootTss;
|
|
|
|
/* Old boot style IDT */
|
|
KIDTENTRY KiBootIdt[256];
|
|
|
|
/* The Boot GDT */
|
|
KGDTENTRY KiBootGdt[256] =
|
|
{
|
|
{0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_NULL */
|
|
{0xffff, 0x0000, {{0x00, 0x9b, 0xcf, 0x00}}}, /* KGDT_R0_CODE */
|
|
{0xffff, 0x0000, {{0x00, 0x93, 0xcf, 0x00}}}, /* KGDT_R0_DATA */
|
|
{0xffff, 0x0000, {{0x00, 0xfb, 0xcf, 0x00}}}, /* KGDT_R3_CODE */
|
|
{0xffff, 0x0000, {{0x00, 0xf3, 0xcf, 0x00}}}, /* KGDT_R3_DATA*/
|
|
{0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_TSS */
|
|
{0x0001, 0xf000, {{0xdf, 0x93, 0xc0, 0xff}}}, /* KGDT_R0_PCR */
|
|
{0x0fff, 0x0000, {{0x00, 0xf3, 0x40, 0x00}}}, /* KGDT_R3_TEB */
|
|
{0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_UNUSED */
|
|
{0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_LDT */
|
|
{0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}}, /* KGDT_DF_TSS */
|
|
{0x0000, 0x0000, {{0x00, 0x00, 0x00, 0x00}}} /* KGDT_NMI_TSS */
|
|
};
|
|
|
|
/* GDT Descriptor */
|
|
KDESCRIPTOR KiGdtDescriptor = {0, sizeof(KiBootGdt) - 1, (ULONG)KiBootGdt};
|
|
|
|
#endif
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
PMEMORY_ALLOCATION_DESCRIPTOR
|
|
NTAPI
|
|
KiRosGetMdFromArray(VOID)
|
|
{
|
|
/* Return the next MD from the list, but make sure we don't overflow */
|
|
if (BldrCurrentMd > 60) ASSERT(FALSE);
|
|
return &BldrMemoryDescriptors[BldrCurrentMd++];
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KiRosAddBiosBlock(ULONG Address,
|
|
ULONG Size)
|
|
{
|
|
PBIOS_MEMORY_DESCRIPTOR BiosBlock = BiosMemoryDescriptorList;
|
|
|
|
/* Loop our BIOS Memory Descriptor List */
|
|
while (BiosBlock->BlockSize > 0)
|
|
{
|
|
/* Check if we've found a matching head block */
|
|
if (Address + Size == BiosBlock->BlockBase)
|
|
{
|
|
/* Simply enlarge and rebase it */
|
|
BiosBlock->BlockBase = Address;
|
|
BiosBlock->BlockSize += Size;
|
|
break;
|
|
}
|
|
|
|
/* Check if we've found a matching tail block */
|
|
if (Address == (BiosBlock->BlockBase + BiosBlock->BlockSize))
|
|
{
|
|
/* Simply enlarge it */
|
|
BiosBlock->BlockSize += Size;
|
|
break;
|
|
}
|
|
|
|
/* Nothing suitable found, try the next block */
|
|
BiosBlock++;
|
|
}
|
|
|
|
/* No usable blocks found, found a free block instead */
|
|
if (!BiosBlock->BlockSize)
|
|
{
|
|
/* Write our data */
|
|
BiosBlock->BlockBase = Address;
|
|
BiosBlock->BlockSize = Size;
|
|
|
|
/* Create a new block and mark it as the end of the array */
|
|
BiosBlock++;
|
|
BiosBlock->BlockBase = BiosBlock->BlockSize = 0L;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KiRosBuildBiosMemoryMap(VOID)
|
|
{
|
|
ULONG BlockBegin, BlockEnd;
|
|
ULONG j;
|
|
|
|
/* Loop the BIOS Memory Map */
|
|
for (j = 0; j < KeMemoryMapRangeCount; j++)
|
|
{
|
|
/* Get the start and end addresses */
|
|
BlockBegin = KeMemoryMap[j].BaseAddrLow;
|
|
BlockEnd = KeMemoryMap[j].BaseAddrLow + KeMemoryMap[j].LengthLow - 1;
|
|
|
|
/* Make sure this isn't a > 4GB descriptor */
|
|
if (!KeMemoryMap[j].BaseAddrHigh)
|
|
{
|
|
/* Make sure we don't overflow */
|
|
if (BlockEnd < BlockBegin) BlockEnd = 0xFFFFFFFF;
|
|
|
|
/* Check if this is free memory */
|
|
if (KeMemoryMap[j].Type == 1)
|
|
{
|
|
/* Add it to our BIOS descriptors */
|
|
KiRosAddBiosBlock(BlockBegin, BlockEnd - BlockBegin + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KiRosAllocateArcDescriptor(IN ULONG PageBegin,
|
|
IN ULONG PageEnd,
|
|
IN MEMORY_TYPE MemoryType)
|
|
{
|
|
ULONG i;
|
|
|
|
/* Loop all our descriptors */
|
|
for (i = 0; i < NumberDescriptors; i++)
|
|
{
|
|
/* Attempt to fing a free block that describes our region */
|
|
if ((MDArray[i].MemoryType == MemoryFree) &&
|
|
(MDArray[i].BasePage <= PageBegin) &&
|
|
(MDArray[i].BasePage + MDArray[i].PageCount > PageBegin) &&
|
|
(MDArray[i].BasePage + MDArray[i].PageCount >= PageEnd))
|
|
{
|
|
/* Found one! */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Check if we found no free blocks, and fail if so */
|
|
if (i == NumberDescriptors) return ENOMEM;
|
|
|
|
/* Check if the block has our base address */
|
|
if (MDArray[i].BasePage == PageBegin)
|
|
{
|
|
/* Check if it also has our ending address */
|
|
if ((MDArray[i].BasePage + MDArray[i].PageCount) == PageEnd)
|
|
{
|
|
/* Then convert this region into our new memory type */
|
|
MDArray[i].MemoryType = MemoryType;
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, make sure we have enough descriptors */
|
|
if (NumberDescriptors == 60) return ENOMEM;
|
|
|
|
/* Cut this descriptor short */
|
|
MDArray[i].BasePage = PageEnd;
|
|
MDArray[i].PageCount -= (PageEnd - PageBegin);
|
|
|
|
/* And allocate a new descriptor for our memory range */
|
|
MDArray[NumberDescriptors].BasePage = PageBegin;
|
|
MDArray[NumberDescriptors].PageCount = PageEnd - PageBegin;
|
|
MDArray[NumberDescriptors].MemoryType = MemoryType;
|
|
NumberDescriptors++;
|
|
}
|
|
}
|
|
else if ((MDArray[i].BasePage + MDArray[i].PageCount) == PageEnd)
|
|
{
|
|
/* This block has our end address, make sure we have a free block */
|
|
if (NumberDescriptors == 60) return ENOMEM;
|
|
|
|
/* Rebase this descriptor */
|
|
MDArray[i].PageCount = PageBegin - MDArray[i].BasePage;
|
|
|
|
/* And allocate a new descriptor for our memory range */
|
|
MDArray[NumberDescriptors].BasePage = PageBegin;
|
|
MDArray[NumberDescriptors].PageCount = PageEnd - PageBegin;
|
|
MDArray[NumberDescriptors].MemoryType = MemoryType;
|
|
NumberDescriptors++;
|
|
}
|
|
else
|
|
{
|
|
/* We'll need two descriptors, make sure they're available */
|
|
if ((NumberDescriptors + 1) >= 60) return ENOMEM;
|
|
|
|
/* Allocate a free memory descriptor for what follows us */
|
|
MDArray[NumberDescriptors].BasePage = PageEnd;
|
|
MDArray[NumberDescriptors].PageCount = MDArray[i].PageCount -
|
|
(PageEnd - MDArray[i].BasePage);
|
|
MDArray[NumberDescriptors].MemoryType = MemoryFree;
|
|
NumberDescriptors++;
|
|
|
|
/* Cut down the current free descriptor */
|
|
MDArray[i].PageCount = PageBegin - MDArray[i].BasePage;
|
|
|
|
/* Allocate a new memory descriptor for our memory range */
|
|
MDArray[NumberDescriptors].BasePage = PageBegin;
|
|
MDArray[NumberDescriptors].PageCount = PageEnd - PageBegin;
|
|
MDArray[NumberDescriptors].MemoryType = MemoryType;
|
|
NumberDescriptors++;
|
|
}
|
|
|
|
/* Everything went well */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KiRosConfigureArcDescriptor(IN ULONG PageBegin,
|
|
IN ULONG PageEnd,
|
|
IN TYPE_OF_MEMORY MemoryType)
|
|
{
|
|
ULONG i;
|
|
ULONG BlockBegin, BlockEnd;
|
|
MEMORY_TYPE BlockType;
|
|
BOOLEAN Combined = FALSE;
|
|
|
|
/* If this descriptor seems bogus, just return */
|
|
if (PageEnd <= PageBegin) return STATUS_SUCCESS;
|
|
|
|
/* Loop every ARC descriptor, trying to find one we can modify */
|
|
for (i = 0; i < NumberDescriptors; i++)
|
|
{
|
|
/* Get its settings */
|
|
BlockBegin = MDArray[i].BasePage;
|
|
BlockEnd = MDArray[i].BasePage + MDArray[i].PageCount;
|
|
BlockType = MDArray[i].MemoryType;
|
|
|
|
/* Check if we can fit inside this block */
|
|
if (BlockBegin < PageBegin)
|
|
{
|
|
/* Check if we are larger then it */
|
|
if ((BlockEnd > PageBegin) && (BlockEnd <= PageEnd))
|
|
{
|
|
/* Make it end where we start */
|
|
BlockEnd = PageBegin;
|
|
}
|
|
|
|
/* Check if it ends after we do */
|
|
if (BlockEnd > PageEnd)
|
|
{
|
|
/* Make sure we can allocate a descriptor */
|
|
if (NumberDescriptors == 60) return ENOMEM;
|
|
|
|
/* Create a descriptor for whatever memory we're not part of */
|
|
MDArray[NumberDescriptors].MemoryType = BlockType;
|
|
MDArray[NumberDescriptors].BasePage = PageEnd;
|
|
MDArray[NumberDescriptors].PageCount = BlockEnd - PageEnd;
|
|
NumberDescriptors++;
|
|
|
|
/* The next block ending is now where we begin */
|
|
BlockEnd = PageBegin;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Check if the blog begins inside our range */
|
|
if (BlockBegin < PageEnd)
|
|
{
|
|
/* Check if it ends before we do */
|
|
if (BlockEnd < PageEnd)
|
|
{
|
|
/* Then make it disappear */
|
|
BlockEnd = BlockBegin;
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise make it start where we end */
|
|
BlockBegin = PageEnd;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check if the block matches us, and we haven't tried combining yet */
|
|
if (((TYPE_OF_MEMORY)BlockType == MemoryType) && !(Combined))
|
|
{
|
|
/* Check if it starts where we end */
|
|
if (BlockBegin == PageEnd)
|
|
{
|
|
/* Make it start with us, and combine us */
|
|
BlockBegin = PageBegin;
|
|
Combined = TRUE;
|
|
}
|
|
else if (BlockEnd == PageBegin)
|
|
{
|
|
/* Otherwise, it ends where we begin, combine its ending */
|
|
BlockEnd = PageEnd;
|
|
Combined = TRUE;
|
|
}
|
|
}
|
|
|
|
/* Check the original block data matches with what we came up with */
|
|
if ((MDArray[i].BasePage == BlockBegin) &&
|
|
(MDArray[i].PageCount == BlockEnd - BlockBegin))
|
|
{
|
|
/* Then skip it */
|
|
continue;
|
|
}
|
|
|
|
/* Otherwise, set our new settings for this block */
|
|
MDArray[i].BasePage = BlockBegin;
|
|
MDArray[i].PageCount = BlockEnd - BlockBegin;
|
|
|
|
/* Check if we are killing the block */
|
|
if (BlockBegin == BlockEnd)
|
|
{
|
|
/* Delete this block and restart the loop properly */
|
|
NumberDescriptors--;
|
|
if (i < NumberDescriptors) MDArray[i] = MDArray[NumberDescriptors];
|
|
i--;
|
|
}
|
|
}
|
|
|
|
/* If we got here without combining, we need to allocate a new block */
|
|
if (!(Combined) && (MemoryType < LoaderMaximum))
|
|
{
|
|
/* Make sure there's enough descriptors */
|
|
if (NumberDescriptors == 60) return ENOMEM;
|
|
|
|
/* Allocate a new block with our data */
|
|
MDArray[NumberDescriptors].MemoryType = MemoryType;
|
|
MDArray[NumberDescriptors].BasePage = PageBegin;
|
|
MDArray[NumberDescriptors].PageCount = PageEnd - PageBegin;
|
|
NumberDescriptors++;
|
|
}
|
|
|
|
/* Changes complete, return success */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KiRosBuildOsMemoryMap(VOID)
|
|
{
|
|
PBIOS_MEMORY_DESCRIPTOR MdBlock;
|
|
ULONG BlockStart, BlockEnd, BiasedStart, BiasedEnd, PageStart, PageEnd;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
ULONG BiosPage = 0xA0;
|
|
|
|
/* Loop the BIOS Memory Descriptor List */
|
|
MdBlock = BiosMemoryDescriptorList;
|
|
while (MdBlock->BlockSize)
|
|
{
|
|
/* Get the statrt and end addresses */
|
|
BlockStart = MdBlock->BlockBase;
|
|
BlockEnd = BlockStart + MdBlock->BlockSize - 1;
|
|
|
|
/* Align them to page boundaries */
|
|
BiasedStart = BlockStart & (PAGE_SIZE - 1);
|
|
if (BiasedStart) BlockStart = BlockStart + PAGE_SIZE - BiasedStart;
|
|
BiasedEnd = (BlockEnd + 1) & (ULONG)(PAGE_SIZE - 1);
|
|
if (BiasedEnd) BlockEnd -= BiasedEnd;
|
|
|
|
/* Get the actual page numbers */
|
|
PageStart = BlockStart >> PAGE_SHIFT;
|
|
PageEnd = (BlockEnd + 1) >> PAGE_SHIFT;
|
|
|
|
/* If we're starting at page 0, then put the BIOS page at the end */
|
|
if (!PageStart) BiosPage = PageEnd;
|
|
|
|
/* Check if we did any alignment */
|
|
if (BiasedStart)
|
|
{
|
|
/* Mark that region as reserved */
|
|
Status = KiRosConfigureArcDescriptor(PageStart - 1,
|
|
PageStart,
|
|
MemorySpecialMemory);
|
|
if (Status != STATUS_SUCCESS) break;
|
|
}
|
|
|
|
/* Check if we did any alignment */
|
|
if (BiasedEnd)
|
|
{
|
|
/* Mark that region as reserved */
|
|
Status = KiRosConfigureArcDescriptor(PageEnd - 1,
|
|
PageEnd,
|
|
MemorySpecialMemory);
|
|
if (Status != STATUS_SUCCESS) break;
|
|
|
|
/* If the bios page was the last page, use the next one instead */
|
|
if (BiosPage == PageEnd) BiosPage += 1;
|
|
}
|
|
|
|
/* Check if the page is below the 16MB Memory hole */
|
|
if (PageEnd <= 0xFC0)
|
|
{
|
|
/* It is, mark the memory a free */
|
|
Status = KiRosConfigureArcDescriptor(PageStart,
|
|
PageEnd,
|
|
LoaderFree);
|
|
}
|
|
else if (PageStart >= 0x1000)
|
|
{
|
|
/* It's over 16MB, so that memory gets marked as reserve */
|
|
Status = KiRosConfigureArcDescriptor(PageStart,
|
|
PageEnd,
|
|
LoaderFree);
|
|
}
|
|
else
|
|
{
|
|
/* Check if it starts below the memory hole */
|
|
if (PageStart < 0xFC0)
|
|
{
|
|
/* Mark that part as free */
|
|
Status = KiRosConfigureArcDescriptor(PageStart,
|
|
0xFC0,
|
|
MemoryFree);
|
|
if (Status != STATUS_SUCCESS) break;
|
|
|
|
/* And update the page start for the code below */
|
|
PageStart = 0xFC0;
|
|
}
|
|
|
|
/* Any code in the memory hole region ends up as reserve */
|
|
Status = KiRosConfigureArcDescriptor(PageStart,
|
|
PageEnd,
|
|
LoaderFree);
|
|
}
|
|
|
|
/* If we failed, break out, otherwise, go to the next BIOS block */
|
|
if (Status != STATUS_SUCCESS) break;
|
|
MdBlock++;
|
|
}
|
|
|
|
/* If anything failed until now, return error code */
|
|
if (Status != STATUS_SUCCESS) return Status;
|
|
|
|
#if defined(_X86_)
|
|
/* Set the top 16MB region as reserved */
|
|
Status = KiRosConfigureArcDescriptor(0xFC0, 0x1000, MemorySpecialMemory);
|
|
if (Status != STATUS_SUCCESS) return Status;
|
|
|
|
/* Setup the BIOS region as reserved */
|
|
KiRosConfigureArcDescriptor(0xA0, 0x100, LoaderMaximum);
|
|
KiRosConfigureArcDescriptor(BiosPage, 0x100, MemoryFirmwarePermanent);
|
|
|
|
/* Build an entry for the IVT */
|
|
Status = KiRosAllocateArcDescriptor(0, 1, MemoryFirmwarePermanent);
|
|
if (Status != STATUS_SUCCESS) return Status;
|
|
#endif
|
|
|
|
/* Build an entry for the KPCR and KUSER_SHARED_DATA */
|
|
Status = KiRosAllocateArcDescriptor(1, 3, LoaderStartupPcrPage);
|
|
if (Status != STATUS_SUCCESS) return Status;
|
|
|
|
/* Build an entry for the PDE and return the status */
|
|
Status = KiRosAllocateArcDescriptor(KeRosLoaderBlock->
|
|
PageDirectoryStart >> PAGE_SHIFT,
|
|
KeRosLoaderBlock->
|
|
PageDirectoryEnd >> PAGE_SHIFT,
|
|
LoaderMemoryData);
|
|
return Status;
|
|
}
|
|
|
|
#if defined(_X86_)
|
|
VOID
|
|
NTAPI
|
|
KiRosBuildReservedMemoryMap(VOID)
|
|
{
|
|
ULONG j;
|
|
ULONG BlockBegin, BlockEnd, BiasedPage;
|
|
|
|
/* Loop the BIOS Memory Map */
|
|
for (j = 0; j < KeMemoryMapRangeCount; j++)
|
|
{
|
|
/* Get the start and end addresses */
|
|
BlockBegin = KeMemoryMap[j].BaseAddrLow;
|
|
BlockEnd = BlockBegin + KeMemoryMap[j].LengthLow - 1;
|
|
|
|
/* Make sure it wasn't a > 4GB descriptor */
|
|
if (!KeMemoryMap[j].BaseAddrHigh)
|
|
{
|
|
/* Make sure it doesn't overflow */
|
|
if (BlockEnd < BlockBegin) BlockEnd = 0xFFFFFFFF;
|
|
|
|
/* Check if this was free memory */
|
|
if (KeMemoryMap[j].Type == 1)
|
|
{
|
|
/* Get the page-aligned addresses */
|
|
BiasedPage = BlockBegin & (PAGE_SIZE - 1);
|
|
BlockBegin >>= PAGE_SHIFT;
|
|
if (BiasedPage) BlockBegin++;
|
|
BlockEnd = (BlockEnd >> PAGE_SHIFT) + 1;
|
|
|
|
/* Check if the block is within the 16MB memory hole */
|
|
if ((BlockBegin < 0xFC0) && (BlockEnd >= 0xFC0))
|
|
{
|
|
/* Don't allow it to cross this boundary */
|
|
BlockBegin = 0xFC0;
|
|
}
|
|
|
|
/* Check if the boundary is across 16MB */
|
|
if ((BlockEnd > 0xFFF) && (BlockBegin <= 0xFFF))
|
|
{
|
|
/* Don't let it cross */
|
|
BlockEnd = 0xFFF;
|
|
}
|
|
|
|
/* Check if the block describes the memory hole */
|
|
if ((BlockBegin >= 0xFC0) && (BlockEnd <= 0xFFF))
|
|
{
|
|
/* Set this region as temporary */
|
|
KiRosConfigureArcDescriptor(BlockBegin,
|
|
BlockEnd,
|
|
MemoryFirmwareTemporary);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Get the page-aligned addresses */
|
|
BlockBegin >>= PAGE_SHIFT;
|
|
BiasedPage = (BlockEnd + 1) & (PAGE_SIZE - 1);
|
|
BlockEnd >>= PAGE_SHIFT;
|
|
if (BiasedPage) BlockEnd++;
|
|
|
|
/* Set this memory as reserved */
|
|
KiRosConfigureArcDescriptor(BlockBegin,
|
|
BlockEnd + 1,
|
|
MemorySpecialMemory);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
VOID
|
|
NTAPI
|
|
KiRosInsertNtDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)
|
|
{
|
|
PLIST_ENTRY ListHead, PreviousEntry, NextEntry;
|
|
PMEMORY_ALLOCATION_DESCRIPTOR Descriptor = NULL, NextDescriptor = NULL;
|
|
|
|
/* Loop the memory descriptor list */
|
|
ListHead = &KeLoaderBlock->MemoryDescriptorListHead;
|
|
PreviousEntry = ListHead;
|
|
NextEntry = ListHead->Flink;
|
|
while (NextEntry != ListHead)
|
|
{
|
|
/* Get the current descriptor and check if it's below ours */
|
|
NextDescriptor = CONTAINING_RECORD(NextEntry,
|
|
MEMORY_ALLOCATION_DESCRIPTOR,
|
|
ListEntry);
|
|
if (NewDescriptor->BasePage < NextDescriptor->BasePage) break;
|
|
|
|
/* It isn't, save the previous entry and descriptor, and try again */
|
|
PreviousEntry = NextEntry;
|
|
Descriptor = NextDescriptor;
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
/* So we found the right spot to insert. Is this free memory? */
|
|
if (NewDescriptor->MemoryType != LoaderFree)
|
|
{
|
|
/* It isn't, so insert us before the last descriptor */
|
|
InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
|
|
}
|
|
else
|
|
{
|
|
/* We're free memory. Check if the entry we found is also free memory */
|
|
if ((PreviousEntry != ListHead) &&
|
|
((Descriptor->MemoryType == LoaderFree) ||
|
|
(Descriptor->MemoryType == LoaderReserve)) &&
|
|
((Descriptor->BasePage + Descriptor->PageCount) ==
|
|
NewDescriptor->BasePage))
|
|
{
|
|
/* It's free memory, and we're right after it. Enlarge that block */
|
|
Descriptor->PageCount += NewDescriptor->PageCount;
|
|
NewDescriptor = Descriptor;
|
|
}
|
|
else
|
|
{
|
|
/* Our range scan't be combined, so just insert us separately */
|
|
InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
|
|
}
|
|
|
|
/* Check if we merged with an existing free memory block */
|
|
if ((NextEntry != ListHead) &&
|
|
((NextDescriptor->MemoryType == LoaderFree) ||
|
|
(NextDescriptor->MemoryType == LoaderReserve)) &&
|
|
((NewDescriptor->BasePage + NewDescriptor->PageCount) ==
|
|
NextDescriptor->BasePage))
|
|
{
|
|
/* Update our own block */
|
|
NewDescriptor->PageCount += NextDescriptor->PageCount;
|
|
|
|
/* Remove the next block */
|
|
RemoveEntryList(&NextDescriptor->ListEntry);
|
|
}
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KiRosBuildNtDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
|
|
IN MEMORY_TYPE MemoryType,
|
|
IN ULONG BasePage,
|
|
IN ULONG PageCount)
|
|
{
|
|
PMEMORY_ALLOCATION_DESCRIPTOR Descriptor, NextDescriptor = NULL;
|
|
LONG Delta;
|
|
TYPE_OF_MEMORY CurrentType;
|
|
BOOLEAN UseNext;
|
|
|
|
/* Check how many pages we'll be consuming */
|
|
Delta = BasePage - MemoryDescriptor->BasePage;
|
|
if (!(Delta) && (PageCount == MemoryDescriptor->PageCount))
|
|
{
|
|
/* We can simply convert the current descriptor into our new type */
|
|
MemoryDescriptor->MemoryType = MemoryType;
|
|
}
|
|
else
|
|
{
|
|
/* Get the current memory type of the descriptor, and reserve it */
|
|
CurrentType = MemoryDescriptor->MemoryType;
|
|
MemoryDescriptor->MemoryType = LoaderSpecialMemory;
|
|
|
|
/* Check if we'll need another descriptor for what's left of memory */
|
|
UseNext = ((BasePage != MemoryDescriptor->BasePage) &&
|
|
(Delta + PageCount != MemoryDescriptor->PageCount));
|
|
|
|
/* Get a descriptor */
|
|
Descriptor = KiRosGetMdFromArray();
|
|
if (!Descriptor) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
/* Check if we are using another descriptor */
|
|
if (UseNext)
|
|
{
|
|
/* Allocate that one too */
|
|
NextDescriptor = KiRosGetMdFromArray();
|
|
if (!NextDescriptor) return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* Build the descriptor we got */
|
|
Descriptor->MemoryType = MemoryType;
|
|
Descriptor->BasePage = BasePage;
|
|
Descriptor->PageCount = PageCount;
|
|
|
|
/* Check if we're starting at the same place as the old one */
|
|
if (BasePage == MemoryDescriptor->BasePage)
|
|
{
|
|
/* Simply decrease the old descriptor and rebase it */
|
|
MemoryDescriptor->BasePage += PageCount;
|
|
MemoryDescriptor->PageCount -= PageCount;
|
|
MemoryDescriptor->MemoryType = CurrentType;
|
|
}
|
|
else if (Delta + PageCount == MemoryDescriptor->PageCount)
|
|
{
|
|
/* We finish where the old one did, shorten it */
|
|
MemoryDescriptor->PageCount -= PageCount;
|
|
MemoryDescriptor->MemoryType = CurrentType;
|
|
}
|
|
else
|
|
{
|
|
/* We're inside the current block, mark our free region */
|
|
NextDescriptor->MemoryType = LoaderFree;
|
|
NextDescriptor->BasePage = BasePage + PageCount;
|
|
NextDescriptor->PageCount = MemoryDescriptor->PageCount -
|
|
(PageCount + Delta);
|
|
|
|
/* And cut down the current descriptor */
|
|
MemoryDescriptor->PageCount = Delta;
|
|
MemoryDescriptor->MemoryType = CurrentType;
|
|
|
|
/* Finally, insert our new free descriptor into the list */
|
|
KiRosInsertNtDescriptor(NextDescriptor);
|
|
}
|
|
|
|
/* Insert the descriptor we allocated */
|
|
KiRosInsertNtDescriptor(Descriptor);
|
|
}
|
|
|
|
/* Return success */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
PMEMORY_ALLOCATION_DESCRIPTOR
|
|
NTAPI
|
|
KiRosFindNtDescriptor(IN ULONG BasePage)
|
|
{
|
|
PMEMORY_ALLOCATION_DESCRIPTOR MdBlock = NULL;
|
|
PLIST_ENTRY NextEntry, ListHead;
|
|
|
|
/* Scan the memory descriptor list */
|
|
ListHead = &KeLoaderBlock->MemoryDescriptorListHead;
|
|
NextEntry = ListHead->Flink;
|
|
while (NextEntry != ListHead)
|
|
{
|
|
/* Get the current descriptor */
|
|
MdBlock = CONTAINING_RECORD(NextEntry,
|
|
MEMORY_ALLOCATION_DESCRIPTOR,
|
|
ListEntry);
|
|
|
|
/* Check if it can contain our memory range */
|
|
if ((MdBlock->BasePage <= BasePage) &&
|
|
(MdBlock->BasePage + MdBlock->PageCount > BasePage))
|
|
{
|
|
/* It can, break out */
|
|
break;
|
|
}
|
|
|
|
/* Go to the next descriptor */
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
/* Return the descriptor we found, if any */
|
|
return MdBlock;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KiRosAllocateNtDescriptor(IN TYPE_OF_MEMORY MemoryType,
|
|
IN ULONG BasePage,
|
|
IN ULONG PageCount,
|
|
IN ULONG Alignment,
|
|
OUT PULONG ReturnedBase)
|
|
{
|
|
PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
|
|
ULONG AlignedBase, AlignedLimit;
|
|
PMEMORY_ALLOCATION_DESCRIPTOR ActiveMdBlock;
|
|
ULONG ActiveAlignedBase = 0;
|
|
PLIST_ENTRY NextEntry, ListHead;
|
|
|
|
/* If no information was given, make some assumptions */
|
|
if (!Alignment) Alignment = 1;
|
|
if (!PageCount) PageCount = 1;
|
|
|
|
/* Start looking for a matching descvriptor */
|
|
do
|
|
{
|
|
/* Calculate the limit of the range */
|
|
AlignedLimit = PageCount + BasePage;
|
|
|
|
/* Find a descriptor that already contains our base address */
|
|
MdBlock = KiRosFindNtDescriptor(BasePage);
|
|
|
|
if (MdBlock)
|
|
{
|
|
/* If it contains our limit as well, break out early */
|
|
if ((MdBlock->PageCount + MdBlock->BasePage) >= AlignedLimit) break;
|
|
}
|
|
|
|
/* Loop the memory list */
|
|
ActiveMdBlock = NULL;
|
|
ListHead = &KeLoaderBlock->MemoryDescriptorListHead;
|
|
NextEntry = ListHead->Flink;
|
|
while (NextEntry != ListHead)
|
|
{
|
|
/* Get the current descriptors */
|
|
MdBlock = CONTAINING_RECORD(NextEntry,
|
|
MEMORY_ALLOCATION_DESCRIPTOR,
|
|
ListEntry);
|
|
|
|
/* Align the base address and our limit */
|
|
AlignedBase = (MdBlock->BasePage + (Alignment - 1)) &~ Alignment;
|
|
AlignedLimit = MdBlock->PageCount -
|
|
AlignedBase +
|
|
MdBlock->BasePage;
|
|
|
|
/* Check if this is a free block that can satisfy us */
|
|
if ((MdBlock->MemoryType == LoaderFree) &&
|
|
(AlignedLimit <= MdBlock->PageCount) &&
|
|
(PageCount <= AlignedLimit))
|
|
{
|
|
/* It is, stop searching */
|
|
ActiveMdBlock = MdBlock;
|
|
ActiveAlignedBase = AlignedBase;
|
|
break;
|
|
}
|
|
|
|
/* Try the next block */
|
|
NextEntry = NextEntry->Flink;
|
|
}
|
|
|
|
/* See if we came up with an adequate block */
|
|
if (ActiveMdBlock)
|
|
{
|
|
/* Generate a descriptor in it */
|
|
*ReturnedBase = AlignedBase;
|
|
return KiRosBuildNtDescriptor(ActiveMdBlock,
|
|
MemoryType,
|
|
ActiveAlignedBase,
|
|
PageCount);
|
|
}
|
|
} while (TRUE);
|
|
|
|
/* We found a matching block, generate a descriptor with it */
|
|
*ReturnedBase = BasePage;
|
|
return KiRosBuildNtDescriptor(MdBlock, MemoryType, BasePage, PageCount);
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
KiRosBuildArcMemoryList(VOID)
|
|
{
|
|
PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
|
|
MEMORY_DESCRIPTOR *Memory;
|
|
ULONG i;
|
|
|
|
/* Loop all BIOS Memory Descriptors */
|
|
for (i = 0; i < NumberDescriptors; i++)
|
|
{
|
|
/* Get the current descriptor */
|
|
Memory = &MDArray[i];
|
|
|
|
/* Allocate an NT Memory Descriptor */
|
|
Descriptor = KiRosGetMdFromArray();
|
|
if (!Descriptor) return ENOMEM;
|
|
|
|
/* Copy the memory type */
|
|
Descriptor->MemoryType = Memory->MemoryType;
|
|
if (Memory->MemoryType == MemoryFreeContiguous)
|
|
{
|
|
/* Convert this to free */
|
|
Descriptor->MemoryType = LoaderFree;
|
|
}
|
|
else if (Memory->MemoryType == MemorySpecialMemory)
|
|
{
|
|
/* Convert this to special memory */
|
|
Descriptor->MemoryType = LoaderSpecialMemory;
|
|
}
|
|
|
|
/* Copy the range data */
|
|
Descriptor->BasePage = Memory->BasePage;
|
|
Descriptor->PageCount = Memory->PageCount;
|
|
|
|
/* Insert the descriptor */
|
|
if (Descriptor->PageCount) KiRosInsertNtDescriptor(Descriptor);
|
|
}
|
|
|
|
/* All went well */
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KiRosFixupComponentTree(IN PCONFIGURATION_COMPONENT_DATA p,
|
|
IN ULONG i)
|
|
{
|
|
PCONFIGURATION_COMPONENT pp;
|
|
|
|
/* Loop each entry */
|
|
while (p)
|
|
{
|
|
/* Grab the component entry */
|
|
pp = &p->ComponentEntry;
|
|
|
|
/* Fixup the pointers */
|
|
if (pp->Identifier) pp->Identifier = (PVOID)((ULONG_PTR)pp->Identifier + i);
|
|
if (p->ConfigurationData) p->ConfigurationData = (PVOID)((ULONG_PTR)p->ConfigurationData + i);
|
|
if (p->Parent) p->Parent = (PVOID)((ULONG_PTR)p->Parent + i);
|
|
if (p->Sibling) p->Sibling = (PVOID)((ULONG_PTR)p->Sibling + i);
|
|
if (p->Child) p->Child = (PVOID)((ULONG_PTR)p->Child + i);
|
|
|
|
/* Check if we have a child */
|
|
if (p->Child) KiRosFixupComponentTree(p->Child, i);
|
|
|
|
/* Get to the next entry */
|
|
p = p->Sibling;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock,
|
|
IN PLOADER_PARAMETER_BLOCK *NtLoaderBlock)
|
|
{
|
|
PLOADER_PARAMETER_BLOCK LoaderBlock;
|
|
PLDR_DATA_TABLE_ENTRY LdrEntry;
|
|
PLOADER_MODULE RosEntry = NULL;
|
|
ULONG i, j, ModSize;
|
|
PVOID ModStart;
|
|
PCHAR DriverName;
|
|
PCHAR BootPath, HalPath;
|
|
CHAR CommandLine[256];
|
|
PARC_DISK_SIGNATURE RosDiskInfo, ArcDiskInfo;
|
|
PIMAGE_NT_HEADERS NtHeader;
|
|
WCHAR PathToDrivers[] = L"\\SystemRoot\\System32\\drivers\\";
|
|
WCHAR PathToSystem32[] = L"\\SystemRoot\\System32\\";
|
|
WCHAR PathSetup[] = L"\\SystemRoot\\";
|
|
CHAR DriverNameLow[256];
|
|
ULONG Base;
|
|
#if defined(_PPC_)
|
|
ULONG KernelBase = RosLoaderBlock->ModsAddr[0].ModStart;
|
|
#endif
|
|
|
|
/* Set the NT Loader block and initialize it */
|
|
*NtLoaderBlock = KeLoaderBlock = LoaderBlock = &BldrLoaderBlock;
|
|
RtlZeroMemory(LoaderBlock, sizeof(LOADER_PARAMETER_BLOCK));
|
|
|
|
/* Set the NLS Data block */
|
|
LoaderBlock->NlsData = &BldrNlsDataBlock;
|
|
|
|
/* Set the ARC Data block */
|
|
LoaderBlock->ArcDiskInformation = &BldrArcDiskInfo;
|
|
|
|
/* Assume this is from FreeLDR's SetupLdr */
|
|
LoaderBlock->SetupLdrBlock = &BldrSetupBlock;
|
|
|
|
/* Setup the list heads */
|
|
InitializeListHead(&LoaderBlock->LoadOrderListHead);
|
|
InitializeListHead(&LoaderBlock->MemoryDescriptorListHead);
|
|
InitializeListHead(&LoaderBlock->BootDriverListHead);
|
|
InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead);
|
|
|
|
/* Build the free memory map, which uses BIOS Descriptors */
|
|
KiRosBuildBiosMemoryMap();
|
|
|
|
/* Build entries for ReactOS memory ranges, which uses ARC Descriptors */
|
|
KiRosBuildOsMemoryMap();
|
|
|
|
#if defined(_X86_)
|
|
/* Build entries for the reserved map, which uses ARC Descriptors */
|
|
KiRosBuildReservedMemoryMap();
|
|
#endif
|
|
|
|
/* Now convert the BIOS and ARC Descriptors into NT Memory Descirptors */
|
|
KiRosBuildArcMemoryList();
|
|
|
|
/* Loop boot driver list */
|
|
for (i = 0; i < RosLoaderBlock->ModsCount; i++)
|
|
{
|
|
/* Get the ROS loader entry */
|
|
RosEntry = &RosLoaderBlock->ModsAddr[i];
|
|
DriverName = (PCHAR)RosEntry->String;
|
|
ModStart = (PVOID)RosEntry->ModStart;
|
|
ModSize = RosEntry->ModEnd - (ULONG_PTR)ModStart;
|
|
|
|
#if defined(_PPC_)
|
|
ModStart -= KernelBase;
|
|
#endif
|
|
|
|
/* Check if this is any of the NLS files */
|
|
if (!_stricmp(DriverName, "ansi.nls"))
|
|
{
|
|
/* ANSI Code page */
|
|
LoaderBlock->NlsData->AnsiCodePageData = KERNEL_RVA(ModStart);
|
|
|
|
/* Create an MD for it */
|
|
KiRosAllocateNtDescriptor(LoaderNlsData,
|
|
KERNEL_DESCRIPTOR_PAGE(ModStart),
|
|
(ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
|
|
0,
|
|
&Base);
|
|
continue;
|
|
}
|
|
else if (!_stricmp(DriverName, "oem.nls"))
|
|
{
|
|
/* OEM Code page */
|
|
LoaderBlock->NlsData->OemCodePageData = KERNEL_RVA(ModStart);
|
|
|
|
/* Create an MD for it */
|
|
KiRosAllocateNtDescriptor(LoaderNlsData,
|
|
KERNEL_DESCRIPTOR_PAGE(ModStart),
|
|
(ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
|
|
0,
|
|
&Base);
|
|
continue;
|
|
}
|
|
else if (!_stricmp(DriverName, "casemap.nls"))
|
|
{
|
|
/* Unicode Code page */
|
|
LoaderBlock->NlsData->UnicodeCodePageData = KERNEL_RVA(ModStart);
|
|
|
|
/* Create an MD for it */
|
|
KiRosAllocateNtDescriptor(LoaderNlsData,
|
|
KERNEL_DESCRIPTOR_PAGE(ModStart),
|
|
(ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
|
|
0,
|
|
&Base);
|
|
continue;
|
|
}
|
|
|
|
/* Check if this is the SYSTEM hive */
|
|
if (!(_stricmp(DriverName, "system")) ||
|
|
!(_stricmp(DriverName, "system.hiv")))
|
|
{
|
|
/* Save registry data */
|
|
LoaderBlock->RegistryBase = KERNEL_RVA(ModStart);
|
|
LoaderBlock->RegistryLength = ModSize;
|
|
|
|
/* Disable setup mode */
|
|
LoaderBlock->SetupLdrBlock = NULL;
|
|
|
|
/* Create an MD for it */
|
|
KiRosAllocateNtDescriptor(LoaderRegistryData,
|
|
KERNEL_DESCRIPTOR_PAGE(ModStart),
|
|
(ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
|
|
0,
|
|
&Base);
|
|
continue;
|
|
}
|
|
|
|
/* Check if this is the HARDWARE hive */
|
|
if (!(_stricmp(DriverName, "hardware")) ||
|
|
!(_stricmp(DriverName, "hardware.hiv")))
|
|
{
|
|
/* Create an MD for it */
|
|
KiRosAllocateNtDescriptor(LoaderRegistryData,
|
|
KERNEL_DESCRIPTOR_PAGE(ModStart),
|
|
(ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
|
|
0,
|
|
&Base);
|
|
continue;
|
|
}
|
|
|
|
/* Check if this is the kernel */
|
|
if (!(_stricmp(DriverName, "ntoskrnl.exe")))
|
|
{
|
|
/* Create an MD for it */
|
|
KiRosAllocateNtDescriptor(LoaderSystemCode,
|
|
KERNEL_DESCRIPTOR_PAGE(ModStart),
|
|
(ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
|
|
0,
|
|
&Base);
|
|
}
|
|
else if (!(_stricmp(DriverName, "hal.dll")))
|
|
{
|
|
/* Create an MD for the HAL */
|
|
KiRosAllocateNtDescriptor(LoaderHalCode,
|
|
KERNEL_DESCRIPTOR_PAGE(ModStart),
|
|
(ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
|
|
0,
|
|
&Base);
|
|
}
|
|
else
|
|
{
|
|
/* Create an MD for any driver */
|
|
KiRosAllocateNtDescriptor(LoaderBootDriver,
|
|
KERNEL_DESCRIPTOR_PAGE(ModStart),
|
|
(ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT,
|
|
0,
|
|
&Base);
|
|
}
|
|
|
|
#if defined(_PPC_)
|
|
ModStart += 0x80800000;
|
|
#endif
|
|
|
|
/* Lowercase the drivername so we can check its extension later */
|
|
strcpy(DriverNameLow, DriverName);
|
|
_strlwr(DriverNameLow);
|
|
|
|
/* Setup the loader entry */
|
|
LdrEntry = &BldrModules[i];
|
|
RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
|
|
|
|
/* Convert driver name from ANSI to Unicode */
|
|
for (j = 0; j < strlen(DriverName); j++)
|
|
{
|
|
BldrModuleStrings[i][j] = DriverName[j];
|
|
}
|
|
|
|
/* Setup driver name */
|
|
RtlInitUnicodeString(&LdrEntry->BaseDllName, BldrModuleStrings[i]);
|
|
|
|
/* Construct a correct full name */
|
|
BldrModuleStringsFull[i][0] = 0;
|
|
LdrEntry->FullDllName.MaximumLength = 260 * sizeof(WCHAR);
|
|
LdrEntry->FullDllName.Length = 0;
|
|
LdrEntry->FullDllName.Buffer = BldrModuleStringsFull[i];
|
|
|
|
/* Guess the path */
|
|
if (LoaderBlock->SetupLdrBlock)
|
|
{
|
|
UNICODE_STRING TempString;
|
|
RtlInitUnicodeString(&TempString, PathSetup);
|
|
RtlAppendUnicodeStringToString(&LdrEntry->FullDllName, &TempString);
|
|
}
|
|
else if (strstr(DriverNameLow, ".dll") || strstr(DriverNameLow, ".exe"))
|
|
{
|
|
UNICODE_STRING TempString;
|
|
RtlInitUnicodeString(&TempString, PathToSystem32);
|
|
RtlAppendUnicodeStringToString(&LdrEntry->FullDllName, &TempString);
|
|
}
|
|
else /* .sys */
|
|
{
|
|
UNICODE_STRING TempString;
|
|
RtlInitUnicodeString(&TempString, PathToDrivers);
|
|
RtlAppendUnicodeStringToString(&LdrEntry->FullDllName, &TempString);
|
|
}
|
|
|
|
/* Append base name of the driver */
|
|
RtlAppendUnicodeStringToString(&LdrEntry->FullDllName, &LdrEntry->BaseDllName);
|
|
|
|
/* Copy data from Freeldr Module Entry */
|
|
LdrEntry->DllBase = ModStart;
|
|
LdrEntry->SizeOfImage = ModSize;
|
|
|
|
/* Copy additional data */
|
|
NtHeader = RtlImageNtHeader(ModStart);
|
|
LdrEntry->EntryPoint = RVA(ModStart,
|
|
NtHeader->
|
|
OptionalHeader.AddressOfEntryPoint);
|
|
|
|
/* Initialize other data */
|
|
LdrEntry->LoadCount = 1;
|
|
LdrEntry->Flags = LDRP_IMAGE_DLL |
|
|
LDRP_ENTRY_PROCESSED;
|
|
if (RosEntry->Reserved) LdrEntry->Flags |= LDRP_ENTRY_INSERTED;
|
|
|
|
/* Check if this is HAL */
|
|
if (!(_stricmp(DriverName, "hal.dll")))
|
|
{
|
|
/* Check if there is a second entry already */
|
|
if (LoaderBlock->LoadOrderListHead.Flink->Flink !=
|
|
&LoaderBlock->LoadOrderListHead)
|
|
{
|
|
PLIST_ENTRY OldSecondEntry;
|
|
|
|
/* Get the second entry */
|
|
OldSecondEntry =
|
|
LoaderBlock->LoadOrderListHead.Flink->Flink;
|
|
|
|
/* Set up our entry correctly */
|
|
LdrEntry->InLoadOrderLinks.Flink = OldSecondEntry;
|
|
LdrEntry->InLoadOrderLinks.Blink = OldSecondEntry->Blink;
|
|
|
|
/* Make the first entry (always the kernel) point to us */
|
|
LoaderBlock->LoadOrderListHead.Flink->Flink =
|
|
&LdrEntry->InLoadOrderLinks;
|
|
|
|
/* Make the old entry point back to us and continue looping */
|
|
OldSecondEntry->Blink = &LdrEntry->InLoadOrderLinks;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
/* Insert it into the loader block */
|
|
InsertTailList(&LoaderBlock->LoadOrderListHead,
|
|
&LdrEntry->InLoadOrderLinks);
|
|
}
|
|
|
|
/* Now mark the remainder of the FreeLDR 6MB area as "in use" */
|
|
KiRosAllocateNtDescriptor(LoaderMemoryData,
|
|
KERNEL_DESCRIPTOR_PAGE(RosEntry->ModEnd),
|
|
KERNEL_DESCRIPTOR_PAGE((0x80800000 + 0x600000)) -
|
|
KERNEL_DESCRIPTOR_PAGE(RosEntry->ModEnd),
|
|
0,
|
|
&Base);
|
|
|
|
//
|
|
// Check if we have a ramdisk
|
|
//
|
|
if ((RosLoaderBlock->RdAddr) && (RosLoaderBlock->RdLength))
|
|
{
|
|
//
|
|
// Build a descriptor for it
|
|
//
|
|
KiRosAllocateNtDescriptor(LoaderXIPRom,
|
|
KERNEL_DESCRIPTOR_PAGE(RosLoaderBlock->RdAddr),
|
|
(RosLoaderBlock->RdLength + PAGE_SIZE - 1) >> PAGE_SHIFT,
|
|
0,
|
|
&Base);
|
|
}
|
|
|
|
/* Setup command line */
|
|
LoaderBlock->LoadOptions = BldrCommandLine;
|
|
strcpy(BldrCommandLine, RosLoaderBlock->CommandLine);
|
|
|
|
/* Setup the extension block */
|
|
LoaderBlock->Extension = &BldrExtensionBlock;
|
|
LoaderBlock->Extension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
|
|
LoaderBlock->Extension->MajorVersion = 5;
|
|
LoaderBlock->Extension->MinorVersion = 2;
|
|
|
|
/* FreeLDR hackllocates 1536 static pages for the initial boot images */
|
|
LoaderBlock->Extension->LoaderPagesSpanned = 1536 * PAGE_SIZE;
|
|
|
|
/* ReactOS always boots the kernel at 0x80800000 (just like NT 5.2) */
|
|
LoaderBlock->Extension->LoaderPagesSpanned += 0x80800000 - KSEG0_BASE;
|
|
|
|
/* Now convert to pages */
|
|
LoaderBlock->Extension->LoaderPagesSpanned /= PAGE_SIZE;
|
|
|
|
/* Check if FreeLdr detected a ACPI table */
|
|
if (RosLoaderBlock->Flags & MB_FLAGS_ACPI_TABLE)
|
|
{
|
|
/* Set the pointer to something for compatibility */
|
|
LoaderBlock->Extension->AcpiTable = (PVOID)1;
|
|
}
|
|
|
|
/* Now setup the setup block if we have one */
|
|
if (LoaderBlock->SetupLdrBlock)
|
|
{
|
|
/* All we'll setup right now is the flag for text-mode setup */
|
|
LoaderBlock->SetupLdrBlock->Flags = SETUPLDR_TEXT_MODE;
|
|
}
|
|
|
|
/* Make a copy of the command line */
|
|
strcpy(CommandLine, LoaderBlock->LoadOptions);
|
|
|
|
/* Find the first \, separating the ARC path from NT path */
|
|
BootPath = strchr(CommandLine, '\\');
|
|
*BootPath = ANSI_NULL;
|
|
strncpy(BldrArcBootPath, CommandLine, 63);
|
|
LoaderBlock->ArcBootDeviceName = BldrArcBootPath;
|
|
|
|
/* The rest of the string is the NT path */
|
|
HalPath = strchr(BootPath + 1, ' ');
|
|
*HalPath = ANSI_NULL;
|
|
BldrNtBootPath[0] = '\\';
|
|
strncat(BldrNtBootPath, BootPath + 1, 63);
|
|
strcat(BldrNtBootPath,"\\");
|
|
LoaderBlock->NtBootPathName = BldrNtBootPath;
|
|
|
|
/* Set the HAL paths */
|
|
strncpy(BldrArcHalPath, BldrArcBootPath, 63);
|
|
LoaderBlock->ArcHalDeviceName = BldrArcHalPath;
|
|
strcpy(BldrNtHalPath, "\\");
|
|
LoaderBlock->NtHalPathName = BldrNtHalPath;
|
|
|
|
/* Use this new command line */
|
|
strncpy(LoaderBlock->LoadOptions, HalPath + 2, 255);
|
|
|
|
/* Parse it and change every slash to a space */
|
|
BootPath = LoaderBlock->LoadOptions;
|
|
do {if (*BootPath == '/') *BootPath = ' ';} while (*BootPath++);
|
|
|
|
/* Now let's loop ARC disk information */
|
|
for (i = 0; i < RosLoaderBlock->DrivesCount; i++)
|
|
{
|
|
/* Get the ROS loader entry */
|
|
RosDiskInfo = &RosLoaderBlock->DrivesAddr[i];
|
|
|
|
/* Get the ARC structure */
|
|
ArcDiskInfo = &BldrDiskInfo[i];
|
|
|
|
/* Copy the data over */
|
|
ArcDiskInfo->Signature = RosDiskInfo->Signature;
|
|
ArcDiskInfo->CheckSum = RosDiskInfo->CheckSum;
|
|
|
|
/* Copy the ARC Name */
|
|
strcpy(BldrArcNames[i], RosDiskInfo->ArcName);
|
|
ArcDiskInfo->ArcName = BldrArcNames[i];
|
|
|
|
/* Insert into the list */
|
|
InsertTailList(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead,
|
|
&ArcDiskInfo->ListEntry);
|
|
}
|
|
|
|
/* Copy the ARC Hardware Tree */
|
|
RtlCopyMemory(BldrArcHwBuffer, (PVOID)RosLoaderBlock->ArchExtra, 16 * 1024);
|
|
LoaderBlock->ConfigurationRoot = (PVOID)BldrArcHwBuffer;
|
|
|
|
/* Apply fixups */
|
|
KiRosFixupComponentTree(LoaderBlock->ConfigurationRoot,
|
|
(ULONG_PTR)BldrArcHwBuffer -
|
|
RosLoaderBlock->ArchExtra);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KiSetupSyscallHandler();
|
|
|
|
VOID
|
|
NTAPI
|
|
KiRosPrepareForSystemStartup(IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock)
|
|
{
|
|
PLOADER_PARAMETER_BLOCK NtLoaderBlock;
|
|
ULONG size, i = 0, *ent;
|
|
#if defined(_X86_)
|
|
PKTSS Tss;
|
|
PKGDTENTRY TssEntry;
|
|
KDESCRIPTOR IdtDescriptor;
|
|
|
|
__sidt(&IdtDescriptor.Limit);
|
|
RtlCopyMemory(KiBootIdt, (PVOID)IdtDescriptor.Base, IdtDescriptor.Limit + 1);
|
|
IdtDescriptor.Base = (ULONG)&KiBootIdt;
|
|
IdtDescriptor.Limit = sizeof(KiBootIdt) - 1;
|
|
|
|
/* Load the GDT and IDT */
|
|
Ke386SetGlobalDescriptorTable(&KiGdtDescriptor.Limit);
|
|
__lidt(&IdtDescriptor.Limit);
|
|
|
|
/* Initialize the boot TSS */
|
|
Tss = &KiBootTss;
|
|
TssEntry = &KiBootGdt[KGDT_TSS / sizeof(KGDTENTRY)];
|
|
TssEntry->HighWord.Bits.Type = I386_TSS;
|
|
TssEntry->HighWord.Bits.Pres = 1;
|
|
TssEntry->HighWord.Bits.Dpl = 0;
|
|
TssEntry->BaseLow = (USHORT)((ULONG_PTR)Tss & 0xFFFF);
|
|
TssEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Tss >> 16);
|
|
TssEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Tss >> 24);
|
|
|
|
/* Set the TSS selector */
|
|
Ke386SetTr(KGDT_TSS);
|
|
#endif
|
|
|
|
#if defined(_M_PPC)
|
|
// Zero bats. We might have residual bats set that will interfere with
|
|
// our mapping of ofwldr.
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
SetBat(i, 0, 0, 0); SetBat(i, 1, 0, 0);
|
|
}
|
|
KiSetupSyscallHandler();
|
|
DbgPrint("Kernel Power (%08x)\n", LoaderBlock);
|
|
DbgPrint("ArchExtra (%08x)!\n", LoaderBlock->ArchExtra);
|
|
#endif
|
|
|
|
/* Save pointer to ROS Block */
|
|
KeRosLoaderBlock = LoaderBlock;
|
|
|
|
/* Save memory manager data */
|
|
KeMemoryMapRangeCount = 0;
|
|
if (LoaderBlock->Flags & MB_FLAGS_MMAP_INFO)
|
|
{
|
|
/* We have a memory map from the nice BIOS */
|
|
ent = ((PULONG)(LoaderBlock->MmapAddr - sizeof(ULONG)));
|
|
size = *ent;
|
|
i = 0;
|
|
|
|
/* Map it until we run out of size */
|
|
while (i < LoaderBlock->MmapLength)
|
|
{
|
|
/* Copy into the Kernel Memory Map */
|
|
memcpy (&KeMemoryMap[KeMemoryMapRangeCount],
|
|
(PVOID)(LoaderBlock->MmapAddr + i),
|
|
sizeof(ADDRESS_RANGE));
|
|
|
|
/* Increase Memory Map Count */
|
|
KeMemoryMapRangeCount++;
|
|
|
|
/* Increase Size */
|
|
i += size;
|
|
}
|
|
|
|
/* Save data */
|
|
LoaderBlock->MmapLength = KeMemoryMapRangeCount * sizeof(ADDRESS_RANGE);
|
|
LoaderBlock->MmapAddr = (ULONG)KeMemoryMap;
|
|
}
|
|
else
|
|
{
|
|
/* Nothing from BIOS */
|
|
LoaderBlock->MmapLength = 0;
|
|
LoaderBlock->MmapAddr = (ULONG)KeMemoryMap;
|
|
}
|
|
|
|
/* Convert the loader block */
|
|
KiRosFrldrLpbToNtLpb(KeRosLoaderBlock, &NtLoaderBlock);
|
|
|
|
#if defined(_M_PPC)
|
|
DbgPrint("Finished KiRosFrldrLpbToNtLpb\n");
|
|
#endif
|
|
|
|
/* Do general System Startup */
|
|
KiSystemStartup(NtLoaderBlock);
|
|
}
|