📄 loader.c
字号:
/*
* FreeLoader
* Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
* Copyright (C) 2005 Alex Ionescu <alex@relsoft.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define _NTSYSTEM_
#include <freeldr.h>
#define NDEBUG
#include <debug.h>
#undef DbgPrint
/* Base Addres of Kernel in Physical Memory */
#define KERNEL_BASE_PHYS 0x200000
/* Bits to shift to convert a Virtual Address into an Offset in the Page Table */
#define PFN_SHIFT 12
/* Bits to shift to convert a Virtual Address into an Offset in the Page Directory */
#define PDE_SHIFT 22
#define PDE_SHIFT_PAE 18
/* Converts a Relative Address read from the Kernel into a Physical Address */
#define RaToPa(p) \
(ULONG_PTR)((ULONG_PTR)p + KERNEL_BASE_PHYS)
/* Converts a Physical Address Pointer into a Page Frame Number */
#define PaPtrToPfn(p) \
(((ULONG_PTR)&p) >> PFN_SHIFT)
/* Converts a Physical Address into a Page Frame Number */
#define PaToPfn(p) \
((p) >> PFN_SHIFT)
#define STARTUP_BASE 0xC0000000
#define HYPERSPACE_BASE 0xC0400000
#define HYPERSPACE_PAE_BASE 0xC0800000
#define APIC_BASE 0xFEC00000
#define KPCR_BASE 0xFF000000
#define LowMemPageTableIndex 0
#define StartupPageTableIndex (STARTUP_BASE >> 22)
#define HyperspacePageTableIndex (HYPERSPACE_BASE >> 22)
#define KpcrPageTableIndex (KPCR_BASE >> 22)
#define ApicPageTableIndex (APIC_BASE >> 22)
#define LowMemPageTableIndexPae 0
#define StartupPageTableIndexPae (STARTUP_BASE >> 21)
#define HyperspacePageTableIndexPae (HYPERSPACE_PAE_BASE >> 21)
#define KpcrPageTableIndexPae (KPCR_BASE >> 21)
#define ApicPageTableIndexPae (APIC_BASE >> 21)
#define KernelEntryPoint (KernelEntry - KERNEL_BASE_PHYS) + KernelBase
/* Load Address of Next Module */
ULONG_PTR NextModuleBase = 0;
/* Currently Opened Module */
PLOADER_MODULE CurrentModule = NULL;
/* Unrelocated Kernel Base in Virtual Memory */
ULONG_PTR KernelBase;
/* Whether PAE is to be used or not */
BOOLEAN PaeModeEnabled;
/* Kernel Entrypoint in Physical Memory */
ULONG_PTR KernelEntry;
typedef struct _HARDWARE_PTE_X64 {
ULONG Valid : 1;
ULONG Write : 1;
ULONG Owner : 1;
ULONG WriteThrough : 1;
ULONG CacheDisable : 1;
ULONG Accessed : 1;
ULONG Dirty : 1;
ULONG LargePage : 1;
ULONG Global : 1;
ULONG CopyOnWrite : 1;
ULONG Prototype : 1;
ULONG reserved : 1;
ULONG PageFrameNumber : 20;
ULONG reserved2 : 31;
ULONG NoExecute : 1;
} HARDWARE_PTE_X64, *PHARDWARE_PTE_X64;
typedef struct _PAGE_DIRECTORY_X86 {
HARDWARE_PTE Pde[1024];
} PAGE_DIRECTORY_X86, *PPAGE_DIRECTORY_X86;
typedef struct _PAGE_DIRECTORY_X64 {
HARDWARE_PTE_X64 Pde[2048];
} PAGE_DIRECTORY_X64, *PPAGE_DIRECTORY_X64;
typedef struct _PAGE_DIRECTORY_TABLE_X64 {
HARDWARE_PTE_X64 Pde[4];
} PAGE_DIRECTORY_TABLE_X64, *PPAGE_DIRECTORY_TABLE_X64;
/* Page Directory and Tables for non-PAE Systems */
extern PAGE_DIRECTORY_X86 startup_pagedirectory;
extern PAGE_DIRECTORY_X86 lowmem_pagetable;
extern PAGE_DIRECTORY_X86 kernel_pagetable;
extern ULONG_PTR hyperspace_pagetable;
extern ULONG_PTR _pae_pagedirtable;
extern PAGE_DIRECTORY_X86 apic_pagetable;
extern PAGE_DIRECTORY_X86 kpcr_pagetable;
/* Page Directory and Tables for PAE Systems */
extern PAGE_DIRECTORY_TABLE_X64 startup_pagedirectorytable_pae;
extern PAGE_DIRECTORY_X64 startup_pagedirectory_pae;
extern PAGE_DIRECTORY_X64 lowmem_pagetable_pae;
extern PAGE_DIRECTORY_X64 kernel_pagetable_pae;
extern ULONG_PTR hyperspace_pagetable_pae;
extern ULONG_PTR pagedirtable_pae;
extern PAGE_DIRECTORY_X64 apic_pagetable_pae;
extern PAGE_DIRECTORY_X64 kpcr_pagetable_pae;
BOOLEAN
NTAPI
FrLdrLoadImage(IN PCHAR szFileName,
IN INT nPos);
/* FUNCTIONS *****************************************************************/
/*++
* FrLdrStartup
* INTERNAL
*
* Prepares the system for loading the Kernel.
*
* Params:
* Magic - Multiboot Magic
*
* Returns:
* None.
*
* Remarks:
* None.
*
*--*/
VOID
NTAPI
FrLdrStartup(ULONG Magic)
{
/* Disable Interrupts */
_disable();
/* Re-initalize EFLAGS */
Ke386EraseFlags();
/* Get the PAE Mode */
FrLdrGetPaeMode();
/* Initialize the page directory */
FrLdrSetupPageDirectory();
/* Initialize Paging, Write-Protection and Load NTOSKRNL */
FrLdrSetupPae(Magic);
}
/*++
* FrLdrSetupPae
* INTERNAL
*
* Configures PAE on a MP System, and sets the PDBR if it's supported, or if
* the system is UP.
*
* Params:
* Magic - Multiboot Magic
*
* Returns:
* None.
*
* Remarks:
* None.
*
*--*/
VOID
FASTCALL
FrLdrSetupPae(ULONG Magic)
{
ULONG_PTR PageDirectoryBaseAddress = (ULONG_PTR)&startup_pagedirectory;
ASMCODE PagedJump;
if (PaeModeEnabled)
{
PageDirectoryBaseAddress = (ULONG_PTR)&startup_pagedirectorytable_pae;
/* Enable PAE */
__writecr4(__readcr4() | X86_CR4_PAE);
}
/* Set the PDBR */
__writecr3(PageDirectoryBaseAddress);
/* Enable Paging and Write Protect*/
__writecr0(__readcr0() | X86_CR0_PG | X86_CR0_WP);
/* Jump to Kernel */
PagedJump = (ASMCODE)(PVOID)(KernelEntryPoint);
PagedJump(Magic, &LoaderBlock);
}
/*++
* FrLdrGetKernelBase
* INTERNAL
*
* Gets the Kernel Base to use.
*
* Params:
*
* Returns:
* None.
*
* Remarks:
* Sets both the FreeLdr internal variable as well as the one which
* will be used by the Kernel.
*
*--*/
static VOID
FASTCALL
FrLdrGetKernelBase(VOID)
{
PCHAR p;
/* Set KernelBase */
LoaderBlock.KernelBase = KernelBase;
/* Read Command Line */
p = (PCHAR)LoaderBlock.CommandLine;
while ((p = strchr(p, '/')) != NULL) {
/* Find "/3GB" */
if (!_strnicmp(p + 1, "3GB", 3)) {
/* Make sure there's nothing following it */
if (p[4] == ' ' || p[4] == 0) {
/* Use 3GB */
KernelBase = 0xE0000000;
LoaderBlock.KernelBase = 0xC0000000;
}
}
p++;
}
}
/*++
* FrLdrGetPaeMode
* INTERNAL
*
* Determines whether PAE mode should be enabled or not.
*
* Params:
* None.
*
* Returns:
* None.
*
* Remarks:
* None.
*
*--*/
VOID
FASTCALL
FrLdrGetPaeMode(VOID)
{
BOOLEAN PaeModeSupported;
PaeModeSupported = FALSE;
PaeModeEnabled = FALSE;
if (CpuidSupported() & 1)
{
ULONG eax, ebx, ecx, FeatureBits;
GetCpuid(1, &eax, &ebx, &ecx, &FeatureBits);
if (FeatureBits & X86_FEATURE_PAE)
{
PaeModeSupported = TRUE;
}
}
if (PaeModeSupported)
{
PCHAR p;
/* Read Command Line */
p = (PCHAR)LoaderBlock.CommandLine;
while ((p = strchr(p, '/')) != NULL) {
p++;
/* Find "PAE" */
if (!_strnicmp(p, "PAE", 3)) {
/* Make sure there's nothing following it */
if (p[3] == ' ' || p[3] == 0) {
/* Use Pae */
PaeModeEnabled = TRUE;
break;
}
}
}
}
}
/*++
* FrLdrSetupPageDirectory
* INTERNAL
*
* Sets up the ReactOS Startup Page Directory.
*
* Params:
* None.
*
* Returns:
* None.
*
* Remarks:
* We are setting PDEs, but using the equvivalent (for our purpose) PTE structure.
* As such, please note that PageFrameNumber == PageEntryNumber.
*
*--*/
VOID
FASTCALL
FrLdrSetupPageDirectory(VOID)
{
PPAGE_DIRECTORY_X86 PageDir;
PPAGE_DIRECTORY_TABLE_X64 PageDirTablePae;
PPAGE_DIRECTORY_X64 PageDirPae;
ULONG KernelPageTableIndex;
ULONG i;
if (PaeModeEnabled) {
/* Get the Kernel Table Index */
KernelPageTableIndex = (KernelBase >> 21);
/* Get the Startup Page Directory Table */
PageDirTablePae = (PPAGE_DIRECTORY_TABLE_X64)&startup_pagedirectorytable_pae;
/* Get the Startup Page Directory */
PageDirPae = (PPAGE_DIRECTORY_X64)&startup_pagedirectory_pae;
/* Set the Startup page directory table */
for (i = 0; i < 4; i++)
{
PageDirTablePae->Pde[i].Valid = 1;
PageDirTablePae->Pde[i].PageFrameNumber = PaPtrToPfn(startup_pagedirectory_pae) + i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -