From 37ae229f62a13cee4681a9da25248e971c47c6d0 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Sat, 25 Aug 2007 09:38:13 +0000 Subject: [PATCH] - Do not ignore BIOS memory map anymore. Private BIOS ranges (such as ACPI, SMBIOS, VideoROM, etc) are not assumed "free" anymore (which would result in hardware failure, crashes and/or corrupted memory). - Enhance the FreeLDR 2 NTLDR Compatibility Layer: * Use a special routine for grabbing static memory descriptors, so that if we ever run out, we will bugcheck. * The descriptors need to contain physical addresses, not virtual. Do proper fixups to handle this. * Add a "Free" memory descriptor for all memory on the system. This needs to be fragmented later. * Add memory descriptors for each reserved entry in the BIOS memory map. * Add memory descriptors for the PDE and KPCR pages that FreeLDR allocates. * Add a memory descriptor for page 0, which is reserved. * Add a memory descriptor for the Video frame buffer at 0xA0000. This is the location on most systems, and also the location that ReactOS hard-codes in other Mm code. - Bug found and NTLDR memory descriptor analysis by Alex. svn path=/trunk/; revision=28537 --- .../boot/freeldr/freeldr/reactos/reactos.c | 2 +- reactos/ntoskrnl/ke/freeldr.c | 140 ++++++++++++++++-- reactos/ntoskrnl/ke/i386/kiinit.c | 8 +- reactos/ntoskrnl/mm/mminit.c | 47 ++++++ 4 files changed, 178 insertions(+), 19 deletions(-) diff --git a/reactos/boot/freeldr/freeldr/reactos/reactos.c b/reactos/boot/freeldr/freeldr/reactos/reactos.c index 9de94fd082f..aaece17eee5 100644 --- a/reactos/boot/freeldr/freeldr/reactos/reactos.c +++ b/reactos/boot/freeldr/freeldr/reactos/reactos.c @@ -599,7 +599,7 @@ LoadAndBootReactOS(PCSTR OperatingSystemName) if (LoaderBlock.MmapLength) { ULONG i; - + LoaderBlock.Flags |= MB_FLAGS_MEM_INFO | MB_FLAGS_MMAP_INFO; LoaderBlock.MmapAddr = (unsigned long)&reactos_memory_map; reactos_memory_map_descriptor_size = sizeof(memory_map_t); // GetBiosMemoryMap uses a fixed value of 24 for (i=0; i<(LoaderBlock.MmapLength/sizeof(memory_map_t)); i++) diff --git a/reactos/ntoskrnl/ke/freeldr.c b/reactos/ntoskrnl/ke/freeldr.c index 88d72a73a6f..64f1b0b65b8 100644 --- a/reactos/ntoskrnl/ke/freeldr.c +++ b/reactos/ntoskrnl/ke/freeldr.c @@ -23,6 +23,12 @@ ULONG MmFreeLdrPageDirectoryEnd; /* FreeLDR Loader Data */ PROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock; BOOLEAN AcpiTableDetected; +ADDRESS_RANGE KeMemoryMap[64]; +ULONG KeMemoryMapRangeCount; + +/* NT Loader Module/Descriptor Count */ +ULONG BldrCurrentMd; +ULONG BldrCurrentMod; /* NT Loader Data. Eats up about 80KB! */ LOADER_PARAMETER_BLOCK BldrLoaderBlock; // 0x0000 @@ -45,6 +51,15 @@ ARC_DISK_SIGNATURE BldrDiskInfo[32]; // 0x1413C /* FUNCTIONS *****************************************************************/ +PMEMORY_ALLOCATION_DESCRIPTOR +NTAPI +KiRosGetMdFromArray(VOID) +{ + /* Return the next MD from the list, but make sure we don't overflow */ + if (BldrCurrentMd > 64) KEBUGCHECK(0); + return &BldrMemoryDescriptors[BldrCurrentMd++]; +} + VOID NTAPI KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock, @@ -69,6 +84,7 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock, AcpiTableDetected = (RosLoaderBlock->Flags & MB_FLAGS_ACPI_TABLE) ? TRUE : FALSE; MmFreeLdrMemHigher = RosLoaderBlock->MemHigher; MmFreeLdrPageDirectoryEnd = RosLoaderBlock->PageDirectoryEnd; + if (!MmFreeLdrPageDirectoryEnd) MmFreeLdrPageDirectoryEnd = 0x40000; /* Set the NT Loader block and initialize it */ *NtLoaderBlock = LoaderBlock = &BldrLoaderBlock; @@ -89,6 +105,64 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock, InitializeListHead(&LoaderBlock->BootDriverListHead); InitializeListHead(&LoaderBlock->ArcDiskInformation->DiskSignatureListHead); + /* Create one large blob of free memory */ + MdEntry = KiRosGetMdFromArray(); + MdEntry->MemoryType = LoaderFree; + MdEntry->BasePage = 0; + MdEntry->PageCount = MmFreeLdrMemHigher / 4; + InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); + + /* + * FIXME: Instead of just "inserting" MDs into the list, + * we need to make then be "consumed" from the Free Descriptor. + * This will happen soon (and also ensure a sorted list). + */ + + /* Loop the BIOS Memory Map */ + for (j = 0; j < KeMemoryMapRangeCount; j++) + { + /* Check if this is a reserved entry */ + if (KeMemoryMap[j].Type == 2) + { + /* It is, build an entry for it */ + MdEntry = KiRosGetMdFromArray(); + MdEntry->MemoryType = LoaderSpecialMemory; + MdEntry->BasePage = KeMemoryMap[j].BaseAddrLow >> PAGE_SHIFT; + MdEntry->PageCount = (KeMemoryMap[j].LengthLow + PAGE_SIZE - 1) >> PAGE_SHIFT; + InsertTailList(&LoaderBlock->MemoryDescriptorListHead, + &MdEntry->ListEntry); + } + } + + /* Page 0 is reserved: build an entry for it */ + MdEntry = KiRosGetMdFromArray(); + MdEntry->MemoryType = LoaderFirmwarePermanent; + MdEntry->BasePage = 0; + MdEntry->PageCount = 1; + InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); + + /* Build an entry for the KPCR (which we put in page 1) */ + MdEntry = KiRosGetMdFromArray(); + MdEntry->MemoryType = LoaderMemoryData; + MdEntry->BasePage = 1; + MdEntry->PageCount = 1; + InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); + + /* Build an entry for the PDE */ + MdEntry = KiRosGetMdFromArray(); + MdEntry->MemoryType = LoaderMemoryData; + MdEntry->BasePage = (ULONG_PTR)MmGetPageDirectory() >> PAGE_SHIFT; + MdEntry->PageCount = (MmFreeLdrPageDirectoryEnd - + (ULONG_PTR)MmGetPageDirectory()) / PAGE_SIZE; + InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); + + /* Mark Video ROM as reserved */ + MdEntry = KiRosGetMdFromArray(); + MdEntry->MemoryType = LoaderFirmwarePermanent; + MdEntry->BasePage = 0xA0000 >> PAGE_SHIFT; + MdEntry->PageCount = (0xE8000 - 0xA0000) / PAGE_SIZE; + InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); + /* Loop boot driver list */ for (i = 0; i < RosLoaderBlock->ModsCount; i++) { @@ -106,9 +180,9 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock, LoaderBlock->NlsData->AnsiCodePageData = ModStart; /* Create an MD for it */ - MdEntry = &BldrMemoryDescriptors[i]; + MdEntry = KiRosGetMdFromArray(); MdEntry->MemoryType = LoaderNlsData; - MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT; + MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >> PAGE_SHIFT; MdEntry->PageCount = (ModSize + PAGE_SIZE - 1)>> PAGE_SHIFT; InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); @@ -121,9 +195,9 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock, LoaderBlock->NlsData->OemCodePageData = ModStart; /* Create an MD for it */ - MdEntry = &BldrMemoryDescriptors[i]; + MdEntry = KiRosGetMdFromArray(); MdEntry->MemoryType = LoaderNlsData; - MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT; + MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >> PAGE_SHIFT; MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT; InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); @@ -136,9 +210,9 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock, LoaderBlock->NlsData->UnicodeCodePageData = ModStart; /* Create an MD for it */ - MdEntry = &BldrMemoryDescriptors[i]; + MdEntry = KiRosGetMdFromArray(); MdEntry->MemoryType = LoaderNlsData; - MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT; + MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >> PAGE_SHIFT; MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT; InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); @@ -158,9 +232,9 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock, LoaderBlock->SetupLdrBlock = NULL; /* Create an MD for it */ - MdEntry = &BldrMemoryDescriptors[i]; + MdEntry = KiRosGetMdFromArray(); MdEntry->MemoryType = LoaderRegistryData; - MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT; + MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >> PAGE_SHIFT; MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT; InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); @@ -173,9 +247,9 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock, { /* Create an MD for it */ ModStart = RVA(ModStart, KSEG0_BASE); - MdEntry = &BldrMemoryDescriptors[i]; + MdEntry = KiRosGetMdFromArray(); MdEntry->MemoryType = LoaderRegistryData; - MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT; + MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >> PAGE_SHIFT; MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT; InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); @@ -186,9 +260,9 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock, if (!(_stricmp(DriverName, "ntoskrnl.exe"))) { /* Create an MD for it */ - MdEntry = &BldrMemoryDescriptors[i]; + MdEntry = KiRosGetMdFromArray(); MdEntry->MemoryType = LoaderSystemCode; - MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT; + MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >> PAGE_SHIFT; MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT; InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); @@ -196,9 +270,9 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock, else if (!(_stricmp(DriverName, "hal.dll"))) { /* Create an MD for the HAL */ - MdEntry = &BldrMemoryDescriptors[i]; + MdEntry = KiRosGetMdFromArray(); MdEntry->MemoryType = LoaderHalCode; - MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT; + MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >> PAGE_SHIFT; MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT; InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); @@ -206,9 +280,9 @@ KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock, else { /* Create an MD for any driver */ - MdEntry = &BldrMemoryDescriptors[i]; + MdEntry = KiRosGetMdFromArray(); MdEntry->MemoryType = LoaderBootDriver; - MdEntry->BasePage = (ULONG_PTR)ModStart >> PAGE_SHIFT; + MdEntry->BasePage = ((ULONG_PTR)ModStart &~ KSEG0_BASE) >> PAGE_SHIFT; MdEntry->PageCount = (ModSize + PAGE_SIZE - 1) >> PAGE_SHIFT; InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &MdEntry->ListEntry); @@ -356,6 +430,7 @@ KiRosPrepareForSystemStartup(IN ULONG Dummy, IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock) { PLOADER_PARAMETER_BLOCK NtLoaderBlock; + ULONG size, i; #if defined(_M_IX86) PKTSS Tss; PKGDTENTRY TssEntry; @@ -387,6 +462,39 @@ KiRosPrepareForSystemStartup(IN ULONG Dummy, KSEG0_BASE; MmFreeLdrLastKrnlPhysAddr = MmFreeLdrLastKernelAddress - KSEG0_BASE; + KeMemoryMapRangeCount = 0; + if (LoaderBlock->Flags & MB_FLAGS_MMAP_INFO) + { + /* We have a memory map from the nice BIOS */ + size = *((PULONG)(LoaderBlock->MmapAddr - sizeof(ULONG))); + 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; + } + #if defined(_M_IX86) /* Set up the VDM Data */ NtEarlyInitVdm(); diff --git a/reactos/ntoskrnl/ke/i386/kiinit.c b/reactos/ntoskrnl/ke/i386/kiinit.c index b84d0664d1f..1bddc5ea1b5 100644 --- a/reactos/ntoskrnl/ke/i386/kiinit.c +++ b/reactos/ntoskrnl/ke/i386/kiinit.c @@ -18,6 +18,10 @@ KSPIN_LOCK KiFreezeExecutionLock; KSPIN_LOCK Ki486CompatibilityLock; +/* BIOS Memory Map. Not NTLDR-compliant yet */ +extern ULONG KeMemoryMapRangeCount; +extern ADDRESS_RANGE KeMemoryMap[64]; + /* FUNCTIONS *****************************************************************/ VOID @@ -536,8 +540,8 @@ KiInitializeKernel(IN PKPROCESS InitProcess, MmInit1(MmFreeLdrFirstKrnlPhysAddr, MmFreeLdrLastKrnlPhysAddr, MmFreeLdrLastKernelAddress, - NULL, - 0, + KeMemoryMap, + KeMemoryMapRangeCount, 4096); /* Set basic CPU Features that user mode can read */ diff --git a/reactos/ntoskrnl/mm/mminit.c b/reactos/ntoskrnl/mm/mminit.c index 099f81f7d00..eb1e9c6f954 100644 --- a/reactos/ntoskrnl/mm/mminit.c +++ b/reactos/ntoskrnl/mm/mminit.c @@ -301,6 +301,34 @@ MmInitVirtualMemory(ULONG_PTR LastKernelAddress, MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory); } +PCHAR +MemType[] = { + "ExceptionBlock ", // ? + "SystemBlock ", // ? + "Free ", + "Bad ", // used + "LoadedProgram ", // == Free + "FirmwareTemporary ", // == Free + "FirmwarePermanent ", // == Bad + "OsloaderHeap ", // used + "OsloaderStack ", // == Free + "SystemCode ", + "HalCode ", + "BootDriver ", // not used + "ConsoleInDriver ", // ? + "ConsoleOutDriver ", // ? + "StartupDpcStack ", // ? + "StartupKernelStack", // ? + "StartupPanicStack ", // ? + "StartupPcrPage ", // ? + "StartupPdrPage ", // ? + "RegistryData ", // used + "MemoryData ", // not used + "NlsData ", // used + "SpecialMemory ", // == Bad + "BBTMemory " // == Bad +}; + VOID INIT_FUNCTION NTAPI @@ -324,6 +352,25 @@ MmInit1(ULONG_PTR FirstKrnlPhysAddr, LastKrnlPhysAddr, LastKernelAddress); + /* Dump memory descriptors */ + { + PLIST_ENTRY NextEntry; + PMEMORY_ALLOCATION_DESCRIPTOR Md; + ULONG TotalPages = 0; + + DPRINT1("Base\t\tLength\t\tType\n"); + for (NextEntry = KeLoaderBlock->MemoryDescriptorListHead.Flink; + NextEntry != &KeLoaderBlock->MemoryDescriptorListHead; + NextEntry = NextEntry->Flink) + { + Md = CONTAINING_RECORD(NextEntry, MEMORY_ALLOCATION_DESCRIPTOR, ListEntry); + DPRINT1("%08lX\t%08lX\t%s\n", Md->BasePage, Md->PageCount, MemType[Md->MemoryType]); + TotalPages += Md->PageCount; + } + + DPRINT1("Total: %08lX (%d MB)\n", TotalPages, (TotalPages * PAGE_SIZE) / 1024 / 1024); + } + /* Set the page directory */ PsGetCurrentProcess()->Pcb.DirectoryTableBase.LowPart = (ULONG)MmGetPageDirectory();