Rewrote loader to support more complex sections.
This fixes relying on UB to expect elf sections to be page-aligned in file.master
parent
7381cb0a5a
commit
5a94b26f14
|
@ -18,8 +18,9 @@ LD:=ld
|
|||
|
||||
# -O2 sets -foptimize-sibling-calls which breaks code...
|
||||
CFLAGS:=-Wall -Werror -nostdlib -std=c99 -g -ffreestanding
|
||||
CFLAGS+=-I ./include -O2 -fno-optimize-sibling-calls
|
||||
CFLAGS+= -fno-builtin -nostdinc -target i586-elf
|
||||
CFLAGS+=-I ./include -O1 -fno-optimize-sibling-calls
|
||||
CFLAGS+= -fno-builtin -nostdinc -target i586-elf -nostdlib
|
||||
|
||||
LFLAGS:=-nostdlib -nostartfiles -nodefaultlibs -m elf_i386
|
||||
|
||||
.PHONY: all clean loader.bin emulate hdd.img
|
||||
|
|
|
@ -26,6 +26,9 @@ struct elf_header {
|
|||
u16 SectionEntryStrings;
|
||||
};
|
||||
|
||||
#define SHT_PROGBITS 1
|
||||
#define SHT_NOBITS 8
|
||||
|
||||
struct elf_section_header {
|
||||
u32 Name;
|
||||
u32 Type;
|
||||
|
|
|
@ -82,6 +82,32 @@ void move_cursor(u8 X, u8 Y)
|
|||
outb(0x3D5, (u8)(Position >> 8 & 0xFF));
|
||||
}
|
||||
|
||||
|
||||
void puti(s32 Number)
|
||||
{
|
||||
s32 Sign, i;
|
||||
|
||||
if ((Sign = Number) < 0)
|
||||
Number = -Number;
|
||||
|
||||
u8 szString[21];
|
||||
|
||||
i = 0;
|
||||
do {
|
||||
szString[i++] = Number % 10 + '0';
|
||||
} while (( Number /= 10) > 0);
|
||||
|
||||
if (Sign < 0)
|
||||
szString[i] = '-';
|
||||
else
|
||||
i--;
|
||||
|
||||
for (s32 j = i; j >= 0; j--)
|
||||
{
|
||||
putch(szString[j]);
|
||||
}
|
||||
}
|
||||
|
||||
void putch(s8 Character)
|
||||
{
|
||||
volatile u8 *VideoMemory = (u8 *)0xB8000;
|
||||
|
@ -149,9 +175,72 @@ void print_hex(u64 Number)
|
|||
}
|
||||
}
|
||||
|
||||
void update_load_context(T_LOAD_CONTEXT* Context)
|
||||
void io_update_load_context(T_LOAD_CONTEXT* Context)
|
||||
{
|
||||
Context->VGACurrentLine = stdio_current_line;
|
||||
Context->VGACursorX = stdio_cur_x;
|
||||
Context->VGACursorY = stdio_cur_y;
|
||||
}
|
||||
|
||||
u32 strlen(const s8 *szString)
|
||||
{
|
||||
const s8 *s;
|
||||
for (s = szString; *s; ++s)
|
||||
{}
|
||||
return s - szString;
|
||||
}
|
||||
|
||||
#define va_start(v,l) __builtin_va_start(v,l)
|
||||
#define va_arg(v,l) __builtin_va_arg(v,l)
|
||||
#define va_end(v) __builtin_va_end(v)
|
||||
#define va_copy(d,s) __builtin_va_copy(d,s)
|
||||
typedef __builtin_va_list va_list;
|
||||
|
||||
void printf(const s8 *szFormat, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, szFormat);
|
||||
|
||||
u32 Offset = 0;
|
||||
while (Offset < strlen(szFormat))
|
||||
{
|
||||
if (szFormat[Offset] == '%')
|
||||
{
|
||||
switch (szFormat[Offset + 1])
|
||||
{
|
||||
case '%':
|
||||
putch('%');
|
||||
break;
|
||||
case 'c':
|
||||
putch(va_arg(ap, u32));
|
||||
break;
|
||||
case 's':
|
||||
puts(va_arg(ap, s8*));
|
||||
break;
|
||||
case 'i':
|
||||
puti(va_arg(ap, s64));
|
||||
break;
|
||||
case 'u':
|
||||
puti(va_arg(ap, u64));
|
||||
break;
|
||||
case 'X':
|
||||
case 'x':
|
||||
{
|
||||
u64 bData = va_arg(ap, u64);
|
||||
print_hex(bData);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("printf: Unknown escape character %c!\n", szFormat[Offset + 1]);
|
||||
}
|
||||
Offset += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
putch(szFormat[Offset]);
|
||||
Offset++;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
}
|
|
@ -16,6 +16,7 @@ void clear(void);
|
|||
void dump_nibble(u8 Nibble);
|
||||
void print_hex_32(u32 Number);
|
||||
void print_hex(u64 Number);
|
||||
void update_load_context(T_LOAD_CONTEXT *Context);
|
||||
void io_update_load_context(T_LOAD_CONTEXT *Context);
|
||||
void printf(const s8 *szFormat, ...);
|
||||
|
||||
#endif
|
|
@ -2,6 +2,8 @@
|
|||
#include "io.h"
|
||||
#include "context.h"
|
||||
#include "elf.h"
|
||||
#include "paging.h"
|
||||
#include "multiboot.h"
|
||||
|
||||
extern u64 omg64;
|
||||
extern u64 _end;
|
||||
|
@ -12,111 +14,7 @@ static inline void cpuid(u32 code, u32 *a, u32 *d) {
|
|||
__asm__ volatile("cpuid":"=a"(*a),"=d"(*d):"0"(code):"ecx","ebx");
|
||||
}
|
||||
|
||||
|
||||
// A simple PAE paging structure so we can jump into 64-bit.
|
||||
// This will be replaced later on by the kernel code.
|
||||
|
||||
u64 pml4[512] __attribute__((aligned(0x1000)));
|
||||
|
||||
u64 page_dir_ptr_tab_low[512] __attribute__((aligned(0x1000)));
|
||||
u64 page_dir_low[512] __attribute__((aligned(0x1000)));
|
||||
u64 page_tab_low[512] __attribute__((aligned(0x1000)));
|
||||
|
||||
u64 page_dir_ptr_tab_high[512] __attribute__((aligned(0x1000)));
|
||||
u64 page_dir_high[512] __attribute__((aligned(0x1000)));
|
||||
u64 page_tab_high[512] __attribute__((aligned(0x1000)));
|
||||
|
||||
#define GET_PML4_ENTRY(x) (((u64)x >> 39) & 0x1FF)
|
||||
#define GET_PDP_ENTRY(x) (((u64)x >> 30) & 0x1FF)
|
||||
#define GET_DIR_ENTRY(x) (((u64)x >> 21) & 0x1FF)
|
||||
#define GET_TAB_ENTRY(x) (((u64)x >> 12) & 0x1FF)
|
||||
#define GET_OFFSET(x) (x & 0xFFF)
|
||||
|
||||
u32 create_ia32e_paging(u64 KernelPhysicalStart, u64 KernelVirtualStart, u64 KernelSize)
|
||||
{
|
||||
puts("Clearing paging structures...\n");
|
||||
|
||||
for (u16 i = 0; i < 512; i++)
|
||||
{
|
||||
pml4[i] = 0;
|
||||
page_dir_ptr_tab_low[i] = 0;
|
||||
page_dir_low[i] = 0;
|
||||
page_tab_low[i] = 0;
|
||||
page_dir_ptr_tab_high[i] = 0;
|
||||
page_dir_high[i] = 0;
|
||||
page_tab_high[i] = 0;
|
||||
}
|
||||
|
||||
puts("Setting up identity paging for first 2MiB...\n");
|
||||
pml4[GET_PML4_ENTRY(0)] = (u32)page_dir_ptr_tab_low | 3;
|
||||
page_dir_ptr_tab_low[GET_PDP_ENTRY(0)] = (u32)page_dir_low | 3;
|
||||
page_dir_low[GET_DIR_ENTRY(0)] = (u32)page_tab_low | 3;
|
||||
|
||||
u64 Address = 0;
|
||||
for (u16 i = 0; i < 512; i++)
|
||||
{
|
||||
page_tab_low[i] = Address | 3;
|
||||
Address += 0x1000;
|
||||
}
|
||||
|
||||
puts("Setting up paging for the kernel...\n");
|
||||
u16 NumPages = KernelSize / 0x1000;
|
||||
puts(" (0x");
|
||||
print_hex(NumPages);
|
||||
puts(" pages)\n");
|
||||
|
||||
if (NumPages > 512)
|
||||
{
|
||||
puts("Error: Kernel size > 2MiB not implemented!");
|
||||
return 1;
|
||||
}
|
||||
puts("Kernel PML4: "); print_hex(GET_PML4_ENTRY(KernelVirtualStart)); puts("\n");
|
||||
puts("Kernel PDP: "); print_hex(GET_PDP_ENTRY(KernelVirtualStart)); puts("\n");
|
||||
puts("Kernel DIR: "); print_hex(GET_DIR_ENTRY(KernelVirtualStart)); puts("\n");
|
||||
|
||||
if (GET_PML4_ENTRY(KernelVirtualStart) != 0)
|
||||
{
|
||||
// We're NOT mapping the same PML4 entry as for identity mapping...
|
||||
puts("Different PML4...\n");
|
||||
pml4[GET_PML4_ENTRY(KernelVirtualStart)] = (u32)page_dir_ptr_tab_high | 3;
|
||||
puts("Setting pml4["); print_hex_32(GET_PML4_ENTRY(KernelVirtualStart)); puts("] to "); print_hex_32((u32)page_dir_ptr_tab_high | 3); puts(".\n");
|
||||
page_dir_ptr_tab_high[GET_PDP_ENTRY(KernelVirtualStart)] = (u32)page_dir_high | 3;
|
||||
puts("Setting pdp["); print_hex_32(GET_PDP_ENTRY(KernelVirtualStart)); puts("] to "); print_hex_32((u32)page_dir_high | 3); puts(".\n");
|
||||
page_dir_high[GET_DIR_ENTRY(KernelVirtualStart)] = (u32)page_tab_high | 3;
|
||||
puts("Setting dir["); print_hex_32(GET_DIR_ENTRY(KernelVirtualStart)); puts("] to "); print_hex_32((u32)page_tab_high | 3); puts(".\n");
|
||||
}
|
||||
else if (GET_PDP_ENTRY(KernelVirtualStart) != 0)
|
||||
{
|
||||
// We're NOT mapping the same page directory pointer table entry as for identity paging...
|
||||
puts("Different PDPT... (");
|
||||
print_hex(GET_PDP_ENTRY(KernelVirtualStart));
|
||||
puts(")\n");
|
||||
page_dir_ptr_tab_low[GET_PDP_ENTRY(KernelVirtualStart)] = (u32)page_dir_high | 3;
|
||||
page_dir_high[GET_DIR_ENTRY(KernelVirtualStart)] = (u32)page_tab_high | 3;
|
||||
}
|
||||
else if (GET_DIR_ENTRY(KernelVirtualStart) != 0)
|
||||
{
|
||||
// We're NOT mapping the same page directory entry as for identity paging...
|
||||
puts("Different DIR...\n");
|
||||
page_dir_low[GET_DIR_ENTRY(KernelVirtualStart)] = (u32)page_tab_high | 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
puts("Error: kernel overlaps 2MiB identity paging!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
Address = KernelPhysicalStart;
|
||||
for (u16 i = GET_TAB_ENTRY(KernelVirtualStart); i < GET_TAB_ENTRY(KernelVirtualStart) + 512; i++)
|
||||
{
|
||||
page_tab_high[i] = Address | 3;
|
||||
|
||||
Address += 0x1000;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 g_multiboot_header;
|
||||
TMULTIBOOT_INFO *g_Multiboot;
|
||||
T_LOAD_CONTEXT g_Context;
|
||||
extern u64 GDT;
|
||||
extern u32 ldrEntryLow;
|
||||
|
@ -126,18 +24,8 @@ u32 load(void *Multiboot, unsigned int Magic)
|
|||
{
|
||||
clear();
|
||||
puts("Cucumber x86-64 loader...\n");
|
||||
|
||||
puts("GDT: \n");
|
||||
for (u32 i = 0; i < 5; i++)
|
||||
{
|
||||
puts(" ");
|
||||
print_hex(*(&GDT + i));
|
||||
puts("\n");
|
||||
}
|
||||
|
||||
g_multiboot_header = (u32)Multiboot;
|
||||
|
||||
|
||||
g_Multiboot = Multiboot;
|
||||
if (Magic != 0x2BADB002)
|
||||
{
|
||||
puts("Error: not booted via Multiboot!\n");
|
||||
|
@ -146,46 +34,40 @@ u32 load(void *Multiboot, unsigned int Magic)
|
|||
|
||||
u32 CPUID_A, CPUID_D;
|
||||
cpuid(0x80000001, &CPUID_A, &CPUID_D);
|
||||
|
||||
u8 SupportFor64 = (CPUID_D & (1 << 29)) > 0;
|
||||
|
||||
if (!SupportFor64)
|
||||
{
|
||||
puts("Error: You CPU does not support long mode!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 Flags = *((u32*)Multiboot);
|
||||
|
||||
u8 ModulesPresent = (Flags & (1 << 3)) > 0;
|
||||
|
||||
if (!ModulesPresent)
|
||||
if (!(g_Multiboot->Flags & MULTIBOOT_INFO_MODS))
|
||||
{
|
||||
puts("Error: no 64-bit kernel loaded!\n");
|
||||
puts(" (did you forget the module line in GRUB?)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 ModulesCount = *((u32*)Multiboot + 5);
|
||||
u32 ModulesAddress = *((u32*)Multiboot + 6);
|
||||
|
||||
if (ModulesCount == 0)
|
||||
if (!g_Multiboot->ModulesCount)
|
||||
{
|
||||
puts("Error: No kernel specified! Can't boot non-existant code, sorry!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ModulesCount != 1)
|
||||
if (g_Multiboot->ModulesCount != 1)
|
||||
{
|
||||
puts("Error: just one module is enough. Don't load a ton of them.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
puts("Kernel is @");
|
||||
print_hex(ModulesAddress);
|
||||
u32 KernelStart = g_Multiboot->Modules[0].ModuleStart;
|
||||
u32 KernelEnd = g_Multiboot->Modules[0].ModuleEnd;
|
||||
puts("Kernel is ");
|
||||
print_hex(KernelStart);
|
||||
puts("-");
|
||||
print_hex(KernelEnd);
|
||||
puts(".\n");
|
||||
|
||||
struct elf_header *Header = *((struct elf_header **)ModulesAddress);
|
||||
struct elf_header *Header = (struct elf_header *)KernelStart;
|
||||
if (Header->Identification.Magic != 0x464C457F)
|
||||
{
|
||||
puts("Error: Module is not an ELF file!\n");
|
||||
|
@ -219,62 +101,86 @@ u32 load(void *Multiboot, unsigned int Magic)
|
|||
|
||||
//u32 *Strings = (u32*)(ModulesAddress + (u32)StringSection->Offset);
|
||||
|
||||
puts("0x");
|
||||
puts("Kernel ELF has 0x");
|
||||
print_hex(Header->NumSectionHeaderEntries);
|
||||
puts(" ELF sections.\n");
|
||||
puts(" sections.\n");
|
||||
|
||||
u64 ContinuityTest = 0;
|
||||
// Loop through ELF sections to find physical space occupied by them
|
||||
u64 StartPhysical = 0;
|
||||
u64 StartVirtual = 0;
|
||||
u64 Size = 0;
|
||||
u64 EndPhysical = 0;
|
||||
|
||||
for (u16 i = 0; i < Header->NumSectionHeaderEntries; i++)
|
||||
{
|
||||
s8* Name = (s8*)((u32)Header + (u32)StringSection->Offset + (u32)Sections[i].Name);
|
||||
u64 PhysicalAddress = (u32)Header + Sections[i].Offset;
|
||||
u64 VirtualAddress = Sections[i].Address;
|
||||
|
||||
if (VirtualAddress)
|
||||
{
|
||||
if (!StartVirtual)
|
||||
StartVirtual = VirtualAddress;
|
||||
|
||||
if (!StartPhysical)
|
||||
StartPhysical = PhysicalAddress;
|
||||
|
||||
puts("-> Section ");
|
||||
puts(Name);
|
||||
puts(", 0x");
|
||||
print_hex(PhysicalAddress);
|
||||
puts(" will be located at 0x");
|
||||
print_hex(VirtualAddress);
|
||||
puts(".\n");
|
||||
|
||||
if (ContinuityTest && VirtualAddress != ContinuityTest)
|
||||
{
|
||||
puts("Error: kernel is not continuous!\n");
|
||||
puts("Previous section ended at 0x"); print_hex(ContinuityTest); puts("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ContinuityTest = VirtualAddress + Sections[i].Size;
|
||||
Size += Sections[i].Size;
|
||||
u64 EndAddress = StartPhysical + Sections[i].Size;
|
||||
if (EndAddress > EndPhysical)
|
||||
EndPhysical = EndAddress;
|
||||
}
|
||||
}
|
||||
|
||||
puts("\nPaging setup:\n 0x");
|
||||
print_hex(StartVirtual);
|
||||
puts(" => 0x");
|
||||
print_hex(StartPhysical);
|
||||
puts("\n (0x");
|
||||
print_hex(Size);
|
||||
puts(" bytes)\n");
|
||||
u32 FreeSpaceStart = (u32)&_end;
|
||||
if (EndPhysical > FreeSpaceStart)
|
||||
FreeSpaceStart = EndPhysical;
|
||||
if (KernelEnd > FreeSpaceStart)
|
||||
FreeSpaceStart = KernelEnd;
|
||||
if (FreeSpaceStart % 0x1000)
|
||||
FreeSpaceStart = (FreeSpaceStart + 0x1000) & 0xFFFFF000;
|
||||
|
||||
g_Context.KernelPhysicalStart = FreeSpaceStart;
|
||||
|
||||
g_Context.KernelPhysicalStart = StartPhysical;
|
||||
g_Context.KernelPhysicalEnd = StartPhysical + Size;
|
||||
u32 KernelApproximateSize = FreeSpaceStart - StartPhysical;
|
||||
if (FreeSpaceStart + KernelApproximateSize > 0x00EFFFFF)
|
||||
{
|
||||
puts("Kernel will probably not fit in extended memory. Failing.\n");
|
||||
for(;;) {}
|
||||
}
|
||||
puts("Paging frames will be allocated from 0x"); print_hex(FreeSpaceStart); puts("\n");
|
||||
paging_setup(FreeSpaceStart);
|
||||
// allocate idnetity mapping of low & extended memory (up to 0x00EFFFFF)
|
||||
paging_map_address(0, 0, 0x00EFFFFF);
|
||||
// map the kernel sections
|
||||
for (u16 i = 0; i < Header->NumSectionHeaderEntries; i++)
|
||||
{
|
||||
u64 PhysicalAddress = (u32)Header + Sections[i].Offset;
|
||||
u64 VirtualAddress = Sections[i].Address;
|
||||
u64 Size = Sections[i].Size;
|
||||
s8* Name = (s8*)((u32)Header + (u32)StringSection->Offset + (u32)Sections[i].Name);
|
||||
|
||||
if (VirtualAddress)
|
||||
{
|
||||
// allocate space for that section...
|
||||
u64 SizeAligned = Size;
|
||||
if (SizeAligned % 0x1000)
|
||||
SizeAligned = (SizeAligned + 0x1000) & 0xFFFFF000;
|
||||
u8 *Destination = paging_allocate(VirtualAddress, SizeAligned);
|
||||
|
||||
puts(" -> "); puts(Name); puts(" at "); print_hex(VirtualAddress);
|
||||
if (!(Sections[i].Type & SHT_NOBITS))
|
||||
{
|
||||
// not .bss - copy data
|
||||
puts(" (copy from "); print_hex(PhysicalAddress); puts(")\n");
|
||||
u8 *Source = (u8 *)((u32)PhysicalAddress);
|
||||
for (u32 j = 0; j < Size; j++)
|
||||
Destination[j] = Source[j];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 j = 0; j < Size; j++)
|
||||
Destination[j] = 0;
|
||||
puts(" (zeroed out)\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
g_Context.KernelPhysicalEnd = paging_get_last_frame();
|
||||
|
||||
s8 *LoaderName = "Cucumber x86-64 loader";
|
||||
|
||||
u8 i = 0;
|
||||
while (*LoaderName)
|
||||
{
|
||||
|
@ -292,15 +198,10 @@ u32 load(void *Multiboot, unsigned int Magic)
|
|||
print_hex((u32)&g_Context);
|
||||
puts(".\n");
|
||||
|
||||
if (create_ia32e_paging(StartPhysical, StartVirtual, Size))
|
||||
{
|
||||
puts("Could not create paging structure, for some reason... Failing.\n");
|
||||
for (;;) {}
|
||||
}
|
||||
__asm__ volatile ("movl %cr4, %eax; bts $5, %eax; movl %eax, %cr4");
|
||||
__asm__ volatile ("movl %%eax, %%cr3" :: "a" (pml4));
|
||||
__asm__ volatile ("movl %%eax, %%cr3" :: "a" (paging_get_pml4()));
|
||||
puts("CR3 is now pointing to PML4 (0x");
|
||||
print_hex((u32)pml4);
|
||||
print_hex((u32)paging_get_pml4());
|
||||
puts(")\n");
|
||||
|
||||
puts("Here it goes, enabling long mode...\n");
|
||||
|
@ -314,8 +215,8 @@ u32 load(void *Multiboot, unsigned int Magic)
|
|||
"movl %%ebx, %%cr0;":::"eax","ebx","ecx");
|
||||
|
||||
puts("Now in 32-bit compability mode, jumping to the kernel...\n");
|
||||
update_load_context(&g_Context);
|
||||
|
||||
io_update_load_context(&g_Context);
|
||||
// for (;;) {}
|
||||
ldrEntryLow = Header->Entry & 0xFFFFFFFF;
|
||||
ldrEntryHigh = Header->Entry >> 32;
|
||||
return 1;
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef __MULTIBOOT_H__
|
||||
#define __MULTIBOOT_H__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 ModuleStart;
|
||||
u32 ModuleEnd;
|
||||
s8 *String;
|
||||
u32 Reserved;
|
||||
} __attribute__((packed)) TMULTIBOOT_MODULE;
|
||||
|
||||
typedef struct {
|
||||
u32 Flags;
|
||||
u32 MemLower;
|
||||
u32 MemUpper;
|
||||
u32 BootDevice;
|
||||
u32 CommandLines;
|
||||
u32 ModulesCount;
|
||||
TMULTIBOOT_MODULE *Modules;
|
||||
} __attribute__((packed)) TMULTIBOOT_INFO;
|
||||
|
||||
#define MULTIBOOT_INFO_MEMORY 0x00000001
|
||||
#define MULTIBOOT_INFO_BOOTDEV 0x00000002
|
||||
#define MULTIBOOT_INFO_CMDLINE 0x00000004
|
||||
#define MULTIBOOT_INFO_MODS 0x00000008
|
||||
#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010
|
||||
#define MULTIBOOT_INFO_ELF_SHDR 0X00000020
|
||||
#define MULTIBOOT_INFO_MEM_MAP 0x00000040
|
||||
#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080
|
||||
#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100
|
||||
#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200
|
||||
#define MULTIBOOT_INFO_APM_TABLE 0x00000400
|
||||
#define MULTIBOOT_INFO_VIDEO_INFO 0x00000800
|
||||
|
||||
#endif
|
|
@ -0,0 +1,134 @@
|
|||
#include "paging.h"
|
||||
#include "context.h"
|
||||
#include "io.h"
|
||||
|
||||
u32 g_FramePointer;
|
||||
u64 *g_PML4;
|
||||
|
||||
void _zero_paging_structure(u64 *Structure)
|
||||
{
|
||||
for (unsigned i = 0; i < 512; i++)
|
||||
Structure[i] = 0;
|
||||
}
|
||||
|
||||
u32 _allocate_frame_4k(void)
|
||||
{
|
||||
u32 Frame = g_FramePointer;
|
||||
if (Frame > 0xEFFFFF)
|
||||
{
|
||||
puts("BUG: Out of extended memory.\n");
|
||||
for (;;) {}
|
||||
}
|
||||
g_FramePointer += 0x1000;
|
||||
return Frame;
|
||||
}
|
||||
|
||||
void paging_setup(u32 AllocateFramesFrom)
|
||||
{
|
||||
g_FramePointer = AllocateFramesFrom;
|
||||
|
||||
// set up PML4
|
||||
g_PML4 = (u64*)_allocate_frame_4k();
|
||||
_zero_paging_structure(g_PML4);
|
||||
}
|
||||
|
||||
u8 dbg = 0;
|
||||
void paging_map_page(u64 Virtual, u64 Physical)
|
||||
{
|
||||
if (Virtual % 0x1000 || Physical % 0x1000)
|
||||
{
|
||||
puts("BUG: Requsted allocation of unaligned address.\n");
|
||||
print_hex(Virtual);
|
||||
for (;;) {}
|
||||
}
|
||||
// printf("Mapping %x\n", Virtual);
|
||||
|
||||
u64 PML4I = GET_PML4_ENTRY(Virtual);
|
||||
u64 PDPI = GET_PDP_ENTRY(Virtual);
|
||||
u64 DIRI = GET_DIR_ENTRY(Virtual);
|
||||
u64 TABI = GET_TAB_ENTRY(Virtual);
|
||||
// printf("%x %i/%i/%i/%i\n", Virtual, PML4I, PDPI, DIRI, TABI);
|
||||
|
||||
u64 *PDP = (u64 *)(g_PML4[PML4I] & 0xFFFFF000);
|
||||
if (PDP == 0)
|
||||
{
|
||||
// printf("-> Creating PDP @%i\n", PML4I);
|
||||
PDP = (u64 *)_allocate_frame_4k();
|
||||
_zero_paging_structure(PDP);
|
||||
g_PML4[PML4I] = ((u64)PDP) | 3;
|
||||
}
|
||||
u64 *Directory = (u64 *)(PDP[PDPI] & 0xFFFFF000);
|
||||
if (Directory == 0)
|
||||
{
|
||||
// printf("-> Creating Dirctory @%i/%i\n", PML4I, PDPI);
|
||||
Directory = (u64 *)_allocate_frame_4k();
|
||||
_zero_paging_structure(Directory);
|
||||
PDP[PDPI] = ((u64)Directory) | 3;
|
||||
printf("P%x[%i] < d%x\n", (u64)PDP, PDPI, (u64)Directory);
|
||||
dbg = 0;
|
||||
}
|
||||
u64 *Table = (u64 *)(Directory[DIRI] & 0xFFFFF000);
|
||||
if (Table == 0)
|
||||
{
|
||||
if (dbg < 3)
|
||||
{
|
||||
printf("P%x[%i] == D%x\n", (u64)PDP, PDPI, (u64)Directory);
|
||||
dbg += 1;
|
||||
}
|
||||
// printf("P@ %x D@ %x, De %x\n", (u64)PDP, (u64)Directory, Directory[DIRI]);
|
||||
// printf("-> Creating Table @%i/%i/%i\n", PML4I, PDPI, DIRI);
|
||||
Table = (u64 *)_allocate_frame_4k();
|
||||
// printf("aT %x\n", Table);
|
||||
_zero_paging_structure(Table);
|
||||
Directory[DIRI] = ((u64)Table) | 3;
|
||||
// printf("De <- %x\n", Directory[DIRI]);
|
||||
}
|
||||
Table[TABI] = ((u64)Physical) | 3;
|
||||
}
|
||||
|
||||
void paging_map_address(u64 PhysicalStart, u64 VirtualStart, u64 Size)
|
||||
{
|
||||
if (VirtualStart % 0x1000 || PhysicalStart % 0x1000)
|
||||
{
|
||||
puts("BUG: Requsted allocation of unaligned address.\n");
|
||||
for (;;) {}
|
||||
}
|
||||
u64 AlignedSize = Size;
|
||||
if (AlignedSize % 0x1000)
|
||||
AlignedSize = (AlignedSize + 0x1000) & 0xFFFFF000;
|
||||
for (u64 i = 0; i < AlignedSize; i += 0x1000)
|
||||
{
|
||||
paging_map_page(VirtualStart + i, PhysicalStart + i);
|
||||
}
|
||||
}
|
||||
|
||||
void *paging_allocate(u64 VirtualStart, u64 Size)
|
||||
{
|
||||
// let's first allocate all the pages for the actual data
|
||||
u32 Start = 0;
|
||||
for (u64 i = 0; i < Size; i += 0x1000)
|
||||
{
|
||||
u64 Frame = _allocate_frame_4k();
|
||||
if (!Start)
|
||||
Start = Frame;
|
||||
}
|
||||
|
||||
// and now let's map the data (and allocate frames for mapping structures)
|
||||
u32 Frame = Start;
|
||||
for (u64 Virtual = VirtualStart; (Virtual - VirtualStart) < Size; Virtual += 0x1000)
|
||||
{
|
||||
paging_map_page(Virtual, Frame);
|
||||
Frame += 0x1000;
|
||||
}
|
||||
return (void *)Start;
|
||||
}
|
||||
|
||||
u32 paging_get_last_frame(void)
|
||||
{
|
||||
return g_FramePointer;
|
||||
}
|
||||
|
||||
void *paging_get_pml4(void)
|
||||
{
|
||||
return g_PML4;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#ifndef __PAGING_H__
|
||||
#define __PAGING_G__
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define GET_PML4_ENTRY(x) (((u64)x >> 39) & 0x1FF)
|
||||
#define GET_PDP_ENTRY(x) (((u64)x >> 30) & 0x1FF)
|
||||
#define GET_DIR_ENTRY(x) (((u64)x >> 21) & 0x1FF)
|
||||
#define GET_TAB_ENTRY(x) (((u64)x >> 12) & 0x1FF)
|
||||
#define GET_OFFSET(x) (x & 0xFFF)
|
||||
|
||||
void paging_setup(u32 AllocateFramesFrom);
|
||||
void paging_map_address(u64 PhysicalStart, u64 VirtualStart, u64 Size);
|
||||
void *paging_allocate(u64 VirtualStart, u64 Size);
|
||||
u32 paging_get_last_frame(void);
|
||||
void *paging_get_pml4(void);
|
||||
|
||||
#endif
|
|
@ -3,8 +3,11 @@
|
|||
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef short s16;
|
||||
typedef unsigned int u32;
|
||||
typedef int s32;
|
||||
typedef unsigned long long u64;
|
||||
typedef long long s64;
|
||||
typedef char s8;
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue