Restructured and rewritten entire codebase

This commit is contained in:
Alex
2023-10-09 01:16:24 +03:00
parent 446a571018
commit 889e1522a3
484 changed files with 15683 additions and 14032 deletions

View File

@ -0,0 +1,38 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
.code32
.extern Multiboot_start
.section .bootstrap.text, "a"
.global _start
_start:
/* Check for multiboot */
cmp $0x2BADB002, %eax
je .Multiboot
/* Unkown bootloader */
.Hang:
cli
hlt
jmp .Hang
/* Multiboot */
.Multiboot:
call Multiboot_start
jmp .Hang

View File

@ -0,0 +1,317 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <boot/binfo.h>
#include <types.h>
#include <debug.h>
#include <convert.h>
#include "../../../../../tools/limine/limine.h"
#include "../../../../kernel.h"
void InitLimine();
static volatile struct limine_entry_point_request EntryPointRequest = {
.id = LIMINE_ENTRY_POINT_REQUEST,
.revision = 0,
.response = NULL,
.entry = InitLimine};
static volatile struct limine_bootloader_info_request BootloaderInfoRequest = {
.id = LIMINE_BOOTLOADER_INFO_REQUEST,
.revision = 0};
static volatile struct limine_framebuffer_request FramebufferRequest = {
.id = LIMINE_FRAMEBUFFER_REQUEST,
.revision = 0};
static volatile struct limine_memmap_request MemmapRequest = {
.id = LIMINE_MEMMAP_REQUEST,
.revision = 0};
static volatile struct limine_kernel_address_request KernelAddressRequest = {
.id = LIMINE_KERNEL_ADDRESS_REQUEST,
.revision = 0};
static volatile struct limine_rsdp_request RsdpRequest = {
.id = LIMINE_RSDP_REQUEST,
.revision = 0};
static volatile struct limine_kernel_file_request KernelFileRequest = {
.id = LIMINE_KERNEL_FILE_REQUEST,
.revision = 0};
static volatile struct limine_module_request ModuleRequest = {
.id = LIMINE_MODULE_REQUEST,
.revision = 0};
static volatile struct limine_smbios_request SmbiosRequest = {
.id = LIMINE_SMBIOS_REQUEST,
.revision = 0};
void *TempStackPtr = NULL;
__naked __used __no_stack_protector void InitLimine()
{
asmv("mov %%rsp, %0"
: "=r"(TempStackPtr));
asmv("mov %0, %%rsp"
:
: "r"((uintptr_t)TempStackPtr - 0xFFFF800000000000));
asmv("mov $0, %rax\n"
"mov $0, %rbx\n"
"mov $0, %rcx\n"
"mov $0, %rdx\n"
"mov $0, %rsi\n"
"mov $0, %rdi\n"
"mov $0, %rbp\n"
"mov $0, %r8\n"
"mov $0, %r9\n"
"mov $0, %r10\n"
"mov $0, %r11\n"
"mov $0, %r12\n"
"mov $0, %r13\n"
"mov $0, %r14\n"
"mov $0, %r15");
asmv("jmp InitLimineAfterStack");
}
SafeFunction NIF void InitLimineAfterStack()
{
struct BootInfo binfo = {};
struct limine_bootloader_info_response *BootloaderInfoResponse = BootloaderInfoRequest.response;
info("Bootloader: %s %s", BootloaderInfoResponse->name, BootloaderInfoResponse->version);
struct limine_framebuffer_response *FrameBufferResponse = FramebufferRequest.response;
struct limine_memmap_response *MemmapResponse = MemmapRequest.response;
struct limine_kernel_address_response *KernelAddressResponse = KernelAddressRequest.response;
struct limine_rsdp_response *RsdpResponse = RsdpRequest.response;
struct limine_kernel_file_response *KernelFileResponse = KernelFileRequest.response;
struct limine_module_response *ModuleResponse = ModuleRequest.response;
struct limine_smbios_response *SmbiosResponse = SmbiosRequest.response;
if (FrameBufferResponse == NULL || FrameBufferResponse->framebuffer_count < 1)
{
error("No framebuffer available [%#lx;%ld]", FrameBufferResponse,
(FrameBufferResponse == NULL) ? 0 : FrameBufferResponse->framebuffer_count);
inf_loop asmv("hlt");
}
if (MemmapResponse == NULL || MemmapResponse->entry_count < 1)
{
error("No memory map available [%#lx;%ld]", MemmapResponse,
(MemmapResponse == NULL) ? 0 : MemmapResponse->entry_count);
inf_loop asmv("hlt");
}
if (KernelAddressResponse == NULL)
{
error("No kernel address available [%#lx]", KernelAddressResponse);
inf_loop asmv("hlt");
}
if (RsdpResponse == NULL || RsdpResponse->address == 0)
{
error("No RSDP address available [%#lx;%#lx]", RsdpResponse,
(RsdpResponse == NULL) ? 0 : RsdpResponse->address);
inf_loop asmv("hlt");
}
if (KernelFileResponse == NULL || KernelFileResponse->kernel_file == NULL)
{
error("No kernel file available [%#lx;%#lx]", KernelFileResponse,
(KernelFileResponse == NULL) ? 0 : KernelFileResponse->kernel_file);
inf_loop asmv("hlt");
}
/* Actual parsing starts here */
for (uint64_t i = 0; i < FrameBufferResponse->framebuffer_count; i++)
{
struct limine_framebuffer *framebuffer = FrameBufferResponse->framebuffers[i];
switch (framebuffer->memory_model)
{
case LIMINE_FRAMEBUFFER_RGB:
binfo.Framebuffer[i].Type = RGB;
break;
default:
{
error("Unsupported framebuffer memory model %d", framebuffer->memory_model);
inf_loop asmv("hlt");
}
}
binfo.Framebuffer[i].BaseAddress = (void *)((uintptr_t)framebuffer->address - 0xFFFF800000000000);
binfo.Framebuffer[i].Width = (uint32_t)framebuffer->width;
binfo.Framebuffer[i].Height = (uint32_t)framebuffer->height;
binfo.Framebuffer[i].Pitch = (uint32_t)framebuffer->pitch;
binfo.Framebuffer[i].BitsPerPixel = framebuffer->bpp;
binfo.Framebuffer[i].RedMaskSize = framebuffer->red_mask_size;
binfo.Framebuffer[i].RedMaskShift = framebuffer->red_mask_shift;
binfo.Framebuffer[i].GreenMaskSize = framebuffer->green_mask_size;
binfo.Framebuffer[i].GreenMaskShift = framebuffer->green_mask_shift;
binfo.Framebuffer[i].BlueMaskSize = framebuffer->blue_mask_size;
binfo.Framebuffer[i].BlueMaskShift = framebuffer->blue_mask_shift;
binfo.Framebuffer[i].ExtendedDisplayIdentificationData = framebuffer->edid;
binfo.Framebuffer[i].EDIDSize = framebuffer->edid_size;
debug("Framebuffer %d: %dx%d %d bpp", i,
binfo.Framebuffer[i].Width,
binfo.Framebuffer[i].Height,
binfo.Framebuffer[i].BitsPerPixel);
debug("More info:\nAddress: %#lx\nPitch: %ld\nType: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d\nEDID: %#lx\nEDIDSize: %d",
binfo.Framebuffer[i].BaseAddress,
binfo.Framebuffer[i].Pitch,
binfo.Framebuffer[i].Type,
binfo.Framebuffer[i].RedMaskSize,
binfo.Framebuffer[i].RedMaskShift,
binfo.Framebuffer[i].GreenMaskSize,
binfo.Framebuffer[i].GreenMaskShift,
binfo.Framebuffer[i].BlueMaskSize,
binfo.Framebuffer[i].BlueMaskShift,
binfo.Framebuffer[i].ExtendedDisplayIdentificationData,
binfo.Framebuffer[i].EDIDSize);
}
binfo.Memory.Entries = MemmapResponse->entry_count;
for (uint64_t i = 0; i < MemmapResponse->entry_count; i++)
{
if (MemmapResponse->entry_count > MAX_MEMORY_ENTRIES)
{
warn("Too many memory entries, skipping the rest...");
break;
}
struct limine_memmap_entry *entry = MemmapResponse->entries[i];
if (!entry)
{
warn("Null memory entry %ld (%#lx), skipping...", i, entry);
continue;
}
binfo.Memory.Size += entry->length;
switch (entry->type)
{
case LIMINE_MEMMAP_USABLE:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = Usable;
break;
case LIMINE_MEMMAP_RESERVED:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = Reserved;
break;
case LIMINE_MEMMAP_ACPI_RECLAIMABLE:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = ACPIReclaimable;
break;
case LIMINE_MEMMAP_ACPI_NVS:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = ACPINVS;
break;
case LIMINE_MEMMAP_BAD_MEMORY:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = BadMemory;
break;
case LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = BootloaderReclaimable;
break;
case LIMINE_MEMMAP_KERNEL_AND_MODULES:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = KernelAndModules;
break;
case LIMINE_MEMMAP_FRAMEBUFFER:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = Framebuffer;
break;
default:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = Unknown;
break;
}
}
if (ModuleResponse != NULL && ModuleResponse->module_count > 0)
{
for (uint64_t i = 0; i < ModuleResponse->module_count; i++)
{
if (i > MAX_MODULES)
{
warn("Too many modules, skipping the rest...");
break;
}
binfo.Modules[i].Address = (void *)((uint64_t)ModuleResponse->modules[i]->address - 0xFFFF800000000000);
binfo.Modules[i].Size = ModuleResponse->modules[i]->size;
strncpy(binfo.Modules[i].Path,
ModuleResponse->modules[i]->path,
strlen(ModuleResponse->modules[i]->path) + 1);
strncpy(binfo.Modules[i].CommandLine,
ModuleResponse->modules[i]->cmdline,
strlen(ModuleResponse->modules[i]->cmdline) + 1);
debug("Module %d:\nAddress: %#lx\nPath: \"%s\"\nCommand Line: \"%s\"\nSize: %ld",
i,
binfo.Modules[i].Address,
binfo.Modules[i].Path,
binfo.Modules[i].CommandLine,
binfo.Modules[i].Size);
}
}
binfo.RSDP = (struct RSDPInfo *)((uintptr_t)RsdpResponse->address - 0xFFFF800000000000);
debug("RSDP: %#lx [Signature: \"%.8s\"] [OEM: \"%.6s\"]",
binfo.RSDP, binfo.RSDP->Signature, binfo.RSDP->OEMID);
if (SmbiosResponse->entry_64 != NULL)
binfo.SMBIOSPtr = (void *)((uintptr_t)SmbiosResponse->entry_64 - 0xFFFF800000000000);
else if (SmbiosResponse->entry_32 != NULL)
binfo.SMBIOSPtr = (void *)((uintptr_t)SmbiosResponse->entry_32 - 0xFFFF800000000000);
else
binfo.SMBIOSPtr = NULL;
debug("SMBIOS: %#lx %#lx (binfo: %#lx)",
SmbiosResponse->entry_32,
SmbiosResponse->entry_64,
binfo.SMBIOSPtr);
binfo.Kernel.PhysicalBase = (void *)KernelAddressResponse->physical_base;
binfo.Kernel.VirtualBase = (void *)KernelAddressResponse->virtual_base;
binfo.Kernel.FileBase = (void *)((uintptr_t)KernelFileResponse->kernel_file->address - 0xFFFF800000000000);
binfo.Kernel.Size = KernelFileResponse->kernel_file->size;
strncpy(binfo.Kernel.CommandLine,
KernelFileResponse->kernel_file->cmdline,
strlen(KernelFileResponse->kernel_file->cmdline) + 1);
debug("Kernel physical address: %#lx", binfo.Kernel.PhysicalBase);
debug("Kernel virtual address: %#lx", binfo.Kernel.VirtualBase);
strncpy(binfo.Bootloader.Name,
BootloaderInfoResponse->name,
strlen(BootloaderInfoResponse->name) + 1);
strncpy(binfo.Bootloader.Version,
BootloaderInfoResponse->version,
strlen(BootloaderInfoResponse->version) + 1);
Entry(&binfo);
}

View File

@ -0,0 +1,81 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
.intel_syntax noprefix
.code32
.section .bootstrap.text, "a"
.global DetectCPUID
DetectCPUID:
pushfd
pop eax
mov ecx, eax
xor eax, 0x200000
push eax
popfd
pushfd
pop eax
push ecx
popfd
xor eax, ecx
jz .NoCPUID
mov eax, 0x1
ret
.NoCPUID:
xor eax, eax
ret
.global Detect64Bit
Detect64Bit:
mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb .NoLongMode
mov eax, 0x80000001
cpuid
test edx, 0x20000000
jz .NoLongMode
mov eax, 0x1
ret
.NoLongMode:
xor eax, eax
ret
.global DetectPSE
DetectPSE:
mov eax, 0x00000001
cpuid
test edx, 0x00000008
jz .NoPSE
mov eax, 0x1
ret
.NoPSE:
xor eax, eax
ret
.global DetectPAE
DetectPAE:
mov eax, 0x00000001
cpuid
test edx, 0x00000040
jz .NoPAE
mov eax, 0x1
ret
.NoPAE:
xor eax, eax
ret

View File

@ -0,0 +1,64 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
.code32
.section .bootstrap.text, "a"
.align 32
.global gdtr
gdtr:
.word GDT32_END - GDT32 - 1
.long GDT32
.align 32
GDT32:
.quad 0x0
.word 0xFFFF
.word 0x0000
.byte 0x00
.word 0xCF9A
.byte 0x00
.word 0xFFFF
.word 0x0000
.byte 0x00
.word 0xCF92
.byte 0x00
.word 0x0100
.word 0x1000
.byte 0x00
.word 0x4092
.byte 0x00
GDT32_END:
nop
.global LoadGDT32
LoadGDT32:
lgdt [gdtr]
ljmp $0x8, $ActivateGDT
ActivateGDT:
mov $0x10, %cx
mov %cx, %ss
mov %cx, %ds
mov %cx, %es
mov %cx, %fs
mov $0x18, %cx
mov %cx, %gs
ret

View File

@ -0,0 +1,62 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
.code64
.section .bootstrap.data, "a"
/* Access bits */
A = 0x1
RW = 0x2
DC = 0x4
E = 0x8
S = 0x10
DPL0 = 0x0 /* 0 << 5 ???? */
DPL1 = 0x20
P = 0x80
/* Flags bits */
LONG_MODE = 0x20
SZ_32 = 0x40
GRAN_4K = 0x80
.global GDT64.Null
.global GDT64.Code
.global GDT64.Data
.global GDT64.Tss
.global GDT64.Ptr
GDT64:
GDT64.Null = . - GDT64
.quad 0
GDT64.Code = . - GDT64
.long 0xFFFF
.byte 0
.byte P | S | E | RW
.byte GRAN_4K | LONG_MODE | 0xF
.byte 0
GDT64.Data = . - GDT64
.long 0xFFFF
.byte 0
.byte P | S | RW
.byte GRAN_4K | SZ_32 | 0xF
.byte 0
GDT64.Tss = . - GDT64
.long 0x00000068
.long 0x00CF8900
GDT64.Ptr:
.word . - GDT64 - 1
.quad GDT64

View File

@ -0,0 +1,301 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <types.h>
union __attribute__((packed)) PageTableEntry
{
struct
{
bool Present : 1; // 0
bool ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3
bool CacheDisable : 1; // 4
bool Accessed : 1; // 5
bool Dirty : 1; // 6
bool PageAttributeTable : 1; // 7
bool Global : 1; // 8
uint8_t Available0 : 3; // 9-11
uint64_t Address : 40; // 12-51
uint32_t Available1 : 7; // 52-58
uint8_t ProtectionKey : 4; // 59-62
bool ExecuteDisable : 1; // 63
};
uint64_t raw;
__always_inline inline SafeFunction NIF void SetAddress(uintptr_t _Address)
{
_Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12);
}
__always_inline inline SafeFunction NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
};
struct __attribute__((packed)) PageTableEntryPtr
{
PageTableEntry Entries[512];
};
union __attribute__((packed)) PageDirectoryEntry
{
struct
{
bool Present : 1; // 0
bool ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3
bool CacheDisable : 1; // 4
bool Accessed : 1; // 5
bool Available0 : 1; // 6
bool PageSize : 1; // 7
uint8_t Available1 : 4; // 8-11
uint64_t Address : 40; // 12-51
uint32_t Available2 : 11; // 52-62
bool ExecuteDisable : 1; // 63
};
uint64_t raw;
__always_inline inline SafeFunction NIF void SetAddress(uintptr_t _Address)
{
_Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12);
}
__always_inline inline SafeFunction NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
};
struct __attribute__((packed)) PageDirectoryEntryPtr
{
PageDirectoryEntry Entries[512];
};
union __attribute__((packed)) PageDirectoryPointerTableEntry
{
struct
{
bool Present : 1; // 0
bool ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3
bool CacheDisable : 1; // 4
bool Accessed : 1; // 5
bool Available0 : 1; // 6
bool PageSize : 1; // 7
uint8_t Available1 : 4; // 8-11
uint64_t Address : 40; // 12-51
uint32_t Available2 : 11; // 52-62
bool ExecuteDisable : 1; // 63
};
uint64_t raw;
__always_inline inline SafeFunction NIF void SetAddress(uintptr_t _Address)
{
_Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12);
}
__always_inline inline SafeFunction NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
};
struct __attribute__((packed)) PageDirectoryPointerTableEntryPtr
{
PageDirectoryPointerTableEntry Entries[512];
};
union __attribute__((packed)) PageMapLevel4
{
struct
{
bool Present : 1; // 0
bool ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3
bool CacheDisable : 1; // 4
bool Accessed : 1; // 5
bool Available0 : 1; // 6
bool Reserved0 : 1; // 7
uint8_t Available1 : 4; // 8-11
uint64_t Address : 40; // 12-51
uint32_t Available2 : 11; // 52-62
bool ExecuteDisable : 1; // 63
};
uint64_t raw;
__always_inline inline SafeFunction NIF void SetAddress(uintptr_t _Address)
{
_Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12);
}
__always_inline inline SafeFunction NIF uintptr_t GetAddress() { return (this->raw & 0x000FFFFFFFFFF000) >> 12; }
};
struct PageTable4
{
PageMapLevel4 Entries[512];
} __attribute__((aligned(0x1000)));
extern "C" char BootPageTable[];
extern uintptr_t _kernel_start, _kernel_end;
__attribute__((section(".bootstrap.data"))) static PageTable4 *BPTable = (PageTable4 *)BootPageTable;
__attribute__((section(".bootstrap.data"))) static size_t BPT_Allocated = 0x4000;
__always_inline inline SafeFunction NIF void *RequestPage()
{
void *Page = (void *)(BootPageTable + BPT_Allocated);
BPT_Allocated += 0x1000;
if (BPT_Allocated >= 0x10000) /* The length of BootPageTable */
{
while (true)
;
}
return Page;
}
class PageMapIndexer
{
public:
uintptr_t PMLIndex = 0;
uintptr_t PDPTEIndex = 0;
uintptr_t PDEIndex = 0;
uintptr_t PTEIndex = 0;
__always_inline inline SafeFunction NIF PageMapIndexer(uintptr_t VirtualAddress)
{
uintptr_t Address = VirtualAddress;
Address >>= 12;
this->PTEIndex = Address & 0x1FF;
Address >>= 9;
this->PDEIndex = Address & 0x1FF;
Address >>= 9;
this->PDPTEIndex = Address & 0x1FF;
Address >>= 9;
this->PMLIndex = Address & 0x1FF;
}
};
__attribute__((section(".bootstrap.text"))) SafeFunction NIF void MB2_64_Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags)
{
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
// Clear any flags that are not 1 << 0 (Present) - 1 << 5 (Accessed) because rest are for page table entries only
uint64_t DirectoryFlags = Flags & 0x3F;
PageMapLevel4 PML4 = BPTable->Entries[Index.PMLIndex];
PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr;
if (!PML4.Present)
{
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)RequestPage();
if (PDPTEPtr == nullptr)
return;
{
void *ptr = PDPTEPtr;
uint8_t value = 0;
size_t num = 0x1000;
uint8_t *p = (uint8_t *)ptr;
for (size_t i = 0; i < num; i++)
p[i] = value;
}
PML4.Present = true;
PML4.SetAddress((uintptr_t)PDPTEPtr >> 12);
}
else
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4.GetAddress() << 12);
PML4.raw |= DirectoryFlags;
BPTable->Entries[Index.PMLIndex] = PML4;
PageDirectoryPointerTableEntry PDPTE = PDPTEPtr->Entries[Index.PDPTEIndex];
PageDirectoryEntryPtr *PDEPtr = nullptr;
if (!PDPTE.Present)
{
PDEPtr = (PageDirectoryEntryPtr *)RequestPage();
if (PDEPtr == nullptr)
return;
{
void *ptr = PDEPtr;
uint8_t value = 0;
size_t num = 0x1000;
uint8_t *p = (uint8_t *)ptr;
for (size_t i = 0; i < num; i++)
p[i] = value;
}
PDPTE.Present = true;
PDPTE.SetAddress((uintptr_t)PDEPtr >> 12);
}
else
PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE.GetAddress() << 12);
PDPTE.raw |= DirectoryFlags;
PDPTEPtr->Entries[Index.PDPTEIndex] = PDPTE;
PageDirectoryEntry PDE = PDEPtr->Entries[Index.PDEIndex];
PageTableEntryPtr *PTEPtr = nullptr;
if (!PDE.Present)
{
PTEPtr = (PageTableEntryPtr *)RequestPage();
if (PTEPtr == nullptr)
return;
{
void *ptr = PTEPtr;
uint8_t value = 0;
size_t num = 0x1000;
uint8_t *p = (uint8_t *)ptr;
for (size_t i = 0; i < num; i++)
p[i] = value;
}
PDE.Present = true;
PDE.SetAddress((uintptr_t)PTEPtr >> 12);
}
else
PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE.GetAddress() << 12);
PDE.raw |= DirectoryFlags;
PDEPtr->Entries[Index.PDEIndex] = PDE;
PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex];
PTE.Present = true;
PTE.raw |= Flags;
PTE.SetAddress((uintptr_t)PhysicalAddress >> 12);
PTEPtr->Entries[Index.PTEIndex] = PTE;
asmv("invlpg (%0)"
:
: "r"(VirtualAddress)
: "memory");
}
EXTERNC __attribute__((section(".bootstrap.text"))) SafeFunction NIF __attribute__((section(".bootstrap.text"))) void UpdatePageTable64()
{
BPTable = (PageTable4 *)BootPageTable;
uintptr_t KernelStart = (uintptr_t)&_kernel_start;
uintptr_t KernelEnd = (uintptr_t)&_kernel_end;
uintptr_t PhysicalStart = KernelStart - 0xFFFFFFFF80000000;
for (uintptr_t i = KernelStart; i < KernelEnd; i += 0x1000)
{
MB2_64_Map((void *)i, (void *)PhysicalStart, 0x3);
PhysicalStart += 0x1000;
}
asmv("mov %%cr3, %%rax\n"
"mov %%rax, %%cr3\n"
:
:
: "rax");
}

View File

@ -0,0 +1,62 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
PAGE_TABLE_SIZE = 0x4
.code32
.section .bootstrap.data, "a"
.align 0x1000
.global BootPageTable
BootPageTable:
.space 0x10000 /* 0x4000 bytes will be used in UpdatePageTable */
.section .bootstrap.text, "a"
.global UpdatePageTable
UpdatePageTable:
mov $(BootPageTable + 0x0000), %edi /* First PML4E */
mov $(BootPageTable + 0x1000), %eax /* First PDPTE */
or $0x3, %eax /* Bitwise OR on eax (PDPTE) with 11b (Present, Write) */
mov %eax, (%edi) /* Write 11b to PML4E */
mov $(BootPageTable + 0x1000), %edi /* First PDPTE */
mov $(BootPageTable + 0x2000), %eax /* First PDE */
or $0x3, %eax /* Bitwise OR on eax (PDE) with 11b (Present, Write) */
mov $PAGE_TABLE_SIZE, %ecx /* For loop instruction */
mov $0x0, %ebx /* Value to store in the next 4 bytes */
.FillPageTableLevel3:
mov %eax, (%edi) /* Store modified PDE in PDPTE */
mov %ebx, 0x4(%edi) /* Store the ebx value in the next 4 bytes */
add $0x1000, %eax /* Increment (page size) */
adc $0x0, %ebx /* Add 0 to carry flag */
add $0x8, %edi /* Add 8 to edi (next PDE) */
loop .FillPageTableLevel3 /* Loop until ecx is 0 */
mov $(BootPageTable + 0x2000), %edi /* First PDE */
mov $0x83, %eax /* Present, Write, Large Page */
mov $(512 * PAGE_TABLE_SIZE), %ecx /* For loop instruction */
mov $0x0, %ebx /* Value to store in the next 4 bytes */
.FillPageTableLevel2:
mov %eax, (%edi) /* Store modified PDE in PDPTE */
mov %ebx, 0x4(%edi) /* Store the ebx value in the next 4 bytes */
add $0x200000, %eax /* Increment (page size) */
adc $0x0, %ebx /* Add 0 (carry flag) to ebx to increment if there was a carry */
add $0x8, %edi /* Add 8 to edi (next PDE) */
loop .FillPageTableLevel2 /* Loop until ecx is 0 */
ret

View File

@ -0,0 +1,38 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
.code32
.extern Multiboot_start
.section .multiboot, "a"
.align 4
MULTIBOOT_HEADER:
.long 0x1BADB002
.long 0x1 | 0x2 | 0x4
.long -(0x1BADB002 + (0x1 | 0x2 | 0x4))
/* KLUDGE */
.long 0
.long 0
.long 0
.long 0
.long 0
/* VIDEO MODE */
.long 0
.long 0
.long 0
.long 0

View File

@ -0,0 +1,92 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
.code32
.extern Multiboot_start
/* https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html */
.section .multiboot2, "a"
.align 0x1000
MULTIBOOT2_HEADER_START:
.long 0xE85250D6
.long 0
.long (MULTIBOOT2_HEADER_END - MULTIBOOT2_HEADER_START)
.long 0x100000000 - (MULTIBOOT2_HEADER_END - MULTIBOOT2_HEADER_START) - 0 - 0xE85250D6
.align 8
InfoRequestTag_Start:
.word 1
.word 0
.long InfoRequestTag_End - InfoRequestTag_Start
.long 1 /* Command Line */
.long 2 /* Boot Loader Name */
.long 3 /* Module */
.long 4 /* Basic Memory Information */
.long 5 /* BIOS Boot Device */
.long 6 /* Memory Map */
.long 7 /* VBE */
.long 8 /* Framebuffer */
.long 9 /* ELF Sections */
.long 10 /* APM Table */
.long 11 /* EFI 32-bit System Table Pointer */
.long 12 /* EFI 64-bit System Table Pointer */
/* .long 13 */ /* SMBIOS */
.long 14 /* ACPI Old */
.long 15 /* ACPI New */
.long 16 /* Network */
.long 17 /* EFI Memory Map */
.long 18 /* EFI Boot Services Notifier */
.long 19 /* EFI 32-bit Image Handle Pointer */
.long 20 /* EFI 64-bit Image Handle Pointer */
.long 21 /* Load Base Address */
InfoRequestTag_End:
.align 8
FramebufferTag_Start:
.word 5
.word 1
.long FramebufferTag_End - FramebufferTag_Start
.long 0
.long 0
.long 32
FramebufferTag_End:
.align 8
EGATextSupportTag_Start:
.word 4
.word 0
.long EGATextSupportTag_End - EGATextSupportTag_Start
.long 0 /* https://www.gnu.org/software/grub/manual/multiboot2/html_node/Console-header-tags.html */
EGATextSupportTag_End:
.align 8
AlignedModulesTag_Start:
.word 6
.word 0
.long AlignedModulesTag_End - AlignedModulesTag_Start
AlignedModulesTag_End:
.align 8
EntryAddressTag_Start:
.word 3
.word 0
.long EntryAddressTag_End - EntryAddressTag_Start
.long Multiboot_start
EntryAddressTag_End:
.align 8
EndTag_Start:
.word 0
.word 0
.long EndTag_End - EndTag_Start
EndTag_End:
MULTIBOOT2_HEADER_END:
nop

View File

@ -0,0 +1,210 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <types.h>
#include <boot/protocol/multiboot.h>
#include <memory.hpp>
#include "../../../../kernel.h"
void multiboot_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
{
multiboot_info *InfoAddress = r_cst(multiboot_info *, Info);
if (InfoAddress->flags & MULTIBOOT_INFO_MEMORY)
{
fixme("mem_lower: %#x, mem_upper: %#x",
InfoAddress->mem_lower, InfoAddress->mem_upper);
}
if (InfoAddress->flags & MULTIBOOT_INFO_BOOTDEV)
{
fixme("boot_device: %#x",
InfoAddress->boot_device);
}
if (InfoAddress->flags & MULTIBOOT_INFO_CMDLINE)
{
strncpy(mb2binfo.Kernel.CommandLine,
r_cst(const char *, InfoAddress->cmdline),
strlen(r_cst(const char *, InfoAddress->cmdline)));
debug("Kernel command line: %s", mb2binfo.Kernel.CommandLine);
}
if (InfoAddress->flags & MULTIBOOT_INFO_MODS)
{
multiboot_mod_list *module = r_cst(multiboot_mod_list *, InfoAddress->mods_addr);
for (size_t i = 0; i < InfoAddress->mods_count; i++)
{
if (i > MAX_MODULES)
{
warn("Too many modules, skipping the rest...");
break;
}
mb2binfo.Modules[i].Address = (void *)(uint64_t)module[i].mod_start;
mb2binfo.Modules[i].Size = module[i].mod_end - module[i].mod_start;
strncpy(mb2binfo.Modules[i].Path, "(null)", 6);
strncpy(mb2binfo.Modules[i].CommandLine, r_cst(const char *, module[i].cmdline),
strlen(r_cst(const char *, module[i].cmdline)));
debug("Module: %s", mb2binfo.Modules[i].Path);
}
}
if (InfoAddress->flags & MULTIBOOT_INFO_AOUT_SYMS)
{
fixme("aout_sym: [tabsize: %#x, strsize: %#x, addr: %#x, reserved: %#x]",
InfoAddress->u.aout_sym.tabsize, InfoAddress->u.aout_sym.strsize,
InfoAddress->u.aout_sym.addr, InfoAddress->u.aout_sym.reserved);
}
if (InfoAddress->flags & MULTIBOOT_INFO_ELF_SHDR)
{
mb2binfo.Kernel.Symbols.Num = InfoAddress->u.elf_sec.num;
mb2binfo.Kernel.Symbols.EntSize = InfoAddress->u.elf_sec.size;
mb2binfo.Kernel.Symbols.Shndx = InfoAddress->u.elf_sec.shndx;
mb2binfo.Kernel.Symbols.Sections = s_cst(uintptr_t, InfoAddress->u.elf_sec.addr);
}
if (InfoAddress->flags & MULTIBOOT_INFO_MEM_MAP)
{
mb2binfo.Memory.Entries = InfoAddress->mmap_length / sizeof(multiboot_mmap_entry);
for (uint32_t i = 0; i < mb2binfo.Memory.Entries; i++)
{
if (i > MAX_MEMORY_ENTRIES)
{
warn("Too many memory entries, skipping the rest...");
break;
}
multiboot_mmap_entry entry = r_cst(multiboot_mmap_entry *, InfoAddress->mmap_addr)[i];
mb2binfo.Memory.Size += entry.len;
switch (entry.type)
{
case MULTIBOOT_MEMORY_AVAILABLE:
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
mb2binfo.Memory.Entry[i].Length = entry.len;
mb2binfo.Memory.Entry[i].Type = Usable;
break;
case MULTIBOOT_MEMORY_RESERVED:
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
mb2binfo.Memory.Entry[i].Length = entry.len;
mb2binfo.Memory.Entry[i].Type = Reserved;
break;
case MULTIBOOT_MEMORY_ACPI_RECLAIMABLE:
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
mb2binfo.Memory.Entry[i].Length = entry.len;
mb2binfo.Memory.Entry[i].Type = ACPIReclaimable;
break;
case MULTIBOOT_MEMORY_NVS:
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
mb2binfo.Memory.Entry[i].Length = entry.len;
mb2binfo.Memory.Entry[i].Type = ACPINVS;
break;
case MULTIBOOT_MEMORY_BADRAM:
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
mb2binfo.Memory.Entry[i].Length = entry.len;
mb2binfo.Memory.Entry[i].Type = BadMemory;
break;
default:
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
mb2binfo.Memory.Entry[i].Length = entry.len;
mb2binfo.Memory.Entry[i].Type = Unknown;
break;
}
debug("Memory entry: [BaseAddress: %#x, Length: %#x, Type: %d]",
mb2binfo.Memory.Entry[i].BaseAddress,
mb2binfo.Memory.Entry[i].Length,
mb2binfo.Memory.Entry[i].Type);
}
}
if (InfoAddress->flags & MULTIBOOT_INFO_DRIVE_INFO)
{
fixme("drives_length: %d, drives_addr: %#x",
InfoAddress->drives_length, InfoAddress->drives_addr);
}
if (InfoAddress->flags & MULTIBOOT_INFO_CONFIG_TABLE)
{
fixme("config_table: %#x",
InfoAddress->config_table);
}
if (InfoAddress->flags & MULTIBOOT_INFO_BOOT_LOADER_NAME)
{
strncpy(mb2binfo.Bootloader.Name,
r_cst(const char *, InfoAddress->boot_loader_name),
strlen(r_cst(const char *, InfoAddress->boot_loader_name)));
debug("Bootloader name: %s", mb2binfo.Bootloader.Name);
}
if (InfoAddress->flags & MULTIBOOT_INFO_APM_TABLE)
{
fixme("apm_table: %#x",
InfoAddress->apm_table);
}
if (InfoAddress->flags & MULTIBOOT_INFO_VBE_INFO)
{
fixme("vbe_control_info: %#x, vbe_mode_info: %#x, vbe_mode: %#x, vbe_interface_seg: %#x, vbe_interface_off: %#x, vbe_interface_len: %#x",
InfoAddress->vbe_control_info, InfoAddress->vbe_mode_info,
InfoAddress->vbe_mode, InfoAddress->vbe_interface_seg,
InfoAddress->vbe_interface_off, InfoAddress->vbe_interface_len);
}
if (InfoAddress->flags & MULTIBOOT_INFO_FRAMEBUFFER_INFO)
{
static int fb_count = 0;
mb2binfo.Framebuffer[fb_count].BaseAddress = (void *)InfoAddress->framebuffer_addr;
mb2binfo.Framebuffer[fb_count].Width = InfoAddress->framebuffer_width;
mb2binfo.Framebuffer[fb_count].Height = InfoAddress->framebuffer_height;
mb2binfo.Framebuffer[fb_count].Pitch = InfoAddress->framebuffer_pitch;
mb2binfo.Framebuffer[fb_count].BitsPerPixel = InfoAddress->framebuffer_bpp;
switch (InfoAddress->framebuffer_type)
{
case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
{
mb2binfo.Framebuffer[fb_count].Type = Indexed;
break;
}
case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
{
mb2binfo.Framebuffer[fb_count].Type = RGB;
mb2binfo.Framebuffer[fb_count].RedMaskSize = InfoAddress->framebuffer_red_mask_size;
mb2binfo.Framebuffer[fb_count].RedMaskShift = InfoAddress->framebuffer_red_field_position;
mb2binfo.Framebuffer[fb_count].GreenMaskSize = InfoAddress->framebuffer_green_mask_size;
mb2binfo.Framebuffer[fb_count].GreenMaskShift = InfoAddress->framebuffer_green_field_position;
mb2binfo.Framebuffer[fb_count].BlueMaskSize = InfoAddress->framebuffer_blue_mask_size;
mb2binfo.Framebuffer[fb_count].BlueMaskShift = InfoAddress->framebuffer_blue_field_position;
break;
}
case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
{
mb2binfo.Framebuffer[fb_count].Type = EGA;
break;
}
default:
{
mb2binfo.Framebuffer[fb_count].Type = Unknown_Framebuffer_Type;
break;
}
}
debug("Framebuffer %d: %dx%d %d bpp",
fb_count, InfoAddress->framebuffer_width,
InfoAddress->framebuffer_height,
InfoAddress->framebuffer_bpp);
debug("More info:\nAddress: %p\nPitch: %d\nMemoryModel: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d",
InfoAddress->framebuffer_addr, InfoAddress->framebuffer_pitch, InfoAddress->framebuffer_type,
InfoAddress->framebuffer_red_mask_size, InfoAddress->framebuffer_red_field_position, InfoAddress->framebuffer_green_mask_size,
InfoAddress->framebuffer_green_field_position, InfoAddress->framebuffer_blue_mask_size, InfoAddress->framebuffer_blue_field_position);
}
mb2binfo.Kernel.PhysicalBase = (void *)&_bootstrap_start;
mb2binfo.Kernel.VirtualBase = (void *)(uint64_t)((uint64_t)&_bootstrap_start + 0xFFFFFFFF80000000);
mb2binfo.Kernel.Size = ((uint64_t)&_kernel_end - (uint64_t)&_kernel_start) + ((uint64_t)&_bootstrap_end - (uint64_t)&_bootstrap_start);
debug("Kernel base: %p (physical) %p (virtual)", mb2binfo.Kernel.PhysicalBase, mb2binfo.Kernel.VirtualBase);
Entry(&mb2binfo);
}

View File

@ -0,0 +1,284 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <types.h>
#include <boot/protocol/multiboot2.h>
#include <memory.hpp>
#include "../../../../kernel.h"
void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
{
auto InfoAddress = Info;
for (auto Tag = (struct multiboot_tag *)((uint8_t *)InfoAddress + 8);
;
Tag = (struct multiboot_tag *)((multiboot_uint8_t *)Tag + ((Tag->size + 7) & ~7)))
{
if (Tag->type == MULTIBOOT_TAG_TYPE_END)
{
debug("End of multiboot2 tags");
break;
}
switch (Tag->type)
{
case MULTIBOOT_TAG_TYPE_CMDLINE:
{
strncpy(mb2binfo.Kernel.CommandLine,
((multiboot_tag_string *)Tag)->string,
strlen(((multiboot_tag_string *)Tag)->string));
debug("Kernel command line: %s", mb2binfo.Kernel.CommandLine);
break;
}
case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME:
{
strncpy(mb2binfo.Bootloader.Name,
((multiboot_tag_string *)Tag)->string,
strlen(((multiboot_tag_string *)Tag)->string));
debug("Bootloader name: %s", mb2binfo.Bootloader.Name);
break;
}
case MULTIBOOT_TAG_TYPE_MODULE:
{
multiboot_tag_module *module = (multiboot_tag_module *)Tag;
static int module_count = 0;
mb2binfo.Modules[module_count].Address = (void *)(uint64_t)module->mod_start;
mb2binfo.Modules[module_count].Size = module->mod_end - module->mod_start;
strncpy(mb2binfo.Modules[module_count].Path, "(null)", 6);
strncpy(mb2binfo.Modules[module_count].CommandLine, module->cmdline,
strlen(module->cmdline));
debug("Module: %s", mb2binfo.Modules[module_count].Path);
module_count++;
break;
}
case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO:
{
multiboot_tag_basic_meminfo *meminfo = (multiboot_tag_basic_meminfo *)Tag;
fixme("basic_meminfo->[mem_lower: %#x, mem_upper: %#x]",
meminfo->mem_lower, meminfo->mem_upper);
break;
}
case MULTIBOOT_TAG_TYPE_BOOTDEV:
{
multiboot_tag_bootdev *bootdev = (multiboot_tag_bootdev *)Tag;
fixme("bootdev->[biosdev: %#x, slice: %#x, part: %#x]",
bootdev->biosdev, bootdev->slice, bootdev->part);
break;
}
case MULTIBOOT_TAG_TYPE_MMAP:
{
multiboot_tag_mmap *mmap = (multiboot_tag_mmap *)Tag;
size_t EntryCount = mmap->size / sizeof(multiboot_mmap_entry);
mb2binfo.Memory.Entries = EntryCount;
for (uint32_t i = 0; i < EntryCount; i++)
{
if (i > MAX_MEMORY_ENTRIES)
{
warn("Too many memory entries, skipping the rest...");
break;
}
multiboot_mmap_entry entry = mmap->entries[i];
mb2binfo.Memory.Size += entry.len;
switch (entry.type)
{
case MULTIBOOT_MEMORY_AVAILABLE:
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
mb2binfo.Memory.Entry[i].Length = entry.len;
mb2binfo.Memory.Entry[i].Type = Usable;
break;
case MULTIBOOT_MEMORY_RESERVED:
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
mb2binfo.Memory.Entry[i].Length = entry.len;
mb2binfo.Memory.Entry[i].Type = Reserved;
break;
case MULTIBOOT_MEMORY_ACPI_RECLAIMABLE:
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
mb2binfo.Memory.Entry[i].Length = entry.len;
mb2binfo.Memory.Entry[i].Type = ACPIReclaimable;
break;
case MULTIBOOT_MEMORY_NVS:
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
mb2binfo.Memory.Entry[i].Length = entry.len;
mb2binfo.Memory.Entry[i].Type = ACPINVS;
break;
case MULTIBOOT_MEMORY_BADRAM:
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
mb2binfo.Memory.Entry[i].Length = entry.len;
mb2binfo.Memory.Entry[i].Type = BadMemory;
break;
default:
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
mb2binfo.Memory.Entry[i].Length = entry.len;
mb2binfo.Memory.Entry[i].Type = Unknown;
break;
}
debug("Memory entry: [BaseAddress: %#x, Length: %#x, Type: %d]",
mb2binfo.Memory.Entry[i].BaseAddress,
mb2binfo.Memory.Entry[i].Length,
mb2binfo.Memory.Entry[i].Type);
}
break;
}
case MULTIBOOT_TAG_TYPE_VBE:
{
multiboot_tag_vbe *vbe = (multiboot_tag_vbe *)Tag;
fixme("vbe->[vbe_mode: %#x, vbe_interface_seg: %#x, vbe_interface_off: %#x, vbe_interface_len: %#x]",
vbe->vbe_mode, vbe->vbe_interface_seg, vbe->vbe_interface_off, vbe->vbe_interface_len);
break;
}
case MULTIBOOT_TAG_TYPE_FRAMEBUFFER:
{
multiboot_tag_framebuffer *fb = (multiboot_tag_framebuffer *)Tag;
static int fb_count = 0;
mb2binfo.Framebuffer[fb_count].BaseAddress = (void *)fb->common.framebuffer_addr;
mb2binfo.Framebuffer[fb_count].Width = fb->common.framebuffer_width;
mb2binfo.Framebuffer[fb_count].Height = fb->common.framebuffer_height;
mb2binfo.Framebuffer[fb_count].Pitch = fb->common.framebuffer_pitch;
mb2binfo.Framebuffer[fb_count].BitsPerPixel = fb->common.framebuffer_bpp;
switch (fb->common.framebuffer_type)
{
case MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED:
{
mb2binfo.Framebuffer[fb_count].Type = Indexed;
break;
}
case MULTIBOOT_FRAMEBUFFER_TYPE_RGB:
{
mb2binfo.Framebuffer[fb_count].Type = RGB;
mb2binfo.Framebuffer[fb_count].RedMaskSize = fb->framebuffer_red_mask_size;
mb2binfo.Framebuffer[fb_count].RedMaskShift = fb->framebuffer_red_field_position;
mb2binfo.Framebuffer[fb_count].GreenMaskSize = fb->framebuffer_green_mask_size;
mb2binfo.Framebuffer[fb_count].GreenMaskShift = fb->framebuffer_green_field_position;
mb2binfo.Framebuffer[fb_count].BlueMaskSize = fb->framebuffer_blue_mask_size;
mb2binfo.Framebuffer[fb_count].BlueMaskShift = fb->framebuffer_blue_field_position;
break;
}
case MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT:
{
mb2binfo.Framebuffer[fb_count].Type = EGA;
break;
}
default:
{
mb2binfo.Framebuffer[fb_count].Type = Unknown_Framebuffer_Type;
break;
}
}
debug("Framebuffer %d: %dx%d %d bpp", fb_count, fb->common.framebuffer_width, fb->common.framebuffer_height, fb->common.framebuffer_bpp);
debug("More info:\nAddress: %p\nPitch: %d\nMemoryModel: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d",
fb->common.framebuffer_addr, fb->common.framebuffer_pitch, fb->common.framebuffer_type,
fb->framebuffer_red_mask_size, fb->framebuffer_red_field_position, fb->framebuffer_green_mask_size,
fb->framebuffer_green_field_position, fb->framebuffer_blue_mask_size, fb->framebuffer_blue_field_position);
fb_count++;
break;
}
case MULTIBOOT_TAG_TYPE_ELF_SECTIONS:
{
multiboot_tag_elf_sections *elf = (multiboot_tag_elf_sections *)Tag;
mb2binfo.Kernel.Symbols.Num = elf->num;
mb2binfo.Kernel.Symbols.EntSize = elf->entsize;
mb2binfo.Kernel.Symbols.Shndx = elf->shndx;
mb2binfo.Kernel.Symbols.Sections = r_cst(uintptr_t, elf->sections);
break;
}
case MULTIBOOT_TAG_TYPE_APM:
{
multiboot_tag_apm *apm = (multiboot_tag_apm *)Tag;
fixme("apm->[version: %d, cseg: %d, offset: %d, cseg_16: %d, dseg: %d, flags: %d, cseg_len: %d, cseg_16_len: %d, dseg_len: %d]",
apm->version, apm->cseg, apm->offset, apm->cseg_16, apm->dseg, apm->flags, apm->cseg_len, apm->cseg_16_len, apm->dseg_len);
break;
}
case MULTIBOOT_TAG_TYPE_EFI32:
{
multiboot_tag_efi32 *efi32 = (multiboot_tag_efi32 *)Tag;
fixme("efi32->[pointer: %p, size: %d]", efi32->pointer, efi32->size);
break;
}
case MULTIBOOT_TAG_TYPE_EFI64:
{
multiboot_tag_efi64 *efi64 = (multiboot_tag_efi64 *)Tag;
fixme("efi64->[pointer: %p, size: %d]", efi64->pointer, efi64->size);
break;
}
case MULTIBOOT_TAG_TYPE_SMBIOS:
{
multiboot_tag_smbios *smbios = (multiboot_tag_smbios *)Tag;
fixme("smbios->[major: %d, minor: %d]", smbios->major, smbios->minor);
break;
}
case MULTIBOOT_TAG_TYPE_ACPI_OLD:
{
mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_old_acpi *)Tag)->rsdp;
debug("OLD ACPI RSDP: %p", mb2binfo.RSDP);
break;
}
case MULTIBOOT_TAG_TYPE_ACPI_NEW:
{
mb2binfo.RSDP = (BootInfo::RSDPInfo *)((multiboot_tag_new_acpi *)Tag)->rsdp;
debug("NEW ACPI RSDP: %p", mb2binfo.RSDP);
break;
}
case MULTIBOOT_TAG_TYPE_NETWORK:
{
multiboot_tag_network *net = (multiboot_tag_network *)Tag;
fixme("network->[dhcpack: %p]", net->dhcpack);
break;
}
case MULTIBOOT_TAG_TYPE_EFI_MMAP:
{
multiboot_tag_efi_mmap *efi_mmap = (multiboot_tag_efi_mmap *)Tag;
fixme("efi_mmap->[descr_size: %d, descr_vers: %d, efi_mmap: %p]",
efi_mmap->descr_size, efi_mmap->descr_vers, efi_mmap->efi_mmap);
break;
}
case MULTIBOOT_TAG_TYPE_EFI_BS:
{
fixme("efi_bs->[%p] (unknown structure)", Tag);
break;
}
case MULTIBOOT_TAG_TYPE_EFI32_IH:
{
multiboot_tag_efi32_ih *efi32_ih = (multiboot_tag_efi32_ih *)Tag;
fixme("efi32_ih->[pointer: %p]", efi32_ih->pointer);
break;
}
case MULTIBOOT_TAG_TYPE_EFI64_IH:
{
multiboot_tag_efi64_ih *efi64_ih = (multiboot_tag_efi64_ih *)Tag;
fixme("efi64_ih->[pointer: %p]", efi64_ih->pointer);
break;
}
case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
{
multiboot_tag_load_base_addr *load_base_addr = (multiboot_tag_load_base_addr *)Tag;
mb2binfo.Kernel.PhysicalBase = (void *)(uint64_t)load_base_addr->load_base_addr;
mb2binfo.Kernel.VirtualBase = (void *)(uint64_t)(load_base_addr->load_base_addr + 0xFFFFFFFF80000000);
mb2binfo.Kernel.Size = ((uint64_t)&_kernel_end - (uint64_t)&_kernel_start) + ((uint64_t)&_bootstrap_end - (uint64_t)&_bootstrap_start);
debug("Kernel base: %p (physical) %p (virtual)", mb2binfo.Kernel.PhysicalBase, mb2binfo.Kernel.VirtualBase);
break;
}
default:
{
error("Unknown multiboot2 tag type: %d", Tag->type);
break;
}
}
}
Entry(&mb2binfo);
}

View File

@ -0,0 +1,53 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <types.h>
#include <memory.hpp>
#include "../../../../kernel.h"
#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
void multiboot_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info);
void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info);
EXTERNC void multiboot_main(uintptr_t Magic, uintptr_t Info)
{
BootInfo mb2binfo{};
if (Info == NULL || Magic == NULL)
{
if (Magic == NULL)
error("Multiboot magic is NULL");
if (Info == NULL)
error("Multiboot info is NULL");
CPU::Stop();
}
else if (Magic == MULTIBOOT_BOOTLOADER_MAGIC)
multiboot_parse(mb2binfo, Magic, Info);
else if (Magic == MULTIBOOT2_BOOTLOADER_MAGIC)
multiboot2_parse(mb2binfo, Magic, Info);
else
{
error("Unknown multiboot magic %#x", Magic);
CPU::Stop();
}
}

View File

@ -0,0 +1,124 @@
/*
This file is part of Fennix Kernel.
Fennix Kernel 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 3 of
the License, or (at your option) any later version.
Fennix Kernel 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 Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
.code32
KERNEL_STACK_SIZE = 0x4000 /* 16KB */
.extern DetectCPUID
.extern Detect64Bit
.extern DetectPSE
.extern DetectPAE
.extern multiboot_main
.extern LoadGDT32
.extern BootPageTable
.extern UpdatePageTable
.extern GDT64.Ptr
.extern GDT64.Code
.extern GDT64.Data
.section .bootstrap.data, "a"
MB_HeaderMagic:
.quad 0
MB_HeaderInfo:
.quad 0
.section .bootstrap.text, "a"
x32Hang:
cli
hlt
jmp x32Hang
.global Multiboot_start
Multiboot_start:
cli
mov %eax, [MB_HeaderMagic]
mov %ebx, [MB_HeaderInfo]
call DetectCPUID
cmp $0, %eax
je x32Hang
call Detect64Bit
cmp $0, %eax
je x32Hang
call DetectPSE
cmp $0, %eax
je x32Hang
call DetectPAE
cmp $0, %eax
je x32Hang
mov %cr4, %ecx
or $0x00000010, %ecx /* PSE */
or $0x00000020, %ecx /* PAE */
mov %ecx, %cr4
call LoadGDT32
call UpdatePageTable
mov $BootPageTable, %ecx
mov %ecx, %cr3
mov $0xC0000080, %ecx /* EFER */
rdmsr
or $0x800, %eax /* LME */
or $0x100, %eax /* LMA */
or $0x1, %eax /* SCE */
wrmsr
mov %cr0, %ecx
or $0x80000000, %ecx /* PG */
or $0x1, %ecx /* PE */
mov %ecx, %cr0
lgdt [GDT64.Ptr]
ljmp $GDT64.Code, $HigherHalfStart
.extern UpdatePageTable64
.code64
HigherHalfStart:
mov $GDT64.Data, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
call UpdatePageTable64
mov $(KernelStack + KERNEL_STACK_SIZE), %rsp
mov $0x0, %rbp
mov [MB_HeaderMagic], %rdi
mov [MB_HeaderInfo], %rsi
push %rsi
push %rdi
call multiboot_main
.Hang:
hlt
jmp .Hang
.section .bootstrap.bss, "a"
.align 16
KernelStack:
.space KERNEL_STACK_SIZE