⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wlmemory.c

📁 ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机理和API函数调用几乎相同。甚至可以兼容XP的程序。喜欢研究系统内核的人可以看一看。
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * PROJECT:         EFI Windows Loader
 * LICENSE:         GPL - See COPYING in the top level directory
 * FILE:            freeldr/winldr/wlmemory.c
 * PURPOSE:         Memory related routines
 * PROGRAMMERS:     Aleksey Bragin (aleksey@reactos.org)
 */

/* INCLUDES ***************************************************************/

#include <freeldr.h>

#include <ndk/asm.h>
#include <debug.h>

extern ULONG TotalNLSSize;

// This is needed because headers define wrong one for ReactOS
#undef KIP0PCRADDRESS
#define KIP0PCRADDRESS                      0xffdff000

//
// This is the zone which is used by the OS loader
//
#define LOADER_HIGH_ZONE ((16*1024*1024) >> MM_PAGE_SHIFT) //16Mb page

#define HYPER_SPACE_ENTRY       0x300

//TODO: Check if this is correct
PCHAR  MemTypeDesc[]  = {
    "ExceptionBlock    ",
    "SystemBlock       ",
    "Free              ",
    "Bad               ",
    "LoadedProgram     ",
    "FirmwareTemporary ",
    "FirmwarePermanent ",
    "OsloaderHeap      ",
    "OsloaderStack     ",
    "SystemCode        ",
    "HalCode           ",
    "BootDriver        ",
    "ConsoleInDriver   ",
    "ConsoleOutDriver  ",
    "StartupDpcStack   ",
    "StartupKernelStack",
    "StartupPanicStack ",
    "StartupPcrPage    ",
    "StartupPdrPage    ",
    "RegistryData      ",
    "MemoryData        ",
    "NlsData           ",
    "SpecialMemory     ",
    "BBTMemory         ",
    "Maximum           "
    };

VOID
WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);


VOID
MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
                   UINT64 BasePage,
                   UINT64 PageCount,
                   ULONG Type);
VOID
WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
                       IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor);

VOID
WinLdrRemoveDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR Descriptor);

VOID
WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss);

// This is needed only for SetProcessorContext routine
#pragma pack(2)
	typedef struct
	{
		USHORT Limit;
		ULONG Base;
	} GDTIDT;
#pragma pack(4)

// this is needed for new IDT filling
#if 0
extern ULONG_PTR i386DivideByZero;
extern ULONG_PTR i386DebugException;
extern ULONG_PTR i386NMIException;
extern ULONG_PTR i386Breakpoint;
extern ULONG_PTR i386Overflow;
extern ULONG_PTR i386BoundException;
extern ULONG_PTR i386InvalidOpcode;
extern ULONG_PTR i386FPUNotAvailable;
extern ULONG_PTR i386DoubleFault;
extern ULONG_PTR i386CoprocessorSegment;
extern ULONG_PTR i386InvalidTSS;
extern ULONG_PTR i386SegmentNotPresent;
extern ULONG_PTR i386StackException;
extern ULONG_PTR i386GeneralProtectionFault;
extern ULONG_PTR i386PageFault; // exc 14
extern ULONG_PTR i386CoprocessorError; // exc 16
extern ULONG_PTR i386AlignmentCheck; // exc 17
#endif

/* GLOBALS ***************************************************************/

PHARDWARE_PTE PDE;
PHARDWARE_PTE HalPT;

PUCHAR PhysicalPageTablesBuffer;
PUCHAR KernelPageTablesBuffer;
ULONG PhysicalPageTables;
ULONG KernelPageTables;

MEMORY_ALLOCATION_DESCRIPTOR Mad[1024];
ULONG MadCount = 0;


/* FUNCTIONS **************************************************************/

BOOLEAN
MempAllocatePageTables()
{
	ULONG NumPageTables, TotalSize;
	PUCHAR Buffer;
	// It's better to allocate PDE + PTEs contigiuos

	// Max number of entries = MaxPageNum >> 10
	// FIXME: This is a number to describe ALL physical memory
	// and windows doesn't expect ALL memory mapped...
	NumPageTables = (GetSystemMemorySize() >> MM_PAGE_SHIFT) >> 10;

	DbgPrint((DPRINT_WINDOWS, "NumPageTables = %d\n", NumPageTables));

	// Allocate memory block for all these things:
	// PDE, HAL mapping page table, physical mapping, kernel mapping
	TotalSize = (1+1+NumPageTables*2)*MM_PAGE_SIZE;
	Buffer = MmAllocateMemory(TotalSize);

	if (Buffer == NULL)
	{
		UiMessageBox("Impossible to allocate memory block for page tables!");
		return FALSE;
	}

	// Zero all this memory block
	RtlZeroMemory(Buffer, TotalSize);

	// Set up pointers correctly now
	PDE = (PHARDWARE_PTE)Buffer;

	// Map the page directory at 0xC0000000 (maps itself)
	PDE[HYPER_SPACE_ENTRY].PageFrameNumber = (ULONG)PDE >> MM_PAGE_SHIFT;
	PDE[HYPER_SPACE_ENTRY].Valid = 1;
	PDE[HYPER_SPACE_ENTRY].Write = 1;

	// The last PDE slot is allocated for HAL's memory mapping (Virtual Addresses 0xFFC00000 - 0xFFFFFFFF)
	HalPT = (PHARDWARE_PTE)&Buffer[MM_PAGE_SIZE*1];

	// Map it
	PDE[1023].PageFrameNumber = (ULONG)HalPT >> MM_PAGE_SHIFT;
	PDE[1023].Valid = 1;
	PDE[1023].Write = 1;

	// Store pointers to the tables for easier access
	PhysicalPageTablesBuffer = &Buffer[MM_PAGE_SIZE*2];
	KernelPageTablesBuffer = PhysicalPageTablesBuffer + NumPageTables*MM_PAGE_SIZE;

	// Zero counters of page tables used
	PhysicalPageTables = 0;
	KernelPageTables = 0;

	return TRUE;
}

VOID
MempAllocatePTE(ULONG Entry, PHARDWARE_PTE *PhysicalPT, PHARDWARE_PTE *KernelPT)
{
	//Print(L"Creating PDE Entry %X\n", Entry);

	// Identity mapping
	*PhysicalPT = (PHARDWARE_PTE)&PhysicalPageTablesBuffer[PhysicalPageTables*MM_PAGE_SIZE];
	PhysicalPageTables++;

	PDE[Entry].PageFrameNumber = (ULONG)*PhysicalPT >> MM_PAGE_SHIFT;
	PDE[Entry].Valid = 1;
	PDE[Entry].Write = 1;

	if (Entry+(KSEG0_BASE >> 22) > 1023)
	{
		DbgPrint((DPRINT_WINDOWS, "WARNING! Entry: %X > 1023\n", Entry+(KSEG0_BASE >> 22)));
	}

	// Kernel-mode mapping
	*KernelPT = (PHARDWARE_PTE)&KernelPageTablesBuffer[KernelPageTables*MM_PAGE_SIZE];
	KernelPageTables++;

	PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber = ((ULONG)*KernelPT >> MM_PAGE_SHIFT);
	PDE[Entry+(KSEG0_BASE >> 22)].Valid = 1;
	PDE[Entry+(KSEG0_BASE >> 22)].Write = 1;
}

BOOLEAN
MempSetupPaging(IN ULONG StartPage,
				IN ULONG NumberOfPages)
{
	PHARDWARE_PTE PhysicalPT;
	PHARDWARE_PTE KernelPT;
	ULONG Entry, Page;

	//Print(L"MempSetupPaging: SP 0x%X, Number: 0x%X\n", StartPage, NumberOfPages);
	
	// HACK
	if (StartPage+NumberOfPages >= 0x80000)
	{
		//
		// We can't map this as it requires more than 1 PDE
		// and in fact it's not possible at all ;)
		//
		//Print(L"skipping...\n");
		return TRUE;
	}

	//
	// Now actually set up the page tables for identity mapping
	//
	for (Page=StartPage; Page < StartPage+NumberOfPages; Page++)
	{
		Entry = Page >> 10;

		if (((PULONG)PDE)[Entry] == 0)
		{
			MempAllocatePTE(Entry, &PhysicalPT, &KernelPT);
		}
		else
		{
			PhysicalPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT);
			KernelPT = (PHARDWARE_PTE)(PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber << MM_PAGE_SHIFT);
		}

		if (Page == 0)
		{
			PhysicalPT[Page & 0x3ff].PageFrameNumber = Page;
			PhysicalPT[Page & 0x3ff].Valid = 0;
			PhysicalPT[Page & 0x3ff].Write = 0;

			KernelPT[Page & 0x3ff].PageFrameNumber = Page;
			KernelPT[Page & 0x3ff].Valid = 0;
			KernelPT[Page & 0x3ff].Write = 0;
		}
		else
		{
			PhysicalPT[Page & 0x3ff].PageFrameNumber = Page;
			PhysicalPT[Page & 0x3ff].Valid = 1;
			PhysicalPT[Page & 0x3ff].Write = 1;

			KernelPT[Page & 0x3ff].PageFrameNumber = Page;
			KernelPT[Page & 0x3ff].Valid = 1;
			KernelPT[Page & 0x3ff].Write = 1;
		}
	}

	return TRUE;
}

VOID
MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
                   UINT64 BasePage,
                   UINT64 PageCount,
                   ULONG Type)
{
	BOOLEAN Status;

	//
	// Check for some weird stuff at the top
	//
	if (BasePage + PageCount > 0xF0000)
	{
		//
		// Just skip this, without even adding to MAD list
		//
		return;
	}

	//
	// Base page and page count are always set
	//
	Mad[MadCount].BasePage = BasePage;
	Mad[MadCount].PageCount = PageCount;

	//
	// Check if it's more than the allowed for OS loader
	// if yes - don't map the pages, just add as FirmwareTemporary
	//
	if (BasePage + PageCount > LOADER_HIGH_ZONE && (Type != LoaderNlsData))
	{
		Mad[MadCount].MemoryType = LoaderFirmwareTemporary;

		WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
		MadCount++;

		Status = MempSetupPaging(BasePage, PageCount);
		if (!Status)
		{
			DbgPrint((DPRINT_WINDOWS, "Error during WinLdrpSetupPaging\n"));
			return;
		}
		return;
	}
	
	if (BasePage == 0xFFF && PageCount == 1)
	{
		Mad[MadCount].MemoryType = LoaderSpecialMemory;

		WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
		MadCount++;

		//
		// Map it
		//
		Status = MempSetupPaging(BasePage, PageCount);
		if (!Status)
		{
			DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging\n"));
			return;
		}
	}
	else if (BasePage == 0 && PageCount == 1)
	{
		Mad[MadCount].MemoryType = LoaderFirmwarePermanent;

		WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
		MadCount++;

		//
		// Map it
		//
		Status = MempSetupPaging(BasePage, PageCount);
		if (!Status)
		{
			DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging\n"));
			return;
		}
	}
	else
	{
		//
		// Set memory type
		//
		Mad[MadCount].MemoryType = Type;

		//
		// Add descriptor
		//
		WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
		MadCount++;

		//
		// Map it
		//
		Status = MempSetupPaging(BasePage, PageCount);
		if (!Status)
		{
			DbgPrint((DPRINT_WINDOWS, "Error during MempSetupPaging\n"));
			return;
		}
	}
}

BOOLEAN
WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
                   ULONG PcrBasePage,
                   ULONG TssBasePage,
                   PVOID GdtIdt)
{
	ULONG i, PagesCount;
	ULONG LastPageIndex, LastPageType, NtType;
	PPAGE_LOOKUP_TABLE_ITEM MemoryMap;
	ULONG NoEntries;
	PKTSS Tss;
	PVOID NlsBase = VaToPa(((PNLS_DATA_BLOCK)VaToPa(LoaderBlock->NlsData))->AnsiCodePageData);
	ULONG NlsBasePage = (ULONG_PTR)NlsBase >> PAGE_SHIFT;

	//
	// Creating a suitable memory map for the Windows can be tricky, so let's
	// give a few advices:
	// 1) One must not map the whole available memory pages to PDE!
	//    Map only what's needed - 16Mb, 24Mb, 32Mb max I think,
	//    thus occupying 4, 6 or 8 PDE entries for identical mapping,
	//    the same quantity for KSEG0_BASE mapping, one more entry for
	//    hyperspace and one more entry for HAL physical pages mapping.
	// 2) Memory descriptors must map *the whole* physical memory
	//    showing any memory above 16/24/32 as FirmwareTemporary
	//
	// 3) Overall memory blocks count must not exceed 30
	//

	//
	// During MmInitMachineDependent, the kernel zeroes PDE at the following address
	// 0xC0300000 - 0xC03007FC
	//
	// Then it finds the best place for non-paged pool:
	// StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD
	//

	// Before we start mapping pages, create a block of memory, which will contain
	// PDE and PTEs
	if (MempAllocatePageTables() == FALSE)
		return FALSE;

	// Setup an entry for each descriptor
	MemoryMap = MmGetMemoryMap(&NoEntries);
	if (MemoryMap == NULL)
	{
		UiMessageBox("Can not retrieve the current memory map");
		return FALSE;
	}

	DbgPrint((DPRINT_WINDOWS, "Got memory map with %d entries, NlsBasePage 0x%X\n",
		NoEntries, NlsBasePage));

	// Construct a good memory map from what we've got
	PagesCount = 1;
	LastPageIndex = 0;
	LastPageType = MemoryMap[0].PageAllocated;
	for(i=1;i<NoEntries;i++)
	{
		if (MemoryMap[i].PageAllocated == LastPageType &&
			(i < NlsBasePage || i > NlsBasePage+TotalNLSSize) && (i != NoEntries-1) )
		{
			PagesCount++;
		}
		else if (i == NlsBasePage)
		{
			// This is NLS data, map it accordingly
			// It's VERY important for NT kernel - it calculates size of NLS
			// tables based on NlsData memory type descriptors!

			// Firstly map what we already have (if we have any)
			// Convert mem types
			if (LastPageType == 0)
				NtType = LoaderFree;
			else if (LastPageType != 0 && LastPageType != 1)
				NtType = LoaderFirmwarePermanent;
			else if (LastPageType == 1)
				NtType = LoaderSystemCode;
			else
				NtType = LoaderFirmwarePermanent;

			if (PagesCount > 0)
				MempAddMemoryBlock(LoaderBlock, LastPageIndex, PagesCount, NtType);

			// Then map nls data
			MempAddMemoryBlock(LoaderBlock, NlsBasePage, TotalNLSSize, LoaderNlsData);

			// skip them
			i += TotalNLSSize;

			// Reset our counter vars
			LastPageIndex = i;
			LastPageType = MemoryMap[i].PageAllocated;
			PagesCount = 1;

			continue;
		}
		else
		{
			// Add the resulting region

			// Convert mem types
			if (LastPageType == 0)
			{
				NtType = LoaderFree;
			}
			else if (LastPageType != 0 && LastPageType != 1)
			{
				NtType = LoaderFirmwarePermanent;
			}
			else if (LastPageType == 1)
			{
				NtType = LoaderSystemCode;
			}
			else
			{
				NtType = LoaderFirmwarePermanent;
			}

			MempAddMemoryBlock(LoaderBlock, LastPageIndex, PagesCount, NtType);

			// Reset our counter vars
			LastPageIndex = i;
			LastPageType = MemoryMap[i].PageAllocated;
			PagesCount = 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -