/* * 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 #define NDEBUG #include #if defined(_PPC_) #include #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); }