KernelMain reports more details about memory usage, LdrResolveImports catches kernel32, user32, ole32 and winmm and redirects them to win32.
This commit is contained in:
1 parent
129be91e15
commit
c13dd99150
7 files changed
+116
-1190
No files matched your search
-1182
File diff suppressed because it is too large.
Load diff
Binary file not shown.
+13
-7
@@ -78,9 +78,8 @@ typedef KSTATUS (*DRIVER_ENTRY_FN)(const HAL_API *);
|
|||||||
// Phase Helper: Resolve Imports for all registered modules
|
// Phase Helper: Resolve Imports for all registered modules
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
static void ResolveSystemImports(BOOT_INFO* bootInfo) {
|
static void ResolveSystemImports(BOOT_INFO* bootInfo) {
|
||||||
// Resolve imports for all loaded modules (drivers may import from hal.dll,
|
// Resolve imports for all loaded modules (drivers may import from hal.dll, win32.dll imports from syscall.dll, etc).
|
||||||
// win32.dll imports from syscall.dll, etc).
|
// Starting at 2 to skip the kernel and HAL base images.
|
||||||
// Starting at 2 to skip the kernel and HAL base images, as per your design.
|
|
||||||
for (uint32_t i = 2; i < bootInfo->ModuleCount; i++) {
|
for (uint32_t i = 2; i < bootInfo->ModuleCount; i++) {
|
||||||
LdrResolveImports(bootInfo->Modules[i].VirtBase);
|
LdrResolveImports(bootInfo->Modules[i].VirtBase);
|
||||||
}
|
}
|
||||||
@@ -112,7 +111,7 @@ static void InitializeDrivers(BOOT_INFO* bootInfo, const HAL_API* hal) {
|
|||||||
|
|
||||||
// Identify .sys files by extension
|
// Identify .sys files by extension
|
||||||
size_t len = strlen(name);
|
size_t len = strlen(name);
|
||||||
if (len < 4 || strcmp(name + len - 4, ".sys") != 0) continue;
|
if (len < 4 || strcmp(name + len - 4, ".sys")) continue;
|
||||||
|
|
||||||
DbgPrint("KernelMain: Executing DriverEntry for %s\n", name);
|
DbgPrint("KernelMain: Executing DriverEntry for %s\n", name);
|
||||||
|
|
||||||
@@ -235,7 +234,7 @@ static void LoadAndRegisterDll(const char* filename) {
|
|||||||
IoCloseFile(f);
|
IoCloseFile(f);
|
||||||
|
|
||||||
// Map the DLL into memory
|
// Map the DLL into memory
|
||||||
// Passing 'true' for user-mode so init.exe can access its code
|
// Passing 'true' for user-mode
|
||||||
uintptr_t mappedBase = 0;
|
uintptr_t mappedBase = 0;
|
||||||
s = LdrLoadImage(mem, size, &mappedBase, true);
|
s = LdrLoadImage(mem, size, &mappedBase, true);
|
||||||
if (!KSUCCESS(s)) {
|
if (!KSUCCESS(s)) {
|
||||||
@@ -384,8 +383,6 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
|||||||
//
|
//
|
||||||
KeInitializeScheduler();
|
KeInitializeScheduler();
|
||||||
// hal->Screen.Clear(0x000000);
|
// hal->Screen.Clear(0x000000);
|
||||||
DbgPrint("KernelMain: initialisation complete. %.2f MB free.\n",
|
|
||||||
(float)MmFreeFrameCount() * PAGE_SIZE / (1024.0f * 1024.0f));
|
|
||||||
|
|
||||||
DbgPrint("KernelMain: Loading system DLLs...\n");
|
DbgPrint("KernelMain: Loading system DLLs...\n");
|
||||||
LoadAndRegisterDll("syscall.dll");
|
LoadAndRegisterDll("syscall.dll");
|
||||||
@@ -406,6 +403,15 @@ extern void KernelMain(BOOT_INFO* bootInfo) {
|
|||||||
DbgPrint("KernelMain: Starting scheduler... Handing over control.\n");
|
DbgPrint("KernelMain: Starting scheduler... Handing over control.\n");
|
||||||
_enable();
|
_enable();
|
||||||
|
|
||||||
|
float freeMB = (float)MmFreeFrameCount() * PAGE_SIZE / (1024.0f * 1024.0f);
|
||||||
|
float kernelMB = (float)MmGetKernelPoolUsage() / (1024.0f * 1024.0f);
|
||||||
|
float userMB = (float)MmGetUserHeapUsage() / (1024.0f * 1024.0f);
|
||||||
|
|
||||||
|
DbgPrint("Memory Status:\n");
|
||||||
|
DbgPrint(" -> Free (PMM): %.2f MB\n", freeMB);
|
||||||
|
DbgPrint(" -> Kernel Pool: %.2f MB\n", kernelMB);
|
||||||
|
DbgPrint(" -> User Heap: %.2f MB\n", userMB);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
//DbgPrint("KernelMain: Idle loop. Free memory: %.2f MB.\n",
|
//DbgPrint("KernelMain: Idle loop. Free memory: %.2f MB.\n",
|
||||||
//(float)(MmFreeFrameCount() * PAGE_SIZE) / (1024.0f * 1024.0f));
|
//(float)(MmFreeFrameCount() * PAGE_SIZE) / (1024.0f * 1024.0f));
|
||||||
|
|||||||
@@ -225,13 +225,16 @@ KSTATUS LdrResolveImports(uintptr_t imageBase) {
|
|||||||
PE_HEADER* pe = (PE_HEADER *)(imageBase + peOffset);
|
PE_HEADER* pe = (PE_HEADER *)(imageBase + peOffset);
|
||||||
OPT_HEADER64* opt = &pe->OptionalHeader;
|
OPT_HEADER64* opt = &pe->OptionalHeader;
|
||||||
|
|
||||||
if (opt->NumberOfRvaAndSizes < 2) return STATUS_SUCCESS; // no imports
|
if (opt->NumberOfRvaAndSizes < 2) return STATUS_SUCCESS; // no imports
|
||||||
uint32_t impRva = opt->DataDirectory[1].VirtualAddress;
|
uint32_t impRva = opt->DataDirectory[1].VirtualAddress;
|
||||||
if (!impRva) return STATUS_SUCCESS;
|
if (!impRva) return STATUS_SUCCESS;
|
||||||
|
|
||||||
IMPORT_DESC* imp = (IMPORT_DESC *)(imageBase + impRva);
|
IMPORT_DESC* imp = (IMPORT_DESC *)(imageBase + impRva);
|
||||||
while (imp->Name) {
|
while (imp->Name) {
|
||||||
const char* dllName = (const char *)(imageBase + imp->Name);
|
const char* dllName = (const char *)(imageBase + imp->Name);
|
||||||
|
if (!_stricmp(dllName, "kernel32.dll") || !_stricmp(dllName, "user32.dll")
|
||||||
|
|| !_stricmp(dllName, "ole32.dll") || !_stricmp(dllName, "winmm.dll"))
|
||||||
|
dllName = "win32.dll";
|
||||||
uint64_t* thunk = (uint64_t *)(imageBase + imp->FirstThunk);
|
uint64_t* thunk = (uint64_t *)(imageBase + imp->FirstThunk);
|
||||||
uint64_t* origThunk = (uint64_t *)(imageBase + (imp->OriginalFirstThunk
|
uint64_t* origThunk = (uint64_t *)(imageBase + (imp->OriginalFirstThunk
|
||||||
? imp->OriginalFirstThunk
|
? imp->OriginalFirstThunk
|
||||||
|
|||||||
@@ -443,3 +443,13 @@ void* MmReallocatePool(void* ptr, size_t newSize) { return HeapRealloc(&gPoolHea
|
|||||||
void* MmAllocateUserMemory(size_t size) { return HeapAlloc(&gUserHeap, size); }
|
void* MmAllocateUserMemory(size_t size) { return HeapAlloc(&gUserHeap, size); }
|
||||||
void MmFreeUserMemory(void* ptr, size_t size) { (void)size; HeapFree(&gUserHeap, ptr); }
|
void MmFreeUserMemory(void* ptr, size_t size) { (void)size; HeapFree(&gUserHeap, ptr); }
|
||||||
void* MmReallocateUserMemory(void* ptr, size_t newSize) { return HeapRealloc(&gUserHeap, ptr, newSize); }
|
void* MmReallocateUserMemory(void* ptr, size_t newSize) { return HeapRealloc(&gUserHeap, ptr, newSize); }
|
||||||
|
|
||||||
|
size_t MmGetKernelPoolUsage(void) {
|
||||||
|
// Returns bytes committed to the kernel pool
|
||||||
|
return (size_t)(gPoolHeap.Brk - gPoolHeap.Start);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MmGetUserHeapUsage(void) {
|
||||||
|
// Returns bytes committed to the user heap
|
||||||
|
return (size_t)(gUserHeap.Brk - gUserHeap.Start);
|
||||||
|
}
|
||||||
@@ -68,3 +68,6 @@ void* MmReallocatePool(void* ptr, size_t newSize);
|
|||||||
void* MmAllocateUserMemory(size_t size);
|
void* MmAllocateUserMemory(size_t size);
|
||||||
void MmFreeUserMemory(void* ptr, size_t size);
|
void MmFreeUserMemory(void* ptr, size_t size);
|
||||||
void* MmReallocateUserMemory(void* ptr, size_t newSize);
|
void* MmReallocateUserMemory(void* ptr, size_t newSize);
|
||||||
|
|
||||||
|
size_t MmGetKernelPoolUsage(void);
|
||||||
|
size_t MmGetUserHeapUsage(void);
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
# an x86-64 kernel
|
||||||
|
|
||||||
|
boots. runs processes. doesn't crash (usually).
|
||||||
|
|
||||||
|
## what is it?
|
||||||
|
|
||||||
|
a 64-bit operating system kernel written from scratch.
|
||||||
|
UEFI bootloader, physical and virtual memory managers, preemptive scheduler, HAL, VFS, PE loader, partial Win32 layer.
|
||||||
|
it boots into a shell.
|
||||||
|
~20k lines of code.
|
||||||
|
|
||||||
|
## features
|
||||||
|
|
||||||
|
- UEFI bootloader with PE loading and base relocation
|
||||||
|
- physical memory manager (frame stack, O(1) alloc/free)
|
||||||
|
- virtual memory manager with kernel pool
|
||||||
|
- HAL (screen, keyboard, timer, disk, PCI, APIC)
|
||||||
|
- preemptive scheduler with priority levels
|
||||||
|
- processes and threads
|
||||||
|
- VFS with FAT32 driver (read-only)
|
||||||
|
- drive-letter paths (`0:\apps\shell.exe`)
|
||||||
|
- INI-based boot and driver configuration
|
||||||
|
- partial Win32 layer (kernel32 and user32, far from finished)
|
||||||
|
- PE import resolution and dynamic driver loading
|
||||||
|
|
||||||
|
## how 2 build
|
||||||
|
|
||||||
|
* open vs x64 build tools
|
||||||
|
* cd into this directory
|
||||||
|
* `build.bat`
|
||||||
|
* open `run.bat`/`rund.bat`
|
||||||
|
* replace `\\.\PhysicalDrive7` with your thumbdrive partition
|
||||||
|
* `run.bat`/`rund.bat`
|
||||||
|
* enjoy
|
||||||
|
|
||||||
|
## driver model
|
||||||
|
|
||||||
|
drivers are PE32+ `.sys` files with an entry point preferably named DriverEntry accepting a constant pointer to HAL_API.
|
||||||
|
|
||||||
|
drivers to be loaded have their path stored in `drivers.ini`, split into essential for boot (loaded by bootloader) and not required for boot (loaded by kernel).
|
||||||
|
|
||||||
|
a disk driver fills in a `DISK_DRIVER` vtable and calls `IoRegisterDisk(index, &driver)`.
|
||||||
|
a filesystem driver fills in an `IO_FILESYSTEM` vtable and calls `IoRegisterFilesystem(index, &fs, &vol)`.
|
||||||
|
|
||||||
|
## how it boots
|
||||||
|
|
||||||
|
1. UEFI loads `boot.ini`, reads `drivers.ini`
|
||||||
|
2. bootloader maps kernel, HAL, and boot drivers into the upper half
|
||||||
|
3. direct physical window at `0xFFFF880000000000`
|
||||||
|
4. jumps to `KernelMain`
|
||||||
|
5. PMM, VMM, GDT, IDT, HAL, IRQs, scheduler
|
||||||
|
6. loads runtime drivers from disk
|
||||||
|
7. launches `shell.exe`
|
||||||
|
|
||||||
|
## paths
|
||||||
|
|
||||||
|
```
|
||||||
|
"apps\shell.exe" -> drive 0
|
||||||
|
"0:\apps\shell.exe" -> drive 0
|
||||||
|
"2:\data\config.ini" -> drive 2
|
||||||
|
```
|
||||||
|
|
||||||
|
drives 0–7. a drive only works if a filesystem registered on it.
|
||||||
|
|
||||||
|
## faq
|
||||||
|
|
||||||
|
Q: Why?
|
||||||
|
A: Why not.
|
||||||
|
|
||||||
|
Q: Does it run Doom?
|
||||||
|
A: Not yet.
|
||||||
|
|
||||||
|
Q: Is the Win32 layer real?
|
||||||
|
A: Real enough to load binaries that expect it. Not real enough to run Notepad.
|
||||||
|
|
||||||
|
Q: Is the scheduler preemptive?
|
||||||
|
A: Yes.
|
||||||
|
|
||||||
|
Q: Will it corrupt my data?
|
||||||
|
A: How would it? It's read-only.
|
||||||
|
|
||||||
|
Q: Is this finished?
|
||||||
|
A: Not in the slightest.
|
||||||
|
|
||||||
|
Q: Can I use this in production?
|
||||||
|
A: Don't.
|
||||||
Reference in new issue
Block a user