mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-07-01 18:39:16 +00:00
Merge remote-tracking branch 'Kernel/master'
This commit is contained in:
36
Kernel/arch/aarch64/bootstrap/boot.S
Normal file
36
Kernel/arch/aarch64/bootstrap/boot.S
Normal file
@ -0,0 +1,36 @@
|
||||
/* Based on this tutorial:
|
||||
https://github.com/s-matyukevich/raspberry-pi-os */
|
||||
|
||||
.section ".text.boot", "a"
|
||||
|
||||
.extern _bss_start
|
||||
.extern _bss_end
|
||||
|
||||
.extern arm64Entry
|
||||
memzero:
|
||||
str xzr, [x0], #8
|
||||
subs x1, x1, #8
|
||||
b.gt memzero
|
||||
ret
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
mrs x0, mpidr_el1
|
||||
and x0, x0, #0xFF
|
||||
cbz x0, _start2
|
||||
b CPU_Loop
|
||||
|
||||
_start2:
|
||||
adr x0, _bss_start
|
||||
adr x1, _bss_end
|
||||
sub x1, x1, x0
|
||||
bl memzero
|
||||
mov sp, #0x200000
|
||||
bl arm64Entry
|
||||
|
||||
Halt:
|
||||
wfe
|
||||
b Halt
|
||||
|
||||
CPU_Loop:
|
||||
b CPU_Loop
|
59
Kernel/arch/aarch64/cpu/smp.cpp
Normal file
59
Kernel/arch/aarch64/cpu/smp.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
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 <smp.hpp>
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <memory.hpp>
|
||||
#include <cpu.hpp>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
volatile bool CPUEnabled = false;
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
static __aligned(0x1000) CPUData CPUs[MAX_CPU] = {0};
|
||||
|
||||
CPUData *GetCPU(uint64_t id) { return &CPUs[id]; }
|
||||
|
||||
CPUData *GetCurrentCPU()
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
|
||||
if (!CPUs[ret].IsActive)
|
||||
{
|
||||
error("CPU %d is not active!", ret);
|
||||
return &CPUs[0];
|
||||
}
|
||||
|
||||
if (CPUs[ret].Checksum != CPU_DATA_CHECKSUM)
|
||||
{
|
||||
error("CPU %d data is corrupted!", ret);
|
||||
return &CPUs[0];
|
||||
}
|
||||
return &CPUs[ret];
|
||||
}
|
||||
|
||||
namespace SMP
|
||||
{
|
||||
int CPUCores = 0;
|
||||
|
||||
void Initialize(void *madt)
|
||||
{
|
||||
fixme("SMP::Initialize() is not implemented!");
|
||||
}
|
||||
}
|
27
Kernel/arch/aarch64/entry.cpp
Normal file
27
Kernel/arch/aarch64/entry.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
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 <debug.h>
|
||||
#include <cpu.hpp>
|
||||
|
||||
EXTERNC void arm64Entry(uint64_t dtb_ptr32, uint64_t x1, uint64_t x2, uint64_t x3)
|
||||
{
|
||||
trace("Hello, World!");
|
||||
CPU::Halt(true);
|
||||
}
|
0
Kernel/arch/aarch64/include/.gitkeep
Normal file
0
Kernel/arch/aarch64/include/.gitkeep
Normal file
90
Kernel/arch/aarch64/linker.ld
Normal file
90
Kernel/arch/aarch64/linker.ld
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
_bootstrap_start = .;
|
||||
.text.boot :
|
||||
{
|
||||
*(.text.boot)
|
||||
. += CONSTANT(MAXPAGESIZE);
|
||||
_bss_start = .;
|
||||
*(.text.bss)
|
||||
_bss_end = .;
|
||||
}
|
||||
_bootstrap_end = .;
|
||||
|
||||
_kernel_start = .;
|
||||
_kernel_text_start = .;
|
||||
.text :
|
||||
{
|
||||
KEEP(*(.text.boot))
|
||||
*(.text .text.*)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
_kernel_text_end = .;
|
||||
|
||||
_kernel_data_start = .;
|
||||
.data :
|
||||
{
|
||||
*(.data .data.*)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
_kernel_data_end = .;
|
||||
|
||||
_kernel_rodata_start = .;
|
||||
.rodata :
|
||||
{
|
||||
*(.rodata .rodata.*)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
|
||||
.init_array :
|
||||
{
|
||||
PROVIDE_HIDDEN(__init_array_start = .);
|
||||
KEEP(*(.init_array .ctors))
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
}
|
||||
|
||||
.fini_array :
|
||||
{
|
||||
PROVIDE_HIDDEN(__fini_array_start = .);
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||
KEEP(*(.fini_array .dtors))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
}
|
||||
_kernel_rodata_end = .;
|
||||
|
||||
_kernel_bss_start = .;
|
||||
.bss :
|
||||
{
|
||||
*(.bss .bss.*)
|
||||
}
|
||||
. = ALIGN(4096);
|
||||
_kernel_bss_end = .;
|
||||
_kernel_end = .;
|
||||
_bss_size = _kernel_end - _kernel_rodata_end;
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.comment*)
|
||||
*(.note*)
|
||||
}
|
||||
}
|
40
Kernel/arch/aarch64/memory/vmm.cpp
Normal file
40
Kernel/arch/aarch64/memory/vmm.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
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 <memory.hpp>
|
||||
|
||||
#include <convert.h>
|
||||
#include <debug.h>
|
||||
|
||||
namespace Memory
|
||||
{
|
||||
bool Virtual::Check(void *VirtualAddress, PTFlag Flag, MapType Type)
|
||||
{
|
||||
}
|
||||
|
||||
void *Virtual::GetPhysical(void *VirtualAddress)
|
||||
{
|
||||
}
|
||||
|
||||
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type)
|
||||
{
|
||||
}
|
||||
|
||||
void Virtual::Unmap(void *VirtualAddress, MapType Type)
|
||||
{
|
||||
}
|
||||
}
|
31
Kernel/arch/aarch64/syscalls.cpp
Normal file
31
Kernel/arch/aarch64/syscalls.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
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 <syscalls.hpp>
|
||||
|
||||
#include <cpu.hpp>
|
||||
|
||||
extern "C" __naked __used __no_stack_protector void SystemCallHandlerStub()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
extern "C" uint64_t SystemCallsHandler(SyscallsFrame *regs);
|
||||
|
||||
void InitializeSystemCalls()
|
||||
{
|
||||
}
|
38
Kernel/arch/amd64/bootstrap/_start.s
Normal file
38
Kernel/arch/amd64/bootstrap/_start.s
Normal 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
|
317
Kernel/arch/amd64/bootstrap/limine/limine.c
Normal file
317
Kernel/arch/amd64/bootstrap/limine/limine.c
Normal 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");
|
||||
}
|
||||
|
||||
nsa 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);
|
||||
}
|
81
Kernel/arch/amd64/bootstrap/multiboot/Helper/detect.s
Normal file
81
Kernel/arch/amd64/bootstrap/multiboot/Helper/detect.s
Normal 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
|
64
Kernel/arch/amd64/bootstrap/multiboot/Helper/gdt32.s
Normal file
64
Kernel/arch/amd64/bootstrap/multiboot/Helper/gdt32.s
Normal 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
|
62
Kernel/arch/amd64/bootstrap/multiboot/Helper/gdt64.s
Normal file
62
Kernel/arch/amd64/bootstrap/multiboot/Helper/gdt64.s
Normal 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
|
301
Kernel/arch/amd64/bootstrap/multiboot/Paging/mb_64bit_map.cpp
Normal file
301
Kernel/arch/amd64/bootstrap/multiboot/Paging/mb_64bit_map.cpp
Normal 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 nsa NIF void SetAddress(uintptr_t _Address)
|
||||
{
|
||||
_Address &= 0x000000FFFFFFFFFF;
|
||||
this->raw &= 0xFFF0000000000FFF;
|
||||
this->raw |= (_Address << 12);
|
||||
}
|
||||
|
||||
__always_inline inline nsa 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 nsa NIF void SetAddress(uintptr_t _Address)
|
||||
{
|
||||
_Address &= 0x000000FFFFFFFFFF;
|
||||
this->raw &= 0xFFF0000000000FFF;
|
||||
this->raw |= (_Address << 12);
|
||||
}
|
||||
|
||||
__always_inline inline nsa 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 nsa NIF void SetAddress(uintptr_t _Address)
|
||||
{
|
||||
_Address &= 0x000000FFFFFFFFFF;
|
||||
this->raw &= 0xFFF0000000000FFF;
|
||||
this->raw |= (_Address << 12);
|
||||
}
|
||||
|
||||
__always_inline inline nsa 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 nsa NIF void SetAddress(uintptr_t _Address)
|
||||
{
|
||||
_Address &= 0x000000FFFFFFFFFF;
|
||||
this->raw &= 0xFFF0000000000FFF;
|
||||
this->raw |= (_Address << 12);
|
||||
}
|
||||
|
||||
__always_inline inline nsa 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 nsa 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 nsa 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"))) nsa 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"))) nsa 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");
|
||||
}
|
62
Kernel/arch/amd64/bootstrap/multiboot/Paging/mb_pt.s
Normal file
62
Kernel/arch/amd64/bootstrap/multiboot/Paging/mb_pt.s
Normal 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
|
38
Kernel/arch/amd64/bootstrap/multiboot/headers/header1.s
Normal file
38
Kernel/arch/amd64/bootstrap/multiboot/headers/header1.s
Normal 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
|
92
Kernel/arch/amd64/bootstrap/multiboot/headers/header2.s
Normal file
92
Kernel/arch/amd64/bootstrap/multiboot/headers/header2.s
Normal 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
|
210
Kernel/arch/amd64/bootstrap/multiboot/mb1_parse.cpp
Normal file
210
Kernel/arch/amd64/bootstrap/multiboot/mb1_parse.cpp
Normal 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);
|
||||
}
|
284
Kernel/arch/amd64/bootstrap/multiboot/mb2_parse.cpp
Normal file
284
Kernel/arch/amd64/bootstrap/multiboot/mb2_parse.cpp
Normal 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);
|
||||
}
|
53
Kernel/arch/amd64/bootstrap/multiboot/multiboot.cpp
Normal file
53
Kernel/arch/amd64/bootstrap/multiboot/multiboot.cpp
Normal 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();
|
||||
}
|
||||
}
|
124
Kernel/arch/amd64/bootstrap/multiboot/start.s
Normal file
124
Kernel/arch/amd64/bootstrap/multiboot/start.s
Normal 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
|
487
Kernel/arch/amd64/cpu/apic.cpp
Normal file
487
Kernel/arch/amd64/cpu/apic.cpp
Normal file
@ -0,0 +1,487 @@
|
||||
/*
|
||||
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 "apic.hpp"
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <acpi.hpp>
|
||||
#include <uart.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <smp.hpp>
|
||||
#include <io.h>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
NewLock(APICLock);
|
||||
|
||||
using namespace CPU::x64;
|
||||
using namespace CPU::x86;
|
||||
|
||||
/*
|
||||
In constructor 'APIC::APIC::APIC(int)':
|
||||
warning: left shift count >= width of type
|
||||
| APICBaseAddress = BaseStruct.ApicBaseLo << 12u | BaseStruct.ApicBaseHi << 32u;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~^~~~~~
|
||||
*/
|
||||
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
|
||||
|
||||
namespace APIC
|
||||
{
|
||||
// headache
|
||||
// https://www.amd.com/system/files/TechDocs/24593.pdf
|
||||
// https://www.naic.edu/~phil/software/intel/318148.pdf
|
||||
|
||||
uint32_t APIC::Read(uint32_t Register)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (Register != APIC_ICRLO &&
|
||||
Register != APIC_ICRHI &&
|
||||
Register != APIC_ID)
|
||||
debug("APIC::Read(%#lx) [x2=%d]",
|
||||
Register, x2APICSupported ? 1 : 0);
|
||||
#endif
|
||||
if (unlikely(x2APICSupported))
|
||||
assert(!"x2APIC is not supported");
|
||||
|
||||
CPU::MemBar::Barrier();
|
||||
uint32_t ret = *((volatile uint32_t *)((uintptr_t)APICBaseAddress + Register));
|
||||
CPU::MemBar::Barrier();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void APIC::Write(uint32_t Register, uint32_t Value)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (Register != APIC_EOI &&
|
||||
Register != APIC_TDCR &&
|
||||
Register != APIC_TIMER &&
|
||||
Register != APIC_TICR &&
|
||||
Register != APIC_ICRLO &&
|
||||
Register != APIC_ICRHI)
|
||||
debug("APIC::Write(%#lx, %#lx) [x2=%d]",
|
||||
Register, Value, x2APICSupported ? 1 : 0);
|
||||
#endif
|
||||
if (unlikely(x2APICSupported))
|
||||
assert(!"x2APIC is not supported");
|
||||
|
||||
CPU::MemBar::Barrier();
|
||||
*((volatile uint32_t *)(((uintptr_t)APICBaseAddress) + Register)) = Value;
|
||||
CPU::MemBar::Barrier();
|
||||
}
|
||||
|
||||
void APIC::IOWrite(uint64_t Base, uint32_t Register, uint32_t Value)
|
||||
{
|
||||
debug("APIC::IOWrite(%#lx, %#lx, %#lx)", Base, Register, Value);
|
||||
CPU::MemBar::Barrier();
|
||||
*((volatile uint32_t *)(((uintptr_t)Base))) = Register;
|
||||
CPU::MemBar::Barrier();
|
||||
*((volatile uint32_t *)(((uintptr_t)Base + 16))) = Value;
|
||||
CPU::MemBar::Barrier();
|
||||
}
|
||||
|
||||
uint32_t APIC::IORead(uint64_t Base, uint32_t Register)
|
||||
{
|
||||
debug("APIC::IORead(%#lx, %#lx)", Base, Register);
|
||||
CPU::MemBar::Barrier();
|
||||
*((volatile uint32_t *)(((uintptr_t)Base))) = Register;
|
||||
CPU::MemBar::Barrier();
|
||||
uint32_t ret = *((volatile uint32_t *)(((uintptr_t)Base + 16)));
|
||||
CPU::MemBar::Barrier();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void APIC::EOI()
|
||||
{
|
||||
Memory::SwapPT swap =
|
||||
Memory::SwapPT(KernelPageTable, thisPageTable);
|
||||
if (this->x2APICSupported)
|
||||
wrmsr(MSR_X2APIC_EOI, 0);
|
||||
else
|
||||
this->Write(APIC_EOI, 0);
|
||||
}
|
||||
|
||||
void APIC::WaitForIPI()
|
||||
{
|
||||
if (this->x2APICSupported)
|
||||
{
|
||||
ErrorStatusRegister esr{};
|
||||
esr.raw = uint32_t(rdmsr(MSR_X2APIC_ESR));
|
||||
UNUSED(esr);
|
||||
/* FIXME: Not sure if this is required or
|
||||
how to implement it. */
|
||||
}
|
||||
else
|
||||
{
|
||||
InterruptCommandRegister icr{};
|
||||
do
|
||||
{
|
||||
icr.split.Low = this->Read(APIC_ICRLO);
|
||||
CPU::Pause();
|
||||
} while (icr.DS != Idle);
|
||||
}
|
||||
}
|
||||
|
||||
void APIC::ICR(InterruptCommandRegister icr)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
if (x2APICSupported)
|
||||
{
|
||||
assert(icr.MT != LowestPriority);
|
||||
assert(icr.MT != DeliveryMode);
|
||||
assert(icr.MT != ExtINT);
|
||||
wrmsr(MSR_X2APIC_ICR, icr.raw);
|
||||
this->WaitForIPI();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Write(APIC_ICRHI, icr.split.High);
|
||||
this->Write(APIC_ICRLO, icr.split.Low);
|
||||
this->WaitForIPI();
|
||||
}
|
||||
}
|
||||
|
||||
void APIC::SendInitIPI(int CPU)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
InterruptCommandRegister icr{};
|
||||
|
||||
if (x2APICSupported)
|
||||
{
|
||||
icr.x2.MT = INIT;
|
||||
icr.x2.L = Assert;
|
||||
icr.x2.DES = uint8_t(CPU);
|
||||
|
||||
wrmsr(MSR_X2APIC_ICR, icr.raw);
|
||||
this->WaitForIPI();
|
||||
}
|
||||
else
|
||||
{
|
||||
icr.MT = INIT;
|
||||
icr.L = Assert;
|
||||
icr.DES = uint8_t(CPU);
|
||||
|
||||
this->Write(APIC_ICRHI, icr.split.High);
|
||||
this->Write(APIC_ICRLO, icr.split.Low);
|
||||
this->WaitForIPI();
|
||||
}
|
||||
}
|
||||
|
||||
void APIC::SendStartupIPI(int CPU, uint64_t StartupAddress)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
InterruptCommandRegister icr{};
|
||||
|
||||
if (x2APICSupported)
|
||||
{
|
||||
icr.x2.VEC = s_cst(uint8_t, StartupAddress >> 12);
|
||||
icr.x2.MT = Startup;
|
||||
icr.x2.L = Assert;
|
||||
icr.x2.DES = uint8_t(CPU);
|
||||
|
||||
wrmsr(MSR_X2APIC_ICR, icr.raw);
|
||||
this->WaitForIPI();
|
||||
}
|
||||
else
|
||||
{
|
||||
icr.VEC = s_cst(uint8_t, StartupAddress >> 12);
|
||||
icr.MT = Startup;
|
||||
icr.L = Assert;
|
||||
icr.DES = uint8_t(CPU);
|
||||
|
||||
this->Write(APIC_ICRHI, icr.split.High);
|
||||
this->Write(APIC_ICRLO, icr.split.Low);
|
||||
this->WaitForIPI();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t APIC::IOGetMaxRedirect(uint32_t APICID)
|
||||
{
|
||||
ACPI::MADT::MADTIOApic *ioapic = ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[APICID];
|
||||
uint32_t TableAddress = (this->IORead(ioapic->Address, GetIOAPICVersion));
|
||||
IOAPICVersion ver = {.raw = TableAddress};
|
||||
return ver.MLE + 1;
|
||||
}
|
||||
|
||||
void APIC::RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, uint8_t CPU, int Status)
|
||||
{
|
||||
int64_t IOAPICTarget = -1;
|
||||
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
|
||||
for (size_t i = 0; i < madt->ioapic.size(); i++)
|
||||
{
|
||||
if (madt->ioapic[i]->GSIBase <= GSI)
|
||||
{
|
||||
if (madt->ioapic[i]->GSIBase + IOGetMaxRedirect(uint32_t(i)) > GSI)
|
||||
{
|
||||
IOAPICTarget = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (IOAPICTarget == -1)
|
||||
{
|
||||
error("No ISO table found for I/O APIC");
|
||||
return;
|
||||
}
|
||||
|
||||
IOAPICRedirectEntry Entry{};
|
||||
Entry.VEC = Vector;
|
||||
Entry.DES = CPU;
|
||||
|
||||
if (Flags & ActiveHighLow)
|
||||
Entry.IPP = 1;
|
||||
|
||||
if (Flags & EdgeLevel)
|
||||
Entry.TGM = 1;
|
||||
|
||||
if (!Status)
|
||||
Entry.M = 1;
|
||||
|
||||
uint32_t IORegister = (GSI - madt->ioapic[IOAPICTarget]->GSIBase) * 2 + 16;
|
||||
this->IOWrite(madt->ioapic[IOAPICTarget]->Address,
|
||||
IORegister, Entry.split.Low);
|
||||
this->IOWrite(madt->ioapic[IOAPICTarget]->Address,
|
||||
IORegister + 1, Entry.split.High);
|
||||
}
|
||||
|
||||
void APIC::RedirectIRQ(uint8_t CPU, uint8_t IRQ, int Status)
|
||||
{
|
||||
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
|
||||
for (uint64_t i = 0; i < madt->iso.size(); i++)
|
||||
if (madt->iso[i]->IRQSource == IRQ)
|
||||
{
|
||||
debug("[ISO %d] Mapping to source IRQ%#d GSI:%#lx on CPU %d",
|
||||
i, madt->iso[i]->IRQSource, madt->iso[i]->GSI, CPU);
|
||||
|
||||
this->RawRedirectIRQ(madt->iso[i]->IRQSource + 0x20,
|
||||
madt->iso[i]->GSI,
|
||||
madt->iso[i]->Flags,
|
||||
CPU, Status);
|
||||
return;
|
||||
}
|
||||
debug("Mapping IRQ%d on CPU %d", IRQ, CPU);
|
||||
this->RawRedirectIRQ(IRQ + 0x20, IRQ, 0, CPU, Status);
|
||||
}
|
||||
|
||||
void APIC::RedirectIRQs(uint8_t CPU)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
debug("Redirecting IRQs...");
|
||||
for (uint8_t i = 0; i < 16; i++)
|
||||
this->RedirectIRQ(CPU, i, 1);
|
||||
debug("Redirecting IRQs completed.");
|
||||
}
|
||||
|
||||
APIC::APIC(int Core)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
APIC_BASE BaseStruct = {.raw = rdmsr(MSR_APIC_BASE)};
|
||||
uint64_t BaseLow = BaseStruct.ABALow;
|
||||
uint64_t BaseHigh = BaseStruct.ABAHigh;
|
||||
this->APICBaseAddress = BaseLow << 12u | BaseHigh << 32u;
|
||||
trace("APIC Address: %#lx", this->APICBaseAddress);
|
||||
Memory::Virtual().Map((void *)this->APICBaseAddress,
|
||||
(void *)this->APICBaseAddress,
|
||||
Memory::RW | Memory::PCD);
|
||||
|
||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||
{
|
||||
CPU::x86::AMD::CPUID0x00000001 cpuid;
|
||||
if (cpuid.ECX.x2APIC)
|
||||
{
|
||||
this->x2APICSupported = cpuid.ECX.x2APIC;
|
||||
debug("x2APIC is supported");
|
||||
}
|
||||
}
|
||||
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
||||
{
|
||||
CPU::x86::Intel::CPUID0x00000001 cpuid;
|
||||
if (cpuid.ECX.x2APIC)
|
||||
{
|
||||
this->x2APICSupported = cpuid.ECX.x2APIC;
|
||||
debug("x2APIC is supported");
|
||||
}
|
||||
}
|
||||
|
||||
BaseStruct.AE = 1;
|
||||
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
||||
|
||||
if (this->x2APICSupported)
|
||||
{
|
||||
BaseStruct.EXTD = 1;
|
||||
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
||||
}
|
||||
|
||||
if (!this->x2APICSupported)
|
||||
{
|
||||
this->Write(APIC_TPR, 0x0);
|
||||
this->Write(APIC_DFR, 0xF0000000);
|
||||
this->Write(APIC_LDR, this->Read(APIC_ID));
|
||||
}
|
||||
else
|
||||
{
|
||||
wrmsr(MSR_X2APIC_TPR, 0x0);
|
||||
}
|
||||
|
||||
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
|
||||
|
||||
for (size_t i = 0; i < madt->nmi.size(); i++)
|
||||
{
|
||||
if (madt->nmi[i]->processor != 0xFF &&
|
||||
Core != madt->nmi[i]->processor)
|
||||
break;
|
||||
|
||||
uint32_t nmi = 0x402;
|
||||
if (madt->nmi[i]->flags & 2)
|
||||
nmi |= 1 << 13;
|
||||
if (madt->nmi[i]->flags & 8)
|
||||
nmi |= 1 << 15;
|
||||
if (madt->nmi[i]->lint == 0)
|
||||
{
|
||||
if (this->x2APICSupported)
|
||||
wrmsr(MSR_X2APIC_LVT_LINT0, nmi);
|
||||
else
|
||||
this->Write(APIC_LINT0, nmi);
|
||||
}
|
||||
else if (madt->nmi[i]->lint == 1)
|
||||
{
|
||||
if (this->x2APICSupported)
|
||||
wrmsr(MSR_X2APIC_LVT_LINT1, nmi);
|
||||
else
|
||||
this->Write(APIC_LINT1, nmi);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup the spurious interrupt vector */
|
||||
Spurious svr{};
|
||||
if (this->x2APICSupported)
|
||||
svr.raw = uint32_t(rdmsr(MSR_X2APIC_SIVR));
|
||||
else
|
||||
svr.raw = this->Read(APIC_SVR);
|
||||
|
||||
svr.VEC = IRQ223;
|
||||
svr.ASE = 1;
|
||||
if (this->x2APICSupported)
|
||||
wrmsr(MSR_X2APIC_SIVR, svr.raw);
|
||||
else
|
||||
this->Write(APIC_SVR, svr.raw);
|
||||
|
||||
static int once = 0;
|
||||
if (!once++)
|
||||
{
|
||||
// Disable PIT
|
||||
outb(0x43, 0x28);
|
||||
outb(0x40, 0x0);
|
||||
|
||||
// Disable PIC
|
||||
outb(0x21, 0xFF);
|
||||
outb(0xA1, 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
APIC::~APIC() {}
|
||||
|
||||
void Timer::OnInterruptReceived(CPU::TrapFrame *) {}
|
||||
|
||||
void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds)
|
||||
{
|
||||
/* FIXME: Sometimes APIC stops firing when debugging, why? */
|
||||
LVTTimer timer{};
|
||||
timer.VEC = uint8_t(Vector);
|
||||
timer.TMM = LVTTimerMode::OneShot;
|
||||
|
||||
LVTTimerDivide Divider = DivideBy8;
|
||||
|
||||
SmartCriticalSection(APICLock);
|
||||
if (this->lapic->x2APIC)
|
||||
{
|
||||
// wrmsr(MSR_X2APIC_DIV_CONF, Divider); <- gpf on real hardware
|
||||
wrmsr(MSR_X2APIC_INIT_COUNT, uint32_t(Ticks * Miliseconds));
|
||||
wrmsr(MSR_X2APIC_LVT_TIMER, uint32_t(timer.raw));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, uint32_t(Ticks * Miliseconds));
|
||||
this->lapic->Write(APIC_TIMER, uint32_t(timer.raw));
|
||||
}
|
||||
}
|
||||
|
||||
Timer::Timer(APIC *apic) : Interrupts::Handler(0) /* IRQ0 */
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
this->lapic = apic;
|
||||
LVTTimerDivide Divider = DivideBy8;
|
||||
|
||||
trace("Initializing APIC timer on CPU %d",
|
||||
GetCurrentCPU()->ID);
|
||||
|
||||
if (this->lapic->x2APIC)
|
||||
{
|
||||
wrmsr(MSR_X2APIC_DIV_CONF, Divider);
|
||||
wrmsr(MSR_X2APIC_INIT_COUNT, 0xFFFFFFFF);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
TimeManager->Sleep(1, Time::Units::Milliseconds);
|
||||
|
||||
// Mask the timer
|
||||
if (this->lapic->x2APIC)
|
||||
{
|
||||
wrmsr(MSR_X2APIC_LVT_TIMER, 0x10000 /* LVTTimer.Mask flag */);
|
||||
Ticks = 0xFFFFFFFF - rdmsr(MSR_X2APIC_CUR_COUNT);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);
|
||||
Ticks = 0xFFFFFFFF - this->lapic->Read(APIC_TCCR);
|
||||
}
|
||||
|
||||
// Config for IRQ0 timer
|
||||
LVTTimer timer{};
|
||||
timer.VEC = IRQ0;
|
||||
timer.M = Unmasked;
|
||||
timer.TMM = LVTTimerMode::OneShot;
|
||||
|
||||
// Initialize APIC timer
|
||||
if (this->lapic->x2APIC)
|
||||
{
|
||||
wrmsr(MSR_X2APIC_DIV_CONF, Divider);
|
||||
wrmsr(MSR_X2APIC_INIT_COUNT, Ticks);
|
||||
wrmsr(MSR_X2APIC_LVT_TIMER, timer.raw);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, uint32_t(Ticks));
|
||||
this->lapic->Write(APIC_TIMER, uint32_t(timer.raw));
|
||||
}
|
||||
|
||||
trace("%d APIC Timer %d ticks in.",
|
||||
GetCurrentCPU()->ID, Ticks);
|
||||
KPrint("APIC Timer: \x1b[1;32m%ld\x1b[0m ticks.", Ticks);
|
||||
}
|
||||
|
||||
Timer::~Timer()
|
||||
{
|
||||
}
|
||||
}
|
386
Kernel/arch/amd64/cpu/apic.hpp
Normal file
386
Kernel/arch/amd64/cpu/apic.hpp
Normal file
@ -0,0 +1,386 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_KERNEL_APIC_H__
|
||||
#define __FENNIX_KERNEL_APIC_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <cpu.hpp>
|
||||
|
||||
namespace APIC
|
||||
{
|
||||
enum APICRegisters
|
||||
{
|
||||
/* APIC ID Register */
|
||||
APIC_ID = 0x20,
|
||||
/* APIC Version Register */
|
||||
APIC_VER = 0x30,
|
||||
/* Task Priority Register (TPR) */
|
||||
APIC_TPR = 0x80,
|
||||
/* Arbitration Priority Register (APR) */
|
||||
APIC_APR = 0x90,
|
||||
/* Processor Priority Register (PPR) */
|
||||
APIC_PPR = 0xA0,
|
||||
/* End of Interrupt Register (EOI) */
|
||||
APIC_EOI = 0xB0,
|
||||
/* Remote Read Register */
|
||||
APIC_RRD = 0xC0,
|
||||
/* Logical Destination Register (LDR) */
|
||||
APIC_LDR = 0xD0,
|
||||
/* Destination Format Register (DFR) */
|
||||
APIC_DFR = 0xE0,
|
||||
/* Spurious Interrupt Vector Register */
|
||||
APIC_SVR = 0xF0,
|
||||
/* In-Service Register (ISR) */
|
||||
APIC_ISR = 0x100,
|
||||
/* Trigger Mode Register (TMR) */
|
||||
APIC_TMR = 0x180,
|
||||
/* Interrupt Request Register (IRR) */
|
||||
APIC_IRR = 0x200,
|
||||
/* Error Status Register (ESR) */
|
||||
APIC_ESR = 0x280,
|
||||
/* Interrupt Command Register Low (bits 31:0) */
|
||||
APIC_ICRLO = 0x300,
|
||||
/* Interrupt Command Register High (bits 63:32) */
|
||||
APIC_ICRHI = 0x310,
|
||||
/* Timer Local Vector Table Entry */
|
||||
APIC_TIMER = 0x320,
|
||||
/* Thermal Local Vector Table Entry */
|
||||
APIC_THERMAL = 0x330,
|
||||
/* Performance Counter Local Vector Table Entry */
|
||||
APIC_PERF = 0x340,
|
||||
/* Local Interrupt 0 Vector Table Entry */
|
||||
APIC_LINT0 = 0x350,
|
||||
/* Local Interrupt 1 Vector Table Entry */
|
||||
APIC_LINT1 = 0x360,
|
||||
/* Error Vector Table Entry */
|
||||
APIC_ERROR = 0x370,
|
||||
/* Timer Initial Count Register */
|
||||
APIC_TICR = 0x380,
|
||||
/* Timer Current Count Register */
|
||||
APIC_TCCR = 0x390,
|
||||
/* Timer Divide Configuration Register */
|
||||
APIC_TDCR = 0x3E0,
|
||||
/* Extended APIC Feature Register */
|
||||
APIC_EFR = 0x400,
|
||||
/* Extended APIC Control Register */
|
||||
APIC_ECR = 0x410,
|
||||
/* Specific End of Interrupt Register (SEOI) */
|
||||
APIC_SEOI = 0x420,
|
||||
/* Interrupt Enable Registers (IER) */
|
||||
APIC_IER0 = 0x480,
|
||||
/* Extended Interrupt [3:0] Local Vector Table Registers */
|
||||
APIC_EILVT0 = 0x500,
|
||||
};
|
||||
|
||||
enum IOAPICRegisters
|
||||
{
|
||||
GetIOAPICVersion = 0x1
|
||||
};
|
||||
|
||||
enum IOAPICFlags
|
||||
{
|
||||
ActiveHighLow = 2,
|
||||
EdgeLevel = 8
|
||||
};
|
||||
|
||||
enum APICMessageType
|
||||
{
|
||||
Fixed = 0b000,
|
||||
LowestPriority = 0b001, /* Reserved */
|
||||
SMI = 0b010,
|
||||
DeliveryMode = 0b011, /* Reserved */
|
||||
NMI = 0b100,
|
||||
INIT = 0b101,
|
||||
Startup = 0b110,
|
||||
ExtINT = 0b111 /* Reserved */
|
||||
};
|
||||
|
||||
enum APICDestinationMode
|
||||
{
|
||||
Physical = 0b0,
|
||||
Logical = 0b1
|
||||
};
|
||||
|
||||
enum APICDeliveryStatus
|
||||
{
|
||||
Idle = 0b0,
|
||||
SendPending = 0b1
|
||||
};
|
||||
|
||||
enum APICLevel
|
||||
{
|
||||
DeAssert = 0b0,
|
||||
Assert = 0b1
|
||||
};
|
||||
|
||||
enum APICTriggerMode
|
||||
{
|
||||
Edge = 0b0,
|
||||
Level = 0b1
|
||||
};
|
||||
|
||||
enum APICDestinationShorthand
|
||||
{
|
||||
NoShorthand = 0b00,
|
||||
Self = 0b01,
|
||||
AllIncludingSelf = 0b10,
|
||||
AllExcludingSelf = 0b11
|
||||
};
|
||||
|
||||
enum LVTTimerDivide
|
||||
{
|
||||
DivideBy2 = 0b000,
|
||||
DivideBy4 = 0b001,
|
||||
DivideBy8 = 0b010,
|
||||
DivideBy16 = 0b011,
|
||||
DivideBy32 = 0b100,
|
||||
DivideBy64 = 0b101,
|
||||
DivideBy128 = 0b110,
|
||||
DivideBy1 = 0b111
|
||||
};
|
||||
|
||||
enum LVTTimerMask
|
||||
{
|
||||
Unmasked = 0b0,
|
||||
Masked = 0b1
|
||||
};
|
||||
|
||||
enum LVTTimerMode
|
||||
{
|
||||
OneShot = 0b00,
|
||||
Periodic = 0b01,
|
||||
TSCDeadline = 0b10
|
||||
};
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Vector */
|
||||
uint64_t VEC : 8;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 4;
|
||||
/** Delivery Status */
|
||||
uint64_t DS : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved1 : 3;
|
||||
/** Mask */
|
||||
uint64_t M : 1;
|
||||
/** Timer Mode */
|
||||
uint64_t TMM : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved2 : 14;
|
||||
};
|
||||
uint32_t raw;
|
||||
} __packed LVTTimer;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Vector */
|
||||
uint64_t VEC : 8;
|
||||
/** APIC Software Enable */
|
||||
uint64_t ASE : 1;
|
||||
/** Focus CPU Core Checking */
|
||||
uint64_t FCC : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 22;
|
||||
};
|
||||
uint32_t raw;
|
||||
} __packed Spurious;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Vector */
|
||||
uint64_t VEC : 8;
|
||||
/** Message Type */
|
||||
uint64_t MT : 3;
|
||||
/** Destination Mode */
|
||||
uint64_t DM : 1;
|
||||
/** Delivery Status */
|
||||
uint64_t DS : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 1;
|
||||
/** Level */
|
||||
uint64_t L : 1;
|
||||
/** Trigger Mode */
|
||||
uint64_t TGM : 1;
|
||||
/** Remote Read Status */
|
||||
uint64_t RSS : 2;
|
||||
/** Destination Shorthand */
|
||||
uint64_t DSH : 2;
|
||||
/** Reserved */
|
||||
uint64_t Reserved2 : 36;
|
||||
/** Destination */
|
||||
uint64_t DES : 8;
|
||||
};
|
||||
struct
|
||||
{
|
||||
/** Vector */
|
||||
uint64_t VEC : 8;
|
||||
/** Message Type */
|
||||
uint64_t MT : 3;
|
||||
/** Destination Mode */
|
||||
uint64_t DM : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 2;
|
||||
/** Level */
|
||||
uint64_t L : 1;
|
||||
/** Trigger Mode */
|
||||
uint64_t TGM : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved1 : 2;
|
||||
/** Destination Shorthand */
|
||||
uint64_t DSH : 2;
|
||||
/** Reserved */
|
||||
uint64_t Reserved2 : 12;
|
||||
/** Destination */
|
||||
uint64_t DES : 32;
|
||||
} x2;
|
||||
struct
|
||||
{
|
||||
uint32_t Low;
|
||||
uint32_t High;
|
||||
} split;
|
||||
uint64_t raw;
|
||||
} __packed InterruptCommandRegister;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 2;
|
||||
/** Sent Accept Error */
|
||||
uint64_t SAE : 1;
|
||||
/** Receive Accept Error */
|
||||
uint64_t RAE : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved1 : 1;
|
||||
/** Sent Illegal Vector */
|
||||
uint64_t SIV : 1;
|
||||
/** Received Illegal Vector */
|
||||
uint64_t RIV : 1;
|
||||
/** Illegal Register Address */
|
||||
uint64_t IRA : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved2 : 24;
|
||||
};
|
||||
uint32_t raw;
|
||||
} ErrorStatusRegister;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Interrupt Vector */
|
||||
uint64_t VEC : 8;
|
||||
/** Delivery Mode */
|
||||
uint64_t MT : 3;
|
||||
/** Destination Mode */
|
||||
uint64_t DM : 1;
|
||||
/** Delivery Status */
|
||||
uint64_t DS : 1;
|
||||
/** Interrupt Input Pin Polarity */
|
||||
uint64_t IPP : 1;
|
||||
/** Remote IRR */
|
||||
uint64_t RIR : 1;
|
||||
/** Trigger Mode */
|
||||
uint64_t TGM : 1;
|
||||
/** Mask */
|
||||
uint64_t M : 1;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 15;
|
||||
/** Reserved */
|
||||
uint64_t Reserved1 : 24;
|
||||
/** Destination */
|
||||
uint64_t DES : 8;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint32_t Low;
|
||||
uint32_t High;
|
||||
} split;
|
||||
uint64_t raw;
|
||||
} __packed IOAPICRedirectEntry;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** Version */
|
||||
uint64_t VER : 8;
|
||||
/** Reserved */
|
||||
uint64_t Reserved0 : 8;
|
||||
/** Max LVT Entries */
|
||||
uint64_t MLE : 8;
|
||||
/** Reserved */
|
||||
uint64_t Reserved1 : 7;
|
||||
/** Extended APIC Register Space Present */
|
||||
uint64_t EAS : 1;
|
||||
};
|
||||
uint32_t raw;
|
||||
} __packed IOAPICVersion;
|
||||
|
||||
class APIC
|
||||
{
|
||||
private:
|
||||
bool x2APICSupported = false;
|
||||
uint64_t APICBaseAddress = 0;
|
||||
|
||||
public:
|
||||
decltype(x2APICSupported) &x2APIC = x2APICSupported;
|
||||
|
||||
uint32_t Read(uint32_t Register);
|
||||
void Write(uint32_t Register, uint32_t Value);
|
||||
void IOWrite(uint64_t Base, uint32_t Register, uint32_t Value);
|
||||
uint32_t IORead(uint64_t Base, uint32_t Register);
|
||||
void EOI();
|
||||
void RedirectIRQs(uint8_t CPU = 0);
|
||||
void WaitForIPI();
|
||||
void ICR(InterruptCommandRegister icr);
|
||||
void SendInitIPI(int CPU);
|
||||
void SendStartupIPI(int CPU, uint64_t StartupAddress);
|
||||
uint32_t IOGetMaxRedirect(uint32_t APICID);
|
||||
void RawRedirectIRQ(uint8_t Vector, uint32_t GSI, uint16_t Flags, uint8_t CPU, int Status);
|
||||
void RedirectIRQ(uint8_t CPU, uint8_t IRQ, int Status);
|
||||
APIC(int Core);
|
||||
~APIC();
|
||||
};
|
||||
|
||||
class Timer : public Interrupts::Handler
|
||||
{
|
||||
private:
|
||||
APIC *lapic;
|
||||
uint64_t Ticks = 0;
|
||||
void OnInterruptReceived(CPU::TrapFrame *Frame);
|
||||
|
||||
public:
|
||||
uint64_t GetTicks() { return Ticks; }
|
||||
void OneShot(uint32_t Vector, uint64_t Miliseconds);
|
||||
Timer(APIC *apic);
|
||||
~Timer();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_APIC_H__
|
215
Kernel/arch/amd64/cpu/gdt.cpp
Normal file
215
Kernel/arch/amd64/cpu/gdt.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
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 "gdt.hpp"
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <smp.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
namespace GlobalDescriptorTable
|
||||
{
|
||||
static GlobalDescriptorTableEntries GDTEntriesTemplate = {
|
||||
.Null = 0,
|
||||
.Code = {
|
||||
.SegmentLimitLow = 0xFFFF,
|
||||
.BaseAddressLow = 0x0,
|
||||
.BaseAddressHigh = 0x0,
|
||||
.Accessed = 0,
|
||||
.Readable = 1,
|
||||
.Conforming = 0,
|
||||
.Executable = 1,
|
||||
.Type = 1,
|
||||
.DescriptorPrivilegeLevel = 0,
|
||||
.Present = 1,
|
||||
.SegmentLimitHigh = 0xF,
|
||||
.Available = 0,
|
||||
.Long = 1,
|
||||
.Default = 0,
|
||||
.Granularity = 1,
|
||||
.BaseAddressHigher = 0x0,
|
||||
},
|
||||
|
||||
.Data = {
|
||||
.SegmentLimitLow = 0xFFFF,
|
||||
.BaseAddressLow = 0x0,
|
||||
.BaseAddressHigh = 0x0,
|
||||
.Accessed = 0,
|
||||
.Writable = 1,
|
||||
.ExpandDown = 0,
|
||||
.Executable = 0,
|
||||
.Type = 1,
|
||||
.DescriptorPrivilegeLevel = 0,
|
||||
.Present = 1,
|
||||
.SegmentLimitHigh = 0xF,
|
||||
.Available = 0,
|
||||
.Reserved = 0,
|
||||
.Default = 0,
|
||||
.Granularity = 1,
|
||||
.BaseAddressHigher = 0x0,
|
||||
},
|
||||
|
||||
.UserData = {
|
||||
.SegmentLimitLow = 0xFFFF,
|
||||
.BaseAddressLow = 0x0,
|
||||
.BaseAddressHigh = 0x0,
|
||||
.Accessed = 0,
|
||||
.Writable = 1,
|
||||
.ExpandDown = 1,
|
||||
.Executable = 0,
|
||||
.Type = 1,
|
||||
.DescriptorPrivilegeLevel = 3,
|
||||
.Present = 1,
|
||||
.SegmentLimitHigh = 0xF,
|
||||
.Available = 0,
|
||||
.Reserved = 0,
|
||||
.Default = 0,
|
||||
.Granularity = 1,
|
||||
.BaseAddressHigher = 0x0,
|
||||
},
|
||||
|
||||
.UserCode = {
|
||||
.SegmentLimitLow = 0xFFFF,
|
||||
.BaseAddressLow = 0x0,
|
||||
.BaseAddressHigh = 0x0,
|
||||
.Accessed = 0,
|
||||
.Readable = 1,
|
||||
.Conforming = 0,
|
||||
.Executable = 1,
|
||||
.Type = 1,
|
||||
.DescriptorPrivilegeLevel = 3,
|
||||
.Present = 1,
|
||||
.SegmentLimitHigh = 0xF,
|
||||
.Available = 0,
|
||||
.Long = 1,
|
||||
.Default = 0,
|
||||
.Granularity = 1,
|
||||
.BaseAddressHigher = 0x0,
|
||||
},
|
||||
|
||||
.TaskStateSegment{},
|
||||
};
|
||||
|
||||
GlobalDescriptorTableEntries GDTEntries[MAX_CPU] __aligned(16);
|
||||
GlobalDescriptorTableDescriptor gdt[MAX_CPU] __aligned(16);
|
||||
|
||||
TaskStateSegment tss[MAX_CPU] = {
|
||||
0,
|
||||
{0, 0, 0},
|
||||
0,
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
void *CPUStackPointer[MAX_CPU];
|
||||
|
||||
nsa void Init(int Core)
|
||||
{
|
||||
GDTEntries[Core] = GDTEntriesTemplate;
|
||||
gdt[Core] =
|
||||
{
|
||||
.Limit = sizeof(GlobalDescriptorTableEntries) - 1,
|
||||
.BaseAddress = &GDTEntries[Core],
|
||||
};
|
||||
|
||||
debug("GDT: %#lx", &gdt[Core]);
|
||||
debug("GDT KERNEL CODE %#lx", GDT_KERNEL_CODE);
|
||||
debug("GDT KERNEL DATA %#lx", GDT_KERNEL_DATA);
|
||||
debug("GDT USER CODE %#lx", GDT_USER_CODE);
|
||||
debug("GDT USER DATA %#lx", GDT_USER_DATA);
|
||||
debug("GDT TSS %#lx", GDT_TSS);
|
||||
|
||||
CPU::x64::lgdt(&gdt[Core]);
|
||||
|
||||
asmv("movq %%rsp, %%rax\n"
|
||||
"pushq $16\n"
|
||||
"pushq %%rax\n"
|
||||
"pushfq\n"
|
||||
"pushq $8\n"
|
||||
"pushq $1f\n"
|
||||
"iretq\n"
|
||||
"1:\n"
|
||||
"movw $16, %%ax\n"
|
||||
"movw %%ax, %%ds\n"
|
||||
"movw %%ax, %%es\n" ::
|
||||
: "memory", "rax");
|
||||
|
||||
CPUStackPointer[Core] = StackManager.Allocate(STACK_SIZE);
|
||||
memset(CPUStackPointer[Core], 0, STACK_SIZE);
|
||||
debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core,
|
||||
CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE,
|
||||
TO_PAGES(STACK_SIZE + 1));
|
||||
|
||||
uintptr_t Base = (uintptr_t)&tss[Core];
|
||||
size_t Limit = Base + sizeof(TaskStateSegment);
|
||||
SystemSegmentDescriptor *tssDesc = &gdt[Core].BaseAddress->TaskStateSegment;
|
||||
tssDesc->SegmentLimitLow = Limit & 0xFFFF;
|
||||
tssDesc->BaseAddressLow = Base & 0xFFFF;
|
||||
tssDesc->BaseAddressMiddle = (Base >> 16) & 0xFF;
|
||||
tssDesc->Type = AVAILABLE_64BIT_TSS;
|
||||
tssDesc->Zero0 = 0;
|
||||
tssDesc->DescriptorPrivilegeLevel = 0;
|
||||
tssDesc->Present = 1;
|
||||
tssDesc->Available = 0;
|
||||
tssDesc->Reserved0 = 0;
|
||||
tssDesc->Granularity = 0;
|
||||
tssDesc->BaseAddressHigh = (Base >> 24) & 0xFF;
|
||||
tssDesc->BaseAddressHigher = s_cst(uint32_t, (Base >> 32) & 0xFFFFFFFF);
|
||||
tssDesc->Reserved1 = 0;
|
||||
tssDesc->Zero1 = 0;
|
||||
tssDesc->Reserved2 = 0;
|
||||
|
||||
tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
|
||||
tss[Core].StackPointer[0] = (uint64_t)CPUStackPointer[Core] + STACK_SIZE;
|
||||
tss[Core].StackPointer[1] = 0x0;
|
||||
tss[Core].StackPointer[2] = 0x0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(tss[Core].InterruptStackTable) / sizeof(tss[Core].InterruptStackTable[7]); i++)
|
||||
{
|
||||
void *NewStack = StackManager.Allocate(STACK_SIZE);
|
||||
tss[Core].InterruptStackTable[i] = (uint64_t)NewStack + STACK_SIZE;
|
||||
memset((void *)(tss[Core].InterruptStackTable[i] - STACK_SIZE), 0, STACK_SIZE);
|
||||
debug("IST-%d: %#lx-%#lx", i, NewStack, (uintptr_t)NewStack + STACK_SIZE);
|
||||
}
|
||||
|
||||
CPU::x64::ltr(GDT_TSS);
|
||||
debug("Global Descriptor Table initialized");
|
||||
}
|
||||
|
||||
nsa void SetKernelStack(void *Stack)
|
||||
{
|
||||
long CPUID = GetCurrentCPU()->ID;
|
||||
if (Stack != nullptr)
|
||||
tss[CPUID].StackPointer[0] = (uint64_t)Stack;
|
||||
else
|
||||
tss[CPUID].StackPointer[0] = (uint64_t)CPUStackPointer[CPUID] + STACK_SIZE;
|
||||
|
||||
/*
|
||||
FIXME: There's a bug in kernel which if
|
||||
we won't update "tss[CPUID].StackPointer[0]"
|
||||
with the current stack pointer, the kernel
|
||||
will crash.
|
||||
*/
|
||||
asmv("mov %%rsp, %0"
|
||||
: "=r"(tss[CPUID].StackPointer[0]));
|
||||
}
|
||||
|
||||
void *GetKernelStack() { return (void *)tss[GetCurrentCPU()->ID].StackPointer[0]; }
|
||||
}
|
67
Kernel/arch/amd64/cpu/gdt.hpp
Normal file
67
Kernel/arch/amd64/cpu/gdt.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_KERNEL_GDT_H__
|
||||
#define __FENNIX_KERNEL_GDT_H__
|
||||
|
||||
#include <types.h>
|
||||
#include <cpu/x86/x64/SegmentDescriptors.hpp>
|
||||
|
||||
namespace GlobalDescriptorTable
|
||||
{
|
||||
|
||||
struct TaskStateSegment
|
||||
{
|
||||
uint32_t Reserved0 __aligned(16);
|
||||
uint64_t StackPointer[3];
|
||||
uint64_t Reserved1;
|
||||
uint64_t InterruptStackTable[7];
|
||||
uint64_t Reserved2;
|
||||
uint16_t Reserved3;
|
||||
uint16_t IOMapBaseAddressOffset;
|
||||
} __packed;
|
||||
|
||||
struct GlobalDescriptorTableEntries
|
||||
{
|
||||
uint64_t Null;
|
||||
CodeSegmentDescriptor Code;
|
||||
DataSegmentDescriptor Data;
|
||||
DataSegmentDescriptor UserData;
|
||||
CodeSegmentDescriptor UserCode;
|
||||
SystemSegmentDescriptor TaskStateSegment;
|
||||
} __packed;
|
||||
|
||||
struct GlobalDescriptorTableDescriptor
|
||||
{
|
||||
uint16_t Limit;
|
||||
GlobalDescriptorTableEntries *BaseAddress;
|
||||
} __packed;
|
||||
|
||||
extern void *CPUStackPointer[];
|
||||
extern TaskStateSegment tss[];
|
||||
void Init(int Core);
|
||||
void SetKernelStack(void *Stack);
|
||||
void *GetKernelStack();
|
||||
}
|
||||
|
||||
#define GDT_KERNEL_CODE offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Code)
|
||||
#define GDT_KERNEL_DATA offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Data)
|
||||
#define GDT_USER_CODE (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, UserCode) | 3)
|
||||
#define GDT_USER_DATA (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, UserData) | 3)
|
||||
#define GDT_TSS (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, TaskStateSegment) | 3)
|
||||
|
||||
#endif // !__FENNIX_KERNEL_GDT_H__
|
916
Kernel/arch/amd64/cpu/idt.cpp
Normal file
916
Kernel/arch/amd64/cpu/idt.cpp
Normal file
@ -0,0 +1,916 @@
|
||||
/*
|
||||
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 "idt.hpp"
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <debug.h>
|
||||
#include <io.h>
|
||||
|
||||
#include "gdt.hpp"
|
||||
#include "../../../kernel.h"
|
||||
|
||||
/* conversion from 'uint64_t' {aka 'long unsigned int'} to 'unsigned char:2' may change value */
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
|
||||
extern "C" void MainInterruptHandler(void *Data);
|
||||
extern "C" void SchedulerInterruptHandler(void *Data);
|
||||
extern "C" void ExceptionHandler(void *Data);
|
||||
|
||||
#define __stub_handler \
|
||||
__naked __used __no_stack_protector __aligned(16)
|
||||
|
||||
namespace InterruptDescriptorTable
|
||||
{
|
||||
__aligned(8) static IDTGateDescriptor Entries[0x100];
|
||||
|
||||
__aligned(8) IDTRegister IDTr = {
|
||||
.Limit = sizeof(Entries) - 1,
|
||||
.BaseAddress = Entries,
|
||||
};
|
||||
|
||||
void SetEntry(uint8_t Index, void (*Base)(),
|
||||
InterruptStackTableType InterruptStackTable,
|
||||
GateType Gate, PrivilegeLevelType Ring,
|
||||
bool Present, uint16_t SegmentSelector)
|
||||
{
|
||||
switch (Gate)
|
||||
{
|
||||
case CALL_GATE_64BIT:
|
||||
{
|
||||
CallGate gate{
|
||||
.TargetOffsetLow = s_cst(uint16_t, ((uint64_t)Base & 0xFFFF)),
|
||||
.TargetSelector = SegmentSelector,
|
||||
.Reserved0 = 0,
|
||||
.Type = Gate,
|
||||
.Zero0 = 0,
|
||||
.DescriptorPrivilegeLevel = Ring,
|
||||
.Present = Present,
|
||||
.TargetOffsetMiddle = s_cst(uint16_t, ((uint64_t)Base >> 16)),
|
||||
.TargetOffsetHigh = s_cst(uint32_t, ((uint64_t)Base >> 32)),
|
||||
.Reserved1 = 0,
|
||||
.Zero1 = 0,
|
||||
.Reserved2 = 0,
|
||||
};
|
||||
Entries[Index].Call = gate;
|
||||
break;
|
||||
}
|
||||
case INTERRUPT_GATE_64BIT:
|
||||
{
|
||||
InterruptGate gate{
|
||||
.TargetOffsetLow = s_cst(uint16_t, ((uint64_t)Base & 0xFFFF)),
|
||||
.TargetSelector = SegmentSelector,
|
||||
.InterruptStackTable = InterruptStackTable,
|
||||
.Reserved0 = 0,
|
||||
.Type = Gate,
|
||||
.Zero = 0,
|
||||
.DescriptorPrivilegeLevel = Ring,
|
||||
.Present = Present,
|
||||
.TargetOffsetMiddle = s_cst(uint16_t, ((uint64_t)Base >> 16)),
|
||||
.TargetOffsetHigh = s_cst(uint32_t, ((uint64_t)Base >> 32)),
|
||||
.Reserved1 = 0,
|
||||
};
|
||||
Entries[Index].Interrupt = gate;
|
||||
break;
|
||||
}
|
||||
case TRAP_GATE_64BIT:
|
||||
{
|
||||
TrapGate gate{
|
||||
.TargetOffsetLow = s_cst(uint16_t, ((uint64_t)Base & 0xFFFF)),
|
||||
.TargetSelector = SegmentSelector,
|
||||
.InterruptStackTable = InterruptStackTable,
|
||||
.Reserved0 = 0,
|
||||
.Type = Gate,
|
||||
.Zero = 0,
|
||||
.DescriptorPrivilegeLevel = Ring,
|
||||
.Present = Present,
|
||||
.TargetOffsetMiddle = s_cst(uint16_t, ((uint64_t)Base >> 16)),
|
||||
.TargetOffsetHigh = s_cst(uint32_t, ((uint64_t)Base >> 32)),
|
||||
.Reserved1 = 0,
|
||||
};
|
||||
Entries[Index].Trap = gate;
|
||||
break;
|
||||
}
|
||||
case LDT_64BIT:
|
||||
case AVAILABLE_64BIT_TSS:
|
||||
case BUSY_64BIT_TSS:
|
||||
default:
|
||||
{
|
||||
assert(!"Unsupported gate type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __stub_handler void ExceptionHandlerStub()
|
||||
{
|
||||
asm("cld\n"
|
||||
"cli\n"
|
||||
|
||||
"pushq %rax\n"
|
||||
"pushq %rbx\n"
|
||||
"pushq %rcx\n"
|
||||
"pushq %rdx\n"
|
||||
"pushq %rsi\n"
|
||||
"pushq %rdi\n"
|
||||
"pushq %rbp\n"
|
||||
|
||||
"pushq %r8\n"
|
||||
"pushq %r9\n"
|
||||
"pushq %r10\n"
|
||||
"pushq %r11\n"
|
||||
"pushq %r12\n"
|
||||
"pushq %r13\n"
|
||||
"pushq %r14\n"
|
||||
"pushq %r15\n"
|
||||
|
||||
"movq %ds, %rax\n pushq %rax\n"
|
||||
"movq %es, %rax\n pushq %rax\n"
|
||||
"movq %fs, %rax\n pushq %rax\n"
|
||||
"movq %gs, %rax\n pushq %rax\n"
|
||||
|
||||
"movq %dr7, %rax\n pushq %rax\n"
|
||||
"movq %dr6, %rax\n pushq %rax\n"
|
||||
"movq %dr3, %rax\n pushq %rax\n"
|
||||
"movq %dr2, %rax\n pushq %rax\n"
|
||||
"movq %dr1, %rax\n pushq %rax\n"
|
||||
"movq %dr0, %rax\n pushq %rax\n"
|
||||
|
||||
"movq %cr8, %rax\n pushq %rax\n"
|
||||
"movq %cr4, %rax\n pushq %rax\n"
|
||||
"movq %cr3, %rax\n pushq %rax\n"
|
||||
"movq %cr2, %rax\n pushq %rax\n"
|
||||
"movq %cr0, %rax\n pushq %rax\n"
|
||||
|
||||
"movq %rsp, %rdi\n"
|
||||
"call ExceptionHandler\n"
|
||||
|
||||
"popq %rax\n movq %rax, %cr0\n"
|
||||
"popq %rax\n movq %rax, %cr2\n"
|
||||
"popq %rax\n movq %rax, %cr3\n"
|
||||
"popq %rax\n movq %rax, %cr4\n"
|
||||
"popq %rax\n movq %rax, %cr8\n"
|
||||
|
||||
"popq %rax\n movq %rax, %dr0\n"
|
||||
"popq %rax\n movq %rax, %dr1\n"
|
||||
"popq %rax\n movq %rax, %dr2\n"
|
||||
"popq %rax\n movq %rax, %dr3\n"
|
||||
"popq %rax\n movq %rax, %dr6\n"
|
||||
"popq %rax\n movq %rax, %dr7\n"
|
||||
|
||||
"popq %rax\n movq %rax, %gs\n"
|
||||
"popq %rax\n movq %rax, %fs\n"
|
||||
"popq %rax\n movq %rax, %es\n"
|
||||
"popq %rax\n movq %rax, %ds\n"
|
||||
|
||||
"popq %r15\n"
|
||||
"popq %r14\n"
|
||||
"popq %r13\n"
|
||||
"popq %r12\n"
|
||||
"popq %r11\n"
|
||||
"popq %r10\n"
|
||||
"popq %r9\n"
|
||||
"popq %r8\n"
|
||||
|
||||
"popq %rbp\n"
|
||||
"popq %rdi\n"
|
||||
"popq %rsi\n"
|
||||
"popq %rdx\n"
|
||||
"popq %rcx\n"
|
||||
"popq %rbx\n"
|
||||
"popq %rax\n"
|
||||
|
||||
"addq $16, %rsp\n"
|
||||
|
||||
"iretq"); // pop CS RIP RFLAGS SS RSP
|
||||
}
|
||||
|
||||
extern "C" __stub_handler void InterruptHandlerStub()
|
||||
{
|
||||
asm("cld\n"
|
||||
"cli\n"
|
||||
|
||||
"pushq %rax\n"
|
||||
"pushq %rbx\n"
|
||||
"pushq %rcx\n"
|
||||
"pushq %rdx\n"
|
||||
"pushq %rsi\n"
|
||||
"pushq %rdi\n"
|
||||
"pushq %rbp\n"
|
||||
|
||||
"pushq %r8\n"
|
||||
"pushq %r9\n"
|
||||
"pushq %r10\n"
|
||||
"pushq %r11\n"
|
||||
"pushq %r12\n"
|
||||
"pushq %r13\n"
|
||||
"pushq %r14\n"
|
||||
"pushq %r15\n"
|
||||
|
||||
"movq %rsp, %rdi\n"
|
||||
"call MainInterruptHandler\n"
|
||||
|
||||
"popq %r15\n"
|
||||
"popq %r14\n"
|
||||
"popq %r13\n"
|
||||
"popq %r12\n"
|
||||
"popq %r11\n"
|
||||
"popq %r10\n"
|
||||
"popq %r9\n"
|
||||
"popq %r8\n"
|
||||
|
||||
"popq %rbp\n"
|
||||
"popq %rdi\n"
|
||||
"popq %rsi\n"
|
||||
"popq %rdx\n"
|
||||
"popq %rcx\n"
|
||||
"popq %rbx\n"
|
||||
"popq %rax\n"
|
||||
|
||||
"addq $16, %rsp\n"
|
||||
|
||||
"sti\n"
|
||||
"iretq"); // pop CS RIP RFLAGS SS RSP
|
||||
}
|
||||
|
||||
extern "C" __stub_handler void SchedulerHandlerStub()
|
||||
{
|
||||
asm("cld\n"
|
||||
"cli\n"
|
||||
|
||||
"pushq %rax\n"
|
||||
"pushq %rbx\n"
|
||||
"pushq %rcx\n"
|
||||
"pushq %rdx\n"
|
||||
"pushq %rsi\n"
|
||||
"pushq %rdi\n"
|
||||
"pushq %rbp\n"
|
||||
|
||||
"pushq %r8\n"
|
||||
"pushq %r9\n"
|
||||
"pushq %r10\n"
|
||||
"pushq %r11\n"
|
||||
"pushq %r12\n"
|
||||
"pushq %r13\n"
|
||||
"pushq %r14\n"
|
||||
"pushq %r15\n"
|
||||
|
||||
/* TODO: Add advanced check so we won't update the cr3 when not needed */
|
||||
|
||||
"movq %cr3, %rax\n pushq %rax\n" /* Push opt */
|
||||
"pushq %rax\n" /* Push ppt */
|
||||
|
||||
"movq %rsp, %rdi\n"
|
||||
"call SchedulerInterruptHandler\n"
|
||||
|
||||
"popq %rax\n movq %rax, %cr3\n" /* Restore to ppt */
|
||||
"popq %rax\n" /* Pop opt */
|
||||
|
||||
"popq %r15\n"
|
||||
"popq %r14\n"
|
||||
"popq %r13\n"
|
||||
"popq %r12\n"
|
||||
"popq %r11\n"
|
||||
"popq %r10\n"
|
||||
"popq %r9\n"
|
||||
"popq %r8\n"
|
||||
|
||||
"popq %rbp\n"
|
||||
"popq %rdi\n"
|
||||
"popq %rsi\n"
|
||||
"popq %rdx\n"
|
||||
"popq %rcx\n"
|
||||
"popq %rbx\n"
|
||||
"popq %rax\n"
|
||||
|
||||
"addq $16, %rsp\n"
|
||||
|
||||
"sti\n"
|
||||
"iretq"); // pop CS RIP RFLAGS SS RSP
|
||||
}
|
||||
|
||||
#pragma region Interrupt Macros
|
||||
|
||||
#define EXCEPTION_HANDLER(num) \
|
||||
__stub_handler static void InterruptHandler_##num() \
|
||||
{ \
|
||||
asm("pushq $0\n" \
|
||||
"pushq $" #num "\n" \
|
||||
"jmp ExceptionHandlerStub"); \
|
||||
}
|
||||
|
||||
#define EXCEPTION_ERROR_HANDLER(num) \
|
||||
__stub_handler static void InterruptHandler_##num() \
|
||||
{ \
|
||||
asm("pushq $" #num "\n" \
|
||||
"jmp ExceptionHandlerStub"); \
|
||||
}
|
||||
|
||||
#define INTERRUPT_HANDLER(num) \
|
||||
__stub_handler void InterruptHandler_##num() \
|
||||
{ \
|
||||
asm("pushq $0\n" \
|
||||
"pushq $" #num "\n" \
|
||||
"jmp InterruptHandlerStub\n"); \
|
||||
}
|
||||
|
||||
#define SCHEDULER_HANDLER(num) \
|
||||
__stub_handler void InterruptHandler_##num() \
|
||||
{ \
|
||||
asm("pushq $0\n" \
|
||||
"pushq $" #num "\n" \
|
||||
"jmp SchedulerHandlerStub\n"); \
|
||||
}
|
||||
|
||||
/* ISR */
|
||||
|
||||
EXCEPTION_HANDLER(0x0);
|
||||
EXCEPTION_HANDLER(0x1);
|
||||
EXCEPTION_HANDLER(0x2);
|
||||
EXCEPTION_HANDLER(0x3);
|
||||
EXCEPTION_HANDLER(0x4);
|
||||
EXCEPTION_HANDLER(0x5);
|
||||
EXCEPTION_HANDLER(0x6);
|
||||
EXCEPTION_HANDLER(0x7);
|
||||
EXCEPTION_ERROR_HANDLER(0x8);
|
||||
EXCEPTION_HANDLER(0x9);
|
||||
EXCEPTION_ERROR_HANDLER(0xa);
|
||||
EXCEPTION_ERROR_HANDLER(0xb);
|
||||
EXCEPTION_ERROR_HANDLER(0xc);
|
||||
EXCEPTION_ERROR_HANDLER(0xd);
|
||||
EXCEPTION_ERROR_HANDLER(0xe);
|
||||
EXCEPTION_HANDLER(0xf);
|
||||
EXCEPTION_ERROR_HANDLER(0x10);
|
||||
EXCEPTION_HANDLER(0x11);
|
||||
EXCEPTION_HANDLER(0x12);
|
||||
EXCEPTION_HANDLER(0x13);
|
||||
EXCEPTION_HANDLER(0x14);
|
||||
EXCEPTION_HANDLER(0x15);
|
||||
EXCEPTION_HANDLER(0x16);
|
||||
EXCEPTION_HANDLER(0x17);
|
||||
EXCEPTION_HANDLER(0x18);
|
||||
EXCEPTION_HANDLER(0x19);
|
||||
EXCEPTION_HANDLER(0x1a);
|
||||
EXCEPTION_HANDLER(0x1b);
|
||||
EXCEPTION_HANDLER(0x1c);
|
||||
EXCEPTION_HANDLER(0x1d);
|
||||
EXCEPTION_HANDLER(0x1e);
|
||||
EXCEPTION_HANDLER(0x1f);
|
||||
|
||||
/* IRQ */
|
||||
|
||||
INTERRUPT_HANDLER(0x20)
|
||||
INTERRUPT_HANDLER(0x21)
|
||||
INTERRUPT_HANDLER(0x22)
|
||||
INTERRUPT_HANDLER(0x23)
|
||||
INTERRUPT_HANDLER(0x24)
|
||||
INTERRUPT_HANDLER(0x25)
|
||||
INTERRUPT_HANDLER(0x26)
|
||||
INTERRUPT_HANDLER(0x27)
|
||||
INTERRUPT_HANDLER(0x28)
|
||||
INTERRUPT_HANDLER(0x29)
|
||||
INTERRUPT_HANDLER(0x2a)
|
||||
INTERRUPT_HANDLER(0x2b)
|
||||
INTERRUPT_HANDLER(0x2c)
|
||||
INTERRUPT_HANDLER(0x2d)
|
||||
INTERRUPT_HANDLER(0x2e)
|
||||
INTERRUPT_HANDLER(0x2f)
|
||||
|
||||
/* Reserved by OS */
|
||||
|
||||
SCHEDULER_HANDLER(0x30)
|
||||
INTERRUPT_HANDLER(0x31)
|
||||
INTERRUPT_HANDLER(0x32)
|
||||
INTERRUPT_HANDLER(0x33)
|
||||
INTERRUPT_HANDLER(0x34)
|
||||
INTERRUPT_HANDLER(0x35)
|
||||
INTERRUPT_HANDLER(0x36)
|
||||
INTERRUPT_HANDLER(0x37)
|
||||
INTERRUPT_HANDLER(0x38)
|
||||
INTERRUPT_HANDLER(0x39)
|
||||
INTERRUPT_HANDLER(0x3a)
|
||||
INTERRUPT_HANDLER(0x3b)
|
||||
INTERRUPT_HANDLER(0x3c)
|
||||
INTERRUPT_HANDLER(0x3d)
|
||||
|
||||
/* Free */
|
||||
|
||||
INTERRUPT_HANDLER(0x3e)
|
||||
INTERRUPT_HANDLER(0x3f)
|
||||
INTERRUPT_HANDLER(0x40)
|
||||
INTERRUPT_HANDLER(0x41)
|
||||
INTERRUPT_HANDLER(0x42)
|
||||
INTERRUPT_HANDLER(0x43)
|
||||
INTERRUPT_HANDLER(0x44)
|
||||
INTERRUPT_HANDLER(0x45)
|
||||
INTERRUPT_HANDLER(0x46)
|
||||
INTERRUPT_HANDLER(0x47)
|
||||
INTERRUPT_HANDLER(0x48)
|
||||
INTERRUPT_HANDLER(0x49)
|
||||
INTERRUPT_HANDLER(0x4a)
|
||||
INTERRUPT_HANDLER(0x4b)
|
||||
INTERRUPT_HANDLER(0x4c)
|
||||
INTERRUPT_HANDLER(0x4d)
|
||||
INTERRUPT_HANDLER(0x4e)
|
||||
INTERRUPT_HANDLER(0x4f)
|
||||
INTERRUPT_HANDLER(0x50)
|
||||
INTERRUPT_HANDLER(0x51)
|
||||
INTERRUPT_HANDLER(0x52)
|
||||
INTERRUPT_HANDLER(0x53)
|
||||
INTERRUPT_HANDLER(0x54)
|
||||
INTERRUPT_HANDLER(0x55)
|
||||
INTERRUPT_HANDLER(0x56)
|
||||
INTERRUPT_HANDLER(0x57)
|
||||
INTERRUPT_HANDLER(0x58)
|
||||
INTERRUPT_HANDLER(0x59)
|
||||
INTERRUPT_HANDLER(0x5a)
|
||||
INTERRUPT_HANDLER(0x5b)
|
||||
INTERRUPT_HANDLER(0x5c)
|
||||
INTERRUPT_HANDLER(0x5d)
|
||||
INTERRUPT_HANDLER(0x5e)
|
||||
INTERRUPT_HANDLER(0x5f)
|
||||
INTERRUPT_HANDLER(0x60)
|
||||
INTERRUPT_HANDLER(0x61)
|
||||
INTERRUPT_HANDLER(0x62)
|
||||
INTERRUPT_HANDLER(0x63)
|
||||
INTERRUPT_HANDLER(0x64)
|
||||
INTERRUPT_HANDLER(0x65)
|
||||
INTERRUPT_HANDLER(0x66)
|
||||
INTERRUPT_HANDLER(0x67)
|
||||
INTERRUPT_HANDLER(0x68)
|
||||
INTERRUPT_HANDLER(0x69)
|
||||
INTERRUPT_HANDLER(0x6a)
|
||||
INTERRUPT_HANDLER(0x6b)
|
||||
INTERRUPT_HANDLER(0x6c)
|
||||
INTERRUPT_HANDLER(0x6d)
|
||||
INTERRUPT_HANDLER(0x6e)
|
||||
INTERRUPT_HANDLER(0x6f)
|
||||
INTERRUPT_HANDLER(0x70)
|
||||
INTERRUPT_HANDLER(0x71)
|
||||
INTERRUPT_HANDLER(0x72)
|
||||
INTERRUPT_HANDLER(0x73)
|
||||
INTERRUPT_HANDLER(0x74)
|
||||
INTERRUPT_HANDLER(0x75)
|
||||
INTERRUPT_HANDLER(0x76)
|
||||
INTERRUPT_HANDLER(0x77)
|
||||
INTERRUPT_HANDLER(0x78)
|
||||
INTERRUPT_HANDLER(0x79)
|
||||
INTERRUPT_HANDLER(0x7a)
|
||||
INTERRUPT_HANDLER(0x7b)
|
||||
INTERRUPT_HANDLER(0x7c)
|
||||
INTERRUPT_HANDLER(0x7d)
|
||||
INTERRUPT_HANDLER(0x7e)
|
||||
INTERRUPT_HANDLER(0x7f)
|
||||
INTERRUPT_HANDLER(0x80)
|
||||
INTERRUPT_HANDLER(0x81)
|
||||
INTERRUPT_HANDLER(0x82)
|
||||
INTERRUPT_HANDLER(0x83)
|
||||
INTERRUPT_HANDLER(0x84)
|
||||
INTERRUPT_HANDLER(0x85)
|
||||
INTERRUPT_HANDLER(0x86)
|
||||
INTERRUPT_HANDLER(0x87)
|
||||
INTERRUPT_HANDLER(0x88)
|
||||
INTERRUPT_HANDLER(0x89)
|
||||
INTERRUPT_HANDLER(0x8a)
|
||||
INTERRUPT_HANDLER(0x8b)
|
||||
INTERRUPT_HANDLER(0x8c)
|
||||
INTERRUPT_HANDLER(0x8d)
|
||||
INTERRUPT_HANDLER(0x8e)
|
||||
INTERRUPT_HANDLER(0x8f)
|
||||
INTERRUPT_HANDLER(0x90)
|
||||
INTERRUPT_HANDLER(0x91)
|
||||
INTERRUPT_HANDLER(0x92)
|
||||
INTERRUPT_HANDLER(0x93)
|
||||
INTERRUPT_HANDLER(0x94)
|
||||
INTERRUPT_HANDLER(0x95)
|
||||
INTERRUPT_HANDLER(0x96)
|
||||
INTERRUPT_HANDLER(0x97)
|
||||
INTERRUPT_HANDLER(0x98)
|
||||
INTERRUPT_HANDLER(0x99)
|
||||
INTERRUPT_HANDLER(0x9a)
|
||||
INTERRUPT_HANDLER(0x9b)
|
||||
INTERRUPT_HANDLER(0x9c)
|
||||
INTERRUPT_HANDLER(0x9d)
|
||||
INTERRUPT_HANDLER(0x9e)
|
||||
INTERRUPT_HANDLER(0x9f)
|
||||
INTERRUPT_HANDLER(0xa0)
|
||||
INTERRUPT_HANDLER(0xa1)
|
||||
INTERRUPT_HANDLER(0xa2)
|
||||
INTERRUPT_HANDLER(0xa3)
|
||||
INTERRUPT_HANDLER(0xa4)
|
||||
INTERRUPT_HANDLER(0xa5)
|
||||
INTERRUPT_HANDLER(0xa6)
|
||||
INTERRUPT_HANDLER(0xa7)
|
||||
INTERRUPT_HANDLER(0xa8)
|
||||
INTERRUPT_HANDLER(0xa9)
|
||||
INTERRUPT_HANDLER(0xaa)
|
||||
INTERRUPT_HANDLER(0xab)
|
||||
INTERRUPT_HANDLER(0xac)
|
||||
INTERRUPT_HANDLER(0xad)
|
||||
INTERRUPT_HANDLER(0xae)
|
||||
INTERRUPT_HANDLER(0xaf)
|
||||
INTERRUPT_HANDLER(0xb0)
|
||||
INTERRUPT_HANDLER(0xb1)
|
||||
INTERRUPT_HANDLER(0xb2)
|
||||
INTERRUPT_HANDLER(0xb3)
|
||||
INTERRUPT_HANDLER(0xb4)
|
||||
INTERRUPT_HANDLER(0xb5)
|
||||
INTERRUPT_HANDLER(0xb6)
|
||||
INTERRUPT_HANDLER(0xb7)
|
||||
INTERRUPT_HANDLER(0xb8)
|
||||
INTERRUPT_HANDLER(0xb9)
|
||||
INTERRUPT_HANDLER(0xba)
|
||||
INTERRUPT_HANDLER(0xbb)
|
||||
INTERRUPT_HANDLER(0xbc)
|
||||
INTERRUPT_HANDLER(0xbd)
|
||||
INTERRUPT_HANDLER(0xbe)
|
||||
INTERRUPT_HANDLER(0xbf)
|
||||
INTERRUPT_HANDLER(0xc0)
|
||||
INTERRUPT_HANDLER(0xc1)
|
||||
INTERRUPT_HANDLER(0xc2)
|
||||
INTERRUPT_HANDLER(0xc3)
|
||||
INTERRUPT_HANDLER(0xc4)
|
||||
INTERRUPT_HANDLER(0xc5)
|
||||
INTERRUPT_HANDLER(0xc6)
|
||||
INTERRUPT_HANDLER(0xc7)
|
||||
INTERRUPT_HANDLER(0xc8)
|
||||
INTERRUPT_HANDLER(0xc9)
|
||||
INTERRUPT_HANDLER(0xca)
|
||||
INTERRUPT_HANDLER(0xcb)
|
||||
INTERRUPT_HANDLER(0xcc)
|
||||
INTERRUPT_HANDLER(0xcd)
|
||||
INTERRUPT_HANDLER(0xce)
|
||||
INTERRUPT_HANDLER(0xcf)
|
||||
INTERRUPT_HANDLER(0xd0)
|
||||
INTERRUPT_HANDLER(0xd1)
|
||||
INTERRUPT_HANDLER(0xd2)
|
||||
INTERRUPT_HANDLER(0xd3)
|
||||
INTERRUPT_HANDLER(0xd4)
|
||||
INTERRUPT_HANDLER(0xd5)
|
||||
INTERRUPT_HANDLER(0xd6)
|
||||
INTERRUPT_HANDLER(0xd7)
|
||||
INTERRUPT_HANDLER(0xd8)
|
||||
INTERRUPT_HANDLER(0xd9)
|
||||
INTERRUPT_HANDLER(0xda)
|
||||
INTERRUPT_HANDLER(0xdb)
|
||||
INTERRUPT_HANDLER(0xdc)
|
||||
INTERRUPT_HANDLER(0xdd)
|
||||
INTERRUPT_HANDLER(0xde)
|
||||
INTERRUPT_HANDLER(0xdf)
|
||||
INTERRUPT_HANDLER(0xe0)
|
||||
INTERRUPT_HANDLER(0xe1)
|
||||
INTERRUPT_HANDLER(0xe2)
|
||||
INTERRUPT_HANDLER(0xe3)
|
||||
INTERRUPT_HANDLER(0xe4)
|
||||
INTERRUPT_HANDLER(0xe5)
|
||||
INTERRUPT_HANDLER(0xe6)
|
||||
INTERRUPT_HANDLER(0xe7)
|
||||
INTERRUPT_HANDLER(0xe8)
|
||||
INTERRUPT_HANDLER(0xe9)
|
||||
INTERRUPT_HANDLER(0xea)
|
||||
INTERRUPT_HANDLER(0xeb)
|
||||
INTERRUPT_HANDLER(0xec)
|
||||
INTERRUPT_HANDLER(0xed)
|
||||
INTERRUPT_HANDLER(0xee)
|
||||
INTERRUPT_HANDLER(0xef)
|
||||
INTERRUPT_HANDLER(0xf0)
|
||||
INTERRUPT_HANDLER(0xf1)
|
||||
INTERRUPT_HANDLER(0xf2)
|
||||
INTERRUPT_HANDLER(0xf3)
|
||||
INTERRUPT_HANDLER(0xf4)
|
||||
INTERRUPT_HANDLER(0xf5)
|
||||
INTERRUPT_HANDLER(0xf6)
|
||||
INTERRUPT_HANDLER(0xf7)
|
||||
INTERRUPT_HANDLER(0xf8)
|
||||
INTERRUPT_HANDLER(0xf9)
|
||||
INTERRUPT_HANDLER(0xfa)
|
||||
INTERRUPT_HANDLER(0xfb)
|
||||
INTERRUPT_HANDLER(0xfc)
|
||||
INTERRUPT_HANDLER(0xfd)
|
||||
INTERRUPT_HANDLER(0xfe)
|
||||
INTERRUPT_HANDLER(0xff)
|
||||
|
||||
#pragma endregion Interrupt Macros
|
||||
|
||||
void Init(int Core)
|
||||
{
|
||||
if (Core == 0) /* Disable PIC using BSP */
|
||||
{
|
||||
// PIC
|
||||
outb(0x20, 0x10 | 0x1);
|
||||
outb(0x80, 0);
|
||||
outb(0xA0, 0x10 | 0x10);
|
||||
outb(0x80, 0);
|
||||
|
||||
outb(0x21, 0x20);
|
||||
outb(0x80, 0);
|
||||
outb(0xA1, 0x28);
|
||||
outb(0x80, 0);
|
||||
|
||||
outb(0x21, 0x04);
|
||||
outb(0x80, 0);
|
||||
outb(0xA1, 0x02);
|
||||
outb(0x80, 0);
|
||||
|
||||
outb(0x21, 1);
|
||||
outb(0x80, 0);
|
||||
outb(0xA1, 1);
|
||||
outb(0x80, 0);
|
||||
|
||||
// Masking and disabling PIC
|
||||
outb(0x21, 0xff);
|
||||
outb(0x80, 0);
|
||||
outb(0xA1, 0xff);
|
||||
}
|
||||
|
||||
bool EnableISRs = true;
|
||||
#ifdef DEBUG
|
||||
EnableISRs = !DebuggerIsAttached;
|
||||
if (!EnableISRs)
|
||||
KPrint("\x1b[34mThe debugger is attached, disabling all ISRs.");
|
||||
#endif
|
||||
|
||||
/* ISR */
|
||||
SetEntry(0x0, InterruptHandler_0x0, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1, InterruptHandler_0x1, IST1, INTERRUPT_GATE_64BIT, RING3, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2, InterruptHandler_0x2, IST2, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3, InterruptHandler_0x3, IST1, INTERRUPT_GATE_64BIT, RING3, (!DebuggerIsAttached), GDT_KERNEL_CODE); /* Do not handle breakpoints if we are debugging the kernel. */
|
||||
SetEntry(0x4, InterruptHandler_0x4, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5, InterruptHandler_0x5, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6, InterruptHandler_0x6, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7, InterruptHandler_0x7, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8, InterruptHandler_0x8, IST3, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9, InterruptHandler_0x9, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa, InterruptHandler_0xa, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb, InterruptHandler_0xb, IST1, INTERRUPT_GATE_64BIT, RING0, (!DebuggerIsAttached), GDT_KERNEL_CODE);
|
||||
SetEntry(0xc, InterruptHandler_0xc, IST3, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd, InterruptHandler_0xd, IST3, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe, InterruptHandler_0xe, IST3, INTERRUPT_GATE_64BIT, RING0, EnableISRs /* FIXME: CoW? */, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf, InterruptHandler_0xf, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x10, InterruptHandler_0x10, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x11, InterruptHandler_0x11, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x12, InterruptHandler_0x12, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x13, InterruptHandler_0x13, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x14, InterruptHandler_0x14, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x15, InterruptHandler_0x15, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x16, InterruptHandler_0x16, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x17, InterruptHandler_0x17, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x18, InterruptHandler_0x18, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x19, InterruptHandler_0x19, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1a, InterruptHandler_0x1a, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1b, InterruptHandler_0x1b, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1c, InterruptHandler_0x1c, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1d, InterruptHandler_0x1d, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1e, InterruptHandler_0x1e, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1f, InterruptHandler_0x1f, IST1, INTERRUPT_GATE_64BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
|
||||
/* IRQ */
|
||||
|
||||
SetEntry(0x20, InterruptHandler_0x20, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x21, InterruptHandler_0x21, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x22, InterruptHandler_0x22, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x23, InterruptHandler_0x23, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x24, InterruptHandler_0x24, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x25, InterruptHandler_0x25, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x26, InterruptHandler_0x26, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x27, InterruptHandler_0x27, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x28, InterruptHandler_0x28, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x29, InterruptHandler_0x29, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2a, InterruptHandler_0x2a, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2b, InterruptHandler_0x2b, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2c, InterruptHandler_0x2c, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2d, InterruptHandler_0x2d, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2e, InterruptHandler_0x2e, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2f, InterruptHandler_0x2f, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
|
||||
/* Reserved by OS */
|
||||
|
||||
SetEntry(0x30, InterruptHandler_0x30, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x31, InterruptHandler_0x31, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x32, InterruptHandler_0x32, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x33, InterruptHandler_0x33, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x34, InterruptHandler_0x34, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x35, InterruptHandler_0x35, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x36, InterruptHandler_0x36, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x37, InterruptHandler_0x37, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x38, InterruptHandler_0x38, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x39, InterruptHandler_0x39, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3a, InterruptHandler_0x3a, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3b, InterruptHandler_0x3b, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3c, InterruptHandler_0x3c, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3d, InterruptHandler_0x3d, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
|
||||
/* Free */
|
||||
|
||||
SetEntry(0x3e, InterruptHandler_0x3e, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3f, InterruptHandler_0x3f, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x40, InterruptHandler_0x40, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x41, InterruptHandler_0x41, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x42, InterruptHandler_0x42, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x43, InterruptHandler_0x43, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x44, InterruptHandler_0x44, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x45, InterruptHandler_0x45, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x46, InterruptHandler_0x46, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x47, InterruptHandler_0x47, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x48, InterruptHandler_0x48, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x49, InterruptHandler_0x49, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4a, InterruptHandler_0x4a, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4b, InterruptHandler_0x4b, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4c, InterruptHandler_0x4c, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4d, InterruptHandler_0x4d, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4e, InterruptHandler_0x4e, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4f, InterruptHandler_0x4f, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x50, InterruptHandler_0x50, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x51, InterruptHandler_0x51, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x52, InterruptHandler_0x52, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x53, InterruptHandler_0x53, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x54, InterruptHandler_0x54, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x55, InterruptHandler_0x55, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x56, InterruptHandler_0x56, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x57, InterruptHandler_0x57, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x58, InterruptHandler_0x58, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x59, InterruptHandler_0x59, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5a, InterruptHandler_0x5a, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5b, InterruptHandler_0x5b, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5c, InterruptHandler_0x5c, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5d, InterruptHandler_0x5d, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5e, InterruptHandler_0x5e, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5f, InterruptHandler_0x5f, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x60, InterruptHandler_0x60, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x61, InterruptHandler_0x61, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x62, InterruptHandler_0x62, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x63, InterruptHandler_0x63, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x64, InterruptHandler_0x64, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x65, InterruptHandler_0x65, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x66, InterruptHandler_0x66, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x67, InterruptHandler_0x67, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x68, InterruptHandler_0x68, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x69, InterruptHandler_0x69, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6a, InterruptHandler_0x6a, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6b, InterruptHandler_0x6b, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6c, InterruptHandler_0x6c, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6d, InterruptHandler_0x6d, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6e, InterruptHandler_0x6e, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6f, InterruptHandler_0x6f, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x70, InterruptHandler_0x70, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x71, InterruptHandler_0x71, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x72, InterruptHandler_0x72, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x73, InterruptHandler_0x73, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x74, InterruptHandler_0x74, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x75, InterruptHandler_0x75, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x76, InterruptHandler_0x76, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x77, InterruptHandler_0x77, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x78, InterruptHandler_0x78, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x79, InterruptHandler_0x79, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7a, InterruptHandler_0x7a, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7b, InterruptHandler_0x7b, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7c, InterruptHandler_0x7c, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7d, InterruptHandler_0x7d, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7e, InterruptHandler_0x7e, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7f, InterruptHandler_0x7f, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x80, InterruptHandler_0x80, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x81, InterruptHandler_0x81, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x82, InterruptHandler_0x82, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x83, InterruptHandler_0x83, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x84, InterruptHandler_0x84, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x85, InterruptHandler_0x85, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x86, InterruptHandler_0x86, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x87, InterruptHandler_0x87, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x88, InterruptHandler_0x88, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x89, InterruptHandler_0x89, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8a, InterruptHandler_0x8a, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8b, InterruptHandler_0x8b, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8c, InterruptHandler_0x8c, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8d, InterruptHandler_0x8d, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8e, InterruptHandler_0x8e, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8f, InterruptHandler_0x8f, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x90, InterruptHandler_0x90, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x91, InterruptHandler_0x91, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x92, InterruptHandler_0x92, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x93, InterruptHandler_0x93, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x94, InterruptHandler_0x94, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x95, InterruptHandler_0x95, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x96, InterruptHandler_0x96, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x97, InterruptHandler_0x97, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x98, InterruptHandler_0x98, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x99, InterruptHandler_0x99, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9a, InterruptHandler_0x9a, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9b, InterruptHandler_0x9b, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9c, InterruptHandler_0x9c, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9d, InterruptHandler_0x9d, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9e, InterruptHandler_0x9e, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9f, InterruptHandler_0x9f, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa0, InterruptHandler_0xa0, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa1, InterruptHandler_0xa1, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa2, InterruptHandler_0xa2, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa3, InterruptHandler_0xa3, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa4, InterruptHandler_0xa4, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa5, InterruptHandler_0xa5, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa6, InterruptHandler_0xa6, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa7, InterruptHandler_0xa7, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa8, InterruptHandler_0xa8, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa9, InterruptHandler_0xa9, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xaa, InterruptHandler_0xaa, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xab, InterruptHandler_0xab, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xac, InterruptHandler_0xac, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xad, InterruptHandler_0xad, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xae, InterruptHandler_0xae, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xaf, InterruptHandler_0xaf, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb0, InterruptHandler_0xb0, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb1, InterruptHandler_0xb1, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb2, InterruptHandler_0xb2, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb3, InterruptHandler_0xb3, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb4, InterruptHandler_0xb4, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb5, InterruptHandler_0xb5, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb6, InterruptHandler_0xb6, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb7, InterruptHandler_0xb7, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb8, InterruptHandler_0xb8, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb9, InterruptHandler_0xb9, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xba, InterruptHandler_0xba, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbb, InterruptHandler_0xbb, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbc, InterruptHandler_0xbc, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbd, InterruptHandler_0xbd, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbe, InterruptHandler_0xbe, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbf, InterruptHandler_0xbf, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc0, InterruptHandler_0xc0, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc1, InterruptHandler_0xc1, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc2, InterruptHandler_0xc2, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc3, InterruptHandler_0xc3, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc4, InterruptHandler_0xc4, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc5, InterruptHandler_0xc5, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc6, InterruptHandler_0xc6, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc7, InterruptHandler_0xc7, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc8, InterruptHandler_0xc8, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc9, InterruptHandler_0xc9, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xca, InterruptHandler_0xca, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xcb, InterruptHandler_0xcb, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xcc, InterruptHandler_0xcc, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xcd, InterruptHandler_0xcd, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xce, InterruptHandler_0xce, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xcf, InterruptHandler_0xcf, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd0, InterruptHandler_0xd0, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd1, InterruptHandler_0xd1, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd2, InterruptHandler_0xd2, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd3, InterruptHandler_0xd3, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd4, InterruptHandler_0xd4, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd5, InterruptHandler_0xd5, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd6, InterruptHandler_0xd6, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd7, InterruptHandler_0xd7, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd8, InterruptHandler_0xd8, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd9, InterruptHandler_0xd9, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xda, InterruptHandler_0xda, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xdb, InterruptHandler_0xdb, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xdc, InterruptHandler_0xdc, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xdd, InterruptHandler_0xdd, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xde, InterruptHandler_0xde, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xdf, InterruptHandler_0xdf, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe0, InterruptHandler_0xe0, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe1, InterruptHandler_0xe1, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe2, InterruptHandler_0xe2, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe3, InterruptHandler_0xe3, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe4, InterruptHandler_0xe4, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe5, InterruptHandler_0xe5, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe6, InterruptHandler_0xe6, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe7, InterruptHandler_0xe7, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe8, InterruptHandler_0xe8, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe9, InterruptHandler_0xe9, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xea, InterruptHandler_0xea, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xeb, InterruptHandler_0xeb, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xec, InterruptHandler_0xec, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xed, InterruptHandler_0xed, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xee, InterruptHandler_0xee, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xef, InterruptHandler_0xef, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf0, InterruptHandler_0xf0, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf1, InterruptHandler_0xf1, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf2, InterruptHandler_0xf2, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf3, InterruptHandler_0xf3, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf4, InterruptHandler_0xf4, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf5, InterruptHandler_0xf5, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf6, InterruptHandler_0xf6, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf7, InterruptHandler_0xf7, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf8, InterruptHandler_0xf8, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf9, InterruptHandler_0xf9, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfa, InterruptHandler_0xfa, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfb, InterruptHandler_0xfb, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfc, InterruptHandler_0xfc, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfd, InterruptHandler_0xfd, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfe, InterruptHandler_0xfe, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xff, InterruptHandler_0xff, IST0, INTERRUPT_GATE_64BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
CPU::x64::lidt(&IDTr);
|
||||
}
|
||||
}
|
51
Kernel/arch/amd64/cpu/idt.hpp
Normal file
51
Kernel/arch/amd64/cpu/idt.hpp
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_KERNEL_IDT_H__
|
||||
#define __FENNIX_KERNEL_IDT_H__
|
||||
|
||||
#include <types.h>
|
||||
#include <cpu/x86/x64/SegmentDescriptors.hpp>
|
||||
|
||||
namespace InterruptDescriptorTable
|
||||
{
|
||||
|
||||
union IDTGateDescriptor
|
||||
{
|
||||
InterruptGate Interrupt;
|
||||
TrapGate Trap;
|
||||
CallGate Call;
|
||||
};
|
||||
|
||||
struct IDTRegister
|
||||
{
|
||||
uint16_t Limit;
|
||||
IDTGateDescriptor *BaseAddress;
|
||||
} __packed;
|
||||
|
||||
void SetEntry(uint8_t Index,
|
||||
void (*Base)(),
|
||||
InterruptStackTableType InterruptStackTable,
|
||||
GateType Gate,
|
||||
PrivilegeLevelType Ring,
|
||||
bool Present,
|
||||
uint16_t SegmentSelector);
|
||||
|
||||
void Init(int Core);
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_IDT_H__
|
198
Kernel/arch/amd64/cpu/smp.cpp
Normal file
198
Kernel/arch/amd64/cpu/smp.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
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 <smp.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <acpi.hpp>
|
||||
#include <ints.hpp>
|
||||
#include <assert.h>
|
||||
#include <cpu.hpp>
|
||||
#include <atomic>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
#include "apic.hpp"
|
||||
|
||||
extern "C" uint64_t _trampoline_start, _trampoline_end;
|
||||
|
||||
/* https://wiki.osdev.org/Memory_Map_(x86) */
|
||||
enum SMPTrampolineAddress
|
||||
{
|
||||
PAGE_TABLE = 0x500,
|
||||
START_ADDR = 0x520,
|
||||
STACK = 0x570,
|
||||
GDT = 0x580,
|
||||
IDT = 0x590,
|
||||
CORE = 0x600,
|
||||
TRAMPOLINE_START = 0x2000
|
||||
};
|
||||
|
||||
std::atomic_bool CPUEnabled = false;
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
static __aligned(PAGE_SIZE) CPUData CPUs[MAX_CPU] = {0};
|
||||
|
||||
nsa CPUData *GetCPU(long id) { return &CPUs[id]; }
|
||||
|
||||
nsa CPUData *GetCurrentCPU()
|
||||
{
|
||||
if (unlikely(!Interrupts::apic[0]))
|
||||
return &CPUs[0]; /* No APIC means we are on the BSP. */
|
||||
|
||||
APIC::APIC *apic = (APIC::APIC *)Interrupts::apic[0];
|
||||
int CoreID = 0;
|
||||
if (CPUEnabled.load(std::memory_order_acquire) == true)
|
||||
{
|
||||
Memory::SwapPT swap =
|
||||
Memory::SwapPT(KernelPageTable, thisPageTable);
|
||||
|
||||
if (apic->x2APIC)
|
||||
CoreID = int(CPU::x64::rdmsr(CPU::x64::MSR_X2APIC_APICID));
|
||||
else
|
||||
CoreID = apic->Read(APIC::APIC_ID) >> 24;
|
||||
}
|
||||
|
||||
if (unlikely((&CPUs[CoreID])->IsActive != true))
|
||||
{
|
||||
error("CPU %d is not active!", CoreID);
|
||||
assert((&CPUs[0])->IsActive == true); /* We can't continue without the BSP. */
|
||||
return &CPUs[0];
|
||||
}
|
||||
|
||||
assert((&CPUs[CoreID])->Checksum == CPU_DATA_CHECKSUM); /* This should never happen. */
|
||||
return &CPUs[CoreID];
|
||||
}
|
||||
|
||||
extern "C" void StartCPU()
|
||||
{
|
||||
CPU::Interrupts(CPU::Disable);
|
||||
int CoreID = (int)*reinterpret_cast<int *>(CORE);
|
||||
CPU::InitializeFeatures(CoreID);
|
||||
// Initialize GDT and IDT
|
||||
Interrupts::Initialize(CoreID);
|
||||
Interrupts::Enable(CoreID);
|
||||
Interrupts::InitializeTimer(CoreID);
|
||||
asmv("mov %0, %%rsp" ::"r"((&CPUs[CoreID])->Stack));
|
||||
|
||||
CPU::Interrupts(CPU::Enable);
|
||||
KPrint("CPU %d is online", CoreID);
|
||||
CPUEnabled.store(true, std::memory_order_release);
|
||||
CPU::Halt(true);
|
||||
}
|
||||
|
||||
namespace SMP
|
||||
{
|
||||
int CPUCores = 0;
|
||||
|
||||
void Initialize(void *_madt)
|
||||
{
|
||||
if (!_madt)
|
||||
{
|
||||
error("MADT is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
ACPI::MADT *madt = (ACPI::MADT *)_madt;
|
||||
|
||||
if (madt->lapic.size() < 1)
|
||||
{
|
||||
error("No CPUs found!");
|
||||
return;
|
||||
}
|
||||
|
||||
int Cores = madt->CPUCores + 1;
|
||||
|
||||
if (Config.Cores > madt->CPUCores + 1)
|
||||
KPrint("More cores requested than available. Using %d cores",
|
||||
madt->CPUCores + 1);
|
||||
else if (Config.Cores != 0)
|
||||
Cores = Config.Cores;
|
||||
|
||||
CPUCores = Cores;
|
||||
|
||||
uint64_t TrampolineLength = (uintptr_t)&_trampoline_end -
|
||||
(uintptr_t)&_trampoline_start;
|
||||
Memory::Virtual().Map(0x0, 0x0, Memory::PTFlag::RW);
|
||||
/* We reserved the TRAMPOLINE_START address inside Physical class. */
|
||||
Memory::Virtual().Map((void *)TRAMPOLINE_START,
|
||||
(void *)TRAMPOLINE_START,
|
||||
TrampolineLength, Memory::PTFlag::RW);
|
||||
memcpy((void *)TRAMPOLINE_START, &_trampoline_start, TrampolineLength);
|
||||
debug("Trampoline address: %#lx-%#lx",
|
||||
TRAMPOLINE_START,
|
||||
TRAMPOLINE_START + TrampolineLength);
|
||||
|
||||
void *CPUTmpStack = KernelAllocator.RequestPages(TO_PAGES(STACK_SIZE + 1));
|
||||
asmv("sgdt [0x580]");
|
||||
asmv("sidt [0x590]");
|
||||
VPOKE(uintptr_t, STACK) = (uintptr_t)CPUTmpStack + STACK_SIZE;
|
||||
VPOKE(uintptr_t, PAGE_TABLE) = (uintptr_t)KernelPageTable;
|
||||
VPOKE(uintptr_t, START_ADDR) = (uintptr_t)&StartCPU;
|
||||
|
||||
for (int i = 0; i < Cores; i++)
|
||||
{
|
||||
ACPI::MADT::LocalAPIC *lapic = madt->lapic[i];
|
||||
APIC::APIC *apic = (APIC::APIC *)Interrupts::apic[0];
|
||||
|
||||
debug("Initializing CPU %d", lapic->APICId);
|
||||
uint8_t APIC_ID = 0;
|
||||
if (apic->x2APIC)
|
||||
APIC_ID = uint8_t(CPU::x64::rdmsr(CPU::x64::MSR_X2APIC_APICID));
|
||||
else
|
||||
APIC_ID = uint8_t(apic->Read(APIC::APIC_ID) >> 24);
|
||||
|
||||
if (APIC_ID != lapic->APICId)
|
||||
{
|
||||
VPOKE(int, CORE) = i;
|
||||
if (!apic->x2APIC)
|
||||
{
|
||||
APIC::InterruptCommandRegister icr{};
|
||||
icr.MT = APIC::INIT;
|
||||
icr.DES = lapic->APICId;
|
||||
apic->ICR(icr);
|
||||
}
|
||||
|
||||
apic->SendInitIPI(lapic->APICId);
|
||||
TimeManager->Sleep(20, Time::Units::Milliseconds);
|
||||
apic->SendStartupIPI(lapic->APICId, TRAMPOLINE_START);
|
||||
debug("Waiting for CPU %d to load...", lapic->APICId);
|
||||
|
||||
uint64_t Timeout = TimeManager->CalculateTarget(2, Time::Units::Seconds);
|
||||
while (CPUEnabled.load(std::memory_order_acquire) == false)
|
||||
{
|
||||
if (TimeManager->GetCounter() > Timeout)
|
||||
{
|
||||
error("CPU %d failed to load!", lapic->APICId);
|
||||
KPrint("\x1b[1;37;41mCPU %d failed to load!",
|
||||
lapic->APICId);
|
||||
break;
|
||||
}
|
||||
CPU::Pause();
|
||||
}
|
||||
trace("CPU %d loaded.", lapic->APICId);
|
||||
CPUEnabled.store(false, std::memory_order_release);
|
||||
}
|
||||
else
|
||||
KPrint("CPU %d is the BSP", lapic->APICId);
|
||||
}
|
||||
|
||||
KernelAllocator.FreePages(CPUTmpStack, TO_PAGES(STACK_SIZE + 1));
|
||||
/* We are going to unmap the page after we are done with it. */
|
||||
Memory::Virtual().Unmap(0x0);
|
||||
CPUEnabled.store(true, std::memory_order_release);
|
||||
}
|
||||
}
|
179
Kernel/arch/amd64/cpu/smp_trampoline.s
Normal file
179
Kernel/arch/amd64/cpu/smp_trampoline.s
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
/* This has to be the same as enum SMPTrampolineAddress. */
|
||||
TRAMPOLINE_PAGE_TABLE = 0x500
|
||||
TRAMPOLINE_START_ADDR = 0x520
|
||||
TRAMPOLINE_STACK = 0x570
|
||||
TRAMPOLINE_GDT = 0x580
|
||||
TRAMPOLINE_IDT = 0x590
|
||||
TRAMPOLINE_CORE = 0x600
|
||||
TRAMPOLINE_START = 0x2000
|
||||
|
||||
.section .rodata
|
||||
|
||||
/* ========== 16-bit ========== */
|
||||
|
||||
.code16
|
||||
.global _trampoline_start
|
||||
_trampoline_start:
|
||||
cli
|
||||
cld
|
||||
call Trampoline16
|
||||
|
||||
Trampoline16:
|
||||
mov $0x0, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
mov %ax, %ss
|
||||
|
||||
/* Load Protected Mode GDT */
|
||||
lgdt [ProtectedMode_gdtr - _trampoline_start + TRAMPOLINE_START]
|
||||
|
||||
/* Enable Protected Mode */
|
||||
mov %cr0, %eax
|
||||
or $0x1, %al
|
||||
mov %eax, %cr0
|
||||
|
||||
/* Jump to Protected Mode */
|
||||
ljmp $0x8, $(Trampoline32 - _trampoline_start + TRAMPOLINE_START)
|
||||
|
||||
/* ========== 32-bit ========== */
|
||||
|
||||
.code32
|
||||
Trampoline32:
|
||||
mov $0x10, %bx
|
||||
mov %bx, %ds
|
||||
mov %bx, %es
|
||||
mov %bx, %ss
|
||||
|
||||
/* Set a page table */
|
||||
mov [TRAMPOLINE_PAGE_TABLE], %eax
|
||||
mov %eax, %cr3
|
||||
|
||||
/* Enable PAE and PSE */
|
||||
mov %cr4, %eax
|
||||
or $0x20, %eax /* PAE */
|
||||
or $0x80, %eax /* PSE */
|
||||
mov %eax, %cr4
|
||||
|
||||
/* Enable Long Mode */
|
||||
mov $0xC0000080, %ecx
|
||||
rdmsr
|
||||
or $0x100, %eax /* LME */
|
||||
wrmsr
|
||||
|
||||
/* Enable paging */
|
||||
mov %cr0, %eax
|
||||
or $0x80000000, %eax /* PG */
|
||||
mov %eax, %cr0
|
||||
|
||||
/* Load Long Mode GDT */
|
||||
lgdt [LongMode_gdtr - _trampoline_start + TRAMPOLINE_START]
|
||||
|
||||
/* Jump to Long Mode */
|
||||
ljmp $0x8, $(Trampoline64 - _trampoline_start + TRAMPOLINE_START)
|
||||
|
||||
/* ========== 64-bit ========== */
|
||||
|
||||
.code64
|
||||
Trampoline64:
|
||||
mov $0x10, %ax
|
||||
mov %ax, %ds
|
||||
mov %ax, %es
|
||||
mov %ax, %ss
|
||||
|
||||
mov $0x0, %ax
|
||||
mov %ax, %fs
|
||||
mov %ax, %gs
|
||||
|
||||
/* Set custom GDT & IDT */
|
||||
lgdt [TRAMPOLINE_GDT]
|
||||
lidt [TRAMPOLINE_IDT]
|
||||
|
||||
/* Set up stack */
|
||||
mov [TRAMPOLINE_STACK], %rsp
|
||||
mov $0x0, %rbp
|
||||
|
||||
/* Reset RFLAGS */
|
||||
push $0x0
|
||||
popf
|
||||
|
||||
/* Jump to TrampolinePrepareExit */
|
||||
call TrampolineExit
|
||||
|
||||
.extern StartCPU
|
||||
TrampolineExit:
|
||||
mov $StartCPU, %rax
|
||||
call *%rax
|
||||
|
||||
.align 16
|
||||
ProtectedMode_gdtr:
|
||||
.word ProtectedModeGDTEnd - ProtectedModeGDTStart - 1
|
||||
.long ProtectedModeGDTStart - _trampoline_start + TRAMPOLINE_START
|
||||
|
||||
.align 16
|
||||
ProtectedModeGDTStart:
|
||||
/* NULL segment */
|
||||
.quad 0x0
|
||||
|
||||
/* Code segment */
|
||||
.word 0xFFFF
|
||||
.word 0x0000
|
||||
.byte 0x00
|
||||
.word 0xCF9A
|
||||
.byte 0x00
|
||||
|
||||
/* Data segment */
|
||||
.word 0xFFFF
|
||||
.word 0x0000
|
||||
.byte 0x00
|
||||
.word 0xCF92
|
||||
.byte 0x00
|
||||
ProtectedModeGDTEnd:
|
||||
nop
|
||||
|
||||
.align 16
|
||||
LongMode_gdtr:
|
||||
.word LongModeGDTEnd - LongModeGDTStart - 1
|
||||
.quad LongModeGDTStart - _trampoline_start + TRAMPOLINE_START
|
||||
|
||||
.align 16
|
||||
LongModeGDTStart:
|
||||
/* NULL segment */
|
||||
.quad 0x0
|
||||
|
||||
/* Code segment */
|
||||
.word 0xFFFF
|
||||
.word 0x0000
|
||||
.byte 0x00
|
||||
.word 0xAF98
|
||||
.byte 0x00
|
||||
|
||||
/* Data segment */
|
||||
.word 0xFFFF
|
||||
.word 0x0000
|
||||
.byte 0x00
|
||||
.word 0xCF92
|
||||
.byte 0x00
|
||||
LongModeGDTEnd:
|
||||
nop
|
||||
|
||||
.global _trampoline_end
|
||||
_trampoline_end:
|
0
Kernel/arch/amd64/include/.gitkeep
Normal file
0
Kernel/arch/amd64/include/.gitkeep
Normal file
129
Kernel/arch/amd64/linker.ld
Normal file
129
Kernel/arch/amd64/linker.ld
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT(elf64-x86-64)
|
||||
OUTPUT_ARCH(i386:x86-64)
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
PF_R = 0x4;
|
||||
PF_W = 0x2;
|
||||
PF_X = 0x1;
|
||||
|
||||
PHDRS
|
||||
{
|
||||
bootstrap PT_LOAD FLAGS( PF_R | PF_W /*| PF_X*/ );
|
||||
text PT_LOAD FLAGS( PF_R | PF_X );
|
||||
data PT_LOAD FLAGS( PF_R | PF_W );
|
||||
rodata PT_LOAD FLAGS( PF_R );
|
||||
bss PT_LOAD FLAGS( PF_R | PF_W );
|
||||
}
|
||||
|
||||
KERNEL_VMA = 0xFFFFFFFF80000000;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x100000;
|
||||
_bootstrap_start = .;
|
||||
.bootstrap ALIGN(CONSTANT(MAXPAGESIZE)) :
|
||||
{
|
||||
*(.multiboot)
|
||||
*(.multiboot2)
|
||||
*(.bootstrap .bootstrap.*)
|
||||
} :bootstrap
|
||||
_bootstrap_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
. += KERNEL_VMA;
|
||||
|
||||
_kernel_start = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
_kernel_text_start = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
.text ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.text) - KERNEL_VMA)
|
||||
{
|
||||
*(.text .text.*)
|
||||
} :text
|
||||
_kernel_text_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
_kernel_data_start = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
.data ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.data) - KERNEL_VMA)
|
||||
{
|
||||
*(.data .data.*)
|
||||
} :data
|
||||
|
||||
.eh_frame : AT(ADDR(.eh_frame) - KERNEL_VMA) ONLY_IF_RW
|
||||
{
|
||||
KEEP (*(.eh_frame .eh_frame.*))
|
||||
} :data
|
||||
|
||||
.gcc_except_table : AT(ADDR(.gcc_except_table) - KERNEL_VMA) ONLY_IF_RW
|
||||
{
|
||||
KEEP (*(.gcc_except_table .gcc_except_table.*))
|
||||
} :data
|
||||
_kernel_data_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
_kernel_rodata_start = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
.rodata ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.rodata) - KERNEL_VMA)
|
||||
{
|
||||
*(.rodata .rodata.*)
|
||||
} :rodata
|
||||
|
||||
.init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA)
|
||||
{
|
||||
PROVIDE_HIDDEN(__init_array_start = .);
|
||||
KEEP(*(.init_array .ctors))
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
} :rodata
|
||||
|
||||
.fini_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.fini_array) - KERNEL_VMA)
|
||||
{
|
||||
PROVIDE_HIDDEN(__fini_array_start = .);
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||
KEEP(*(.fini_array .dtors))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
} :rodata
|
||||
|
||||
.eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - KERNEL_VMA)
|
||||
{
|
||||
*(.eh_frame_hdr .eh_frame_hdr.*)
|
||||
} :rodata
|
||||
|
||||
.eh_frame : AT(ADDR(.eh_frame) - KERNEL_VMA) ONLY_IF_RO
|
||||
{
|
||||
KEEP (*(.eh_frame .eh_frame.*))
|
||||
} :rodata
|
||||
|
||||
.gcc_except_table : AT(ADDR(.gcc_except_table) - KERNEL_VMA) ONLY_IF_RO
|
||||
{
|
||||
KEEP (*(.gcc_except_table .gcc_except_table.*))
|
||||
} :rodata
|
||||
_kernel_rodata_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
_kernel_bss_start = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
.bss ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.bss) - KERNEL_VMA)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss .bss.*)
|
||||
} :bss
|
||||
_kernel_bss_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
_kernel_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.comment*)
|
||||
*(.note*)
|
||||
}
|
||||
}
|
97
Kernel/arch/amd64/madt.cpp
Normal file
97
Kernel/arch/amd64/madt.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
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 "acpi.hpp"
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace ACPI
|
||||
{
|
||||
MADT::MADT(ACPI::MADTHeader *madt)
|
||||
{
|
||||
trace("Initializing MADT");
|
||||
if (!madt)
|
||||
{
|
||||
error("MADT is NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
CPUCores = 0;
|
||||
LAPICAddress = (LAPIC *)(uintptr_t)madt->LocalControllerAddress;
|
||||
for (uint8_t *ptr = (uint8_t *)(madt->Entries);
|
||||
(uintptr_t)(ptr) < (uintptr_t)(madt) + madt->Header.Length;
|
||||
ptr += *(ptr + 1))
|
||||
{
|
||||
switch (*(ptr))
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (ptr[4] & 1)
|
||||
{
|
||||
lapic.push_back((LocalAPIC *)ptr);
|
||||
KPrint("Local APIC %d (APIC %d) found.", lapic.back()->ACPIProcessorId, lapic.back()->APICId);
|
||||
CPUCores++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
ioapic.push_back((MADTIOApic *)ptr);
|
||||
KPrint("I/O APIC %d (Address %#lx) found.", ioapic.back()->APICID, ioapic.back()->Address);
|
||||
Memory::Virtual(KernelPageTable).Map((void *)(uintptr_t)ioapic.back()->Address, (void *)(uintptr_t)ioapic.back()->Address, Memory::PTFlag::RW | Memory::PTFlag::PCD); // Make sure that the address is mapped.
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
iso.push_back((MADTIso *)ptr);
|
||||
KPrint("ISO (IRQ:%#lx, BUS:%#lx, GSI:%#lx, %s/%s) found.",
|
||||
iso.back()->IRQSource, iso.back()->BuSSource, iso.back()->GSI,
|
||||
iso.back()->Flags & 0x00000004 ? "Active High" : "Active Low",
|
||||
iso.back()->Flags & 0x00000100 ? "Edge Triggered" : "Level Triggered");
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
nmi.push_back((MADTNmi *)ptr);
|
||||
KPrint("NMI %#lx (lint:%#lx) found.", nmi.back()->processor, nmi.back()->lint);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
LAPICAddress = (LAPIC *)ptr;
|
||||
KPrint("APIC found at %#lx", LAPICAddress);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
KPrint("Unknown MADT entry %#lx", *(ptr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
Memory::Virtual(KernelPageTable).Map((void *)LAPICAddress, (void *)LAPICAddress, Memory::PTFlag::RW | Memory::PTFlag::PCD); // I should map more than one page?
|
||||
}
|
||||
CPUCores--; // We start at 0 (BSP) and end at 11 (APs), so we have 12 cores.
|
||||
KPrint("Total CPU cores: %d", CPUCores + 1);
|
||||
}
|
||||
|
||||
MADT::~MADT()
|
||||
{
|
||||
}
|
||||
}
|
518
Kernel/arch/amd64/memory/vmm.cpp
Normal file
518
Kernel/arch/amd64/memory/vmm.cpp
Normal file
@ -0,0 +1,518 @@
|
||||
/*
|
||||
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 <memory.hpp>
|
||||
|
||||
#include <convert.h>
|
||||
#include <debug.h>
|
||||
|
||||
namespace Memory
|
||||
{
|
||||
bool Virtual::Check(void *VirtualAddress, PTFlag Flag)
|
||||
{
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFFFFFFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
|
||||
PageDirectoryPointerTableEntryPtr *PDPTE = nullptr;
|
||||
PageDirectoryEntryPtr *PDE = nullptr;
|
||||
PageTableEntryPtr *PTE = nullptr;
|
||||
|
||||
PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
|
||||
if (!PML4->Present)
|
||||
{
|
||||
debug("PML4 not present for %#lx", VirtualAddress);
|
||||
return false;
|
||||
}
|
||||
|
||||
PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->GetAddress() << 12);
|
||||
if (!PDPTE)
|
||||
{
|
||||
debug("Failed to get PDPTE for %#lx", VirtualAddress);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PDPTE->Entries[Index.PDPTEIndex].PageSize)
|
||||
{
|
||||
bool result = PDPTE->Entries[Index.PDPTEIndex].raw & Flag;
|
||||
if (!result)
|
||||
{
|
||||
debug("Failed to check %#lx for %#lx (raw: %#lx)", VirtualAddress, Flag,
|
||||
PDPTE->Entries[Index.PDPTEIndex].raw);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
|
||||
if (!PDE)
|
||||
{
|
||||
debug("Failed to get PDE for %#lx", VirtualAddress);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PDE->Entries[Index.PDEIndex].PageSize)
|
||||
{
|
||||
bool result = PDE->Entries[Index.PDEIndex].raw & Flag;
|
||||
if (!result)
|
||||
{
|
||||
debug("Failed to check %#lx for %#lx (raw: %#lx)", VirtualAddress, Flag,
|
||||
PDE->Entries[Index.PDEIndex].raw);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
|
||||
if (!PTE)
|
||||
{
|
||||
debug("Failed to get PTE for %#lx", VirtualAddress);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = PTE->Entries[Index.PTEIndex].raw & Flag;
|
||||
if (!result)
|
||||
{
|
||||
debug("Failed to check %#lx for %#lx (raw: %#lx)", VirtualAddress, Flag,
|
||||
PTE->Entries[Index.PTEIndex].raw);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void *Virtual::GetPhysical(void *VirtualAddress)
|
||||
{
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFFFFFFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
|
||||
|
||||
PageDirectoryPointerTableEntryPtr *PDPTE = nullptr;
|
||||
PageDirectoryEntryPtr *PDE = nullptr;
|
||||
PageTableEntryPtr *PTE = nullptr;
|
||||
|
||||
if (PML4->Present)
|
||||
{
|
||||
PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->GetAddress() << 12);
|
||||
if (PDPTE)
|
||||
{
|
||||
if (PDPTE->Entries[Index.PDPTEIndex].Present)
|
||||
{
|
||||
if (PDPTE->Entries[Index.PDPTEIndex].PageSize)
|
||||
return (void *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
|
||||
|
||||
PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
|
||||
if (PDE)
|
||||
{
|
||||
if (PDE->Entries[Index.PDEIndex].Present)
|
||||
{
|
||||
if (PDE->Entries[Index.PDEIndex].PageSize)
|
||||
return (void *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
|
||||
|
||||
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
|
||||
if (PTE)
|
||||
{
|
||||
if (PTE->Entries[Index.PTEIndex].Present)
|
||||
return (void *)((uintptr_t)PTE->Entries[Index.PTEIndex].GetAddress() << 12);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Virtual::MapType Virtual::GetMapType(void *VirtualAddress)
|
||||
{
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFFFFFFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
|
||||
PageDirectoryPointerTableEntryPtr *PDPTE = nullptr;
|
||||
PageDirectoryEntryPtr *PDE = nullptr;
|
||||
PageTableEntryPtr *PTE = nullptr;
|
||||
|
||||
PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
|
||||
if (!PML4->Present)
|
||||
goto ReturnLogError;
|
||||
|
||||
PDPTE = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->GetAddress() << 12);
|
||||
if (!PDPTE || !PDPTE->Entries[Index.PDPTEIndex].Present)
|
||||
goto ReturnLogError;
|
||||
|
||||
if (PDPTE->Entries[Index.PDPTEIndex].PageSize)
|
||||
return MapType::OneGiB;
|
||||
|
||||
PDE = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Entries[Index.PDPTEIndex].GetAddress() << 12);
|
||||
if (!PDE || !PDE->Entries[Index.PDEIndex].Present)
|
||||
goto ReturnLogError;
|
||||
|
||||
if (PDE->Entries[Index.PDEIndex].PageSize)
|
||||
return MapType::TwoMiB;
|
||||
|
||||
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->Entries[Index.PDEIndex].GetAddress() << 12);
|
||||
if (!PTE)
|
||||
goto ReturnLogError;
|
||||
|
||||
if (PTE->Entries[Index.PTEIndex].Present)
|
||||
return MapType::FourKiB;
|
||||
|
||||
ReturnLogError:
|
||||
return MapType::NoMapType;
|
||||
}
|
||||
|
||||
PageMapLevel5 *Virtual::GetPML5(void *VirtualAddress, MapType Type)
|
||||
{
|
||||
UNUSED(VirtualAddress);
|
||||
UNUSED(Type);
|
||||
stub; /* TODO */
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PageMapLevel4 *Virtual::GetPML4(void *VirtualAddress, MapType Type)
|
||||
{
|
||||
UNUSED(Type);
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFFFFFFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
|
||||
if (PML4->Present)
|
||||
return PML4;
|
||||
|
||||
debug("PML4 not present for %#lx", VirtualAddress);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PageDirectoryPointerTableEntry *Virtual::GetPDPTE(void *VirtualAddress, MapType Type)
|
||||
{
|
||||
UNUSED(Type);
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFFFFFFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
|
||||
if (!PML4->Present)
|
||||
{
|
||||
debug("PML4 not present for %#lx", VirtualAddress);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
|
||||
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
|
||||
if (PDPTE->Present)
|
||||
return PDPTE;
|
||||
|
||||
debug("PDPTE not present for %#lx", VirtualAddress);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PageDirectoryEntry *Virtual::GetPDE(void *VirtualAddress, MapType Type)
|
||||
{
|
||||
UNUSED(Type);
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFFFFFFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
|
||||
if (!PML4->Present)
|
||||
{
|
||||
debug("PML4 not present for %#lx", VirtualAddress);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
|
||||
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
|
||||
if (!PDPTE->Present)
|
||||
{
|
||||
debug("PDPTE not present for %#lx", VirtualAddress);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12);
|
||||
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
|
||||
if (PDE->Present)
|
||||
return PDE;
|
||||
|
||||
debug("PDE not present for %#lx", VirtualAddress);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PageTableEntry *Virtual::GetPTE(void *VirtualAddress, MapType Type)
|
||||
{
|
||||
UNUSED(Type);
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFFFFFFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
|
||||
if (!PML4->Present)
|
||||
{
|
||||
debug("PML4 not present for %#lx", VirtualAddress);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
|
||||
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
|
||||
if (!PDPTE->Present)
|
||||
{
|
||||
debug("PDPTE not present for %#lx", VirtualAddress);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12);
|
||||
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
|
||||
if (!PDE->Present)
|
||||
{
|
||||
debug("PDE not present for %#lx", VirtualAddress);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12);
|
||||
PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex];
|
||||
if (PTE->Present)
|
||||
return PTE;
|
||||
|
||||
debug("PTE not present for %#lx", VirtualAddress);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type)
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
if (unlikely(!this->pTable))
|
||||
{
|
||||
error("No page table");
|
||||
return;
|
||||
}
|
||||
|
||||
Flags |= PTFlag::P;
|
||||
|
||||
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 = &this->pTable->Entries[Index.PMLIndex];
|
||||
PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr;
|
||||
if (!PML4->Present)
|
||||
{
|
||||
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryPointerTableEntryPtr) + 1));
|
||||
memset(PDPTEPtr, 0, sizeof(PageDirectoryPointerTableEntryPtr));
|
||||
PML4->Present = true;
|
||||
PML4->SetAddress((uintptr_t)PDPTEPtr >> 12);
|
||||
}
|
||||
else
|
||||
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)(PML4->GetAddress() << 12);
|
||||
PML4->raw |= DirectoryFlags;
|
||||
|
||||
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
|
||||
if (Type == MapType::OneGiB)
|
||||
{
|
||||
PDPTE->raw |= Flags;
|
||||
PDPTE->PageSize = true;
|
||||
PDPTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
|
||||
debug("Mapped 1GB page at %p to %p", VirtualAddress, PhysicalAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
PageDirectoryEntryPtr *PDEPtr = nullptr;
|
||||
if (!PDPTE->Present)
|
||||
{
|
||||
PDEPtr = (PageDirectoryEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryEntryPtr) + 1));
|
||||
memset(PDEPtr, 0, sizeof(PageDirectoryEntryPtr));
|
||||
PDPTE->Present = true;
|
||||
PDPTE->SetAddress((uintptr_t)PDEPtr >> 12);
|
||||
}
|
||||
else
|
||||
PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12);
|
||||
PDPTE->raw |= DirectoryFlags;
|
||||
|
||||
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
|
||||
if (Type == MapType::TwoMiB)
|
||||
{
|
||||
PDE->raw |= Flags;
|
||||
PDE->PageSize = true;
|
||||
PDE->SetAddress((uintptr_t)PhysicalAddress >> 12);
|
||||
debug("Mapped 2MB page at %p to %p", VirtualAddress, PhysicalAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
PageTableEntryPtr *PTEPtr = nullptr;
|
||||
if (!PDE->Present)
|
||||
{
|
||||
PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr) + 1));
|
||||
memset(PTEPtr, 0, sizeof(PageTableEntryPtr));
|
||||
PDE->Present = true;
|
||||
PDE->SetAddress((uintptr_t)PTEPtr >> 12);
|
||||
}
|
||||
else
|
||||
PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12);
|
||||
PDE->raw |= DirectoryFlags;
|
||||
|
||||
PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex];
|
||||
PTE->Present = true;
|
||||
PTE->raw |= Flags;
|
||||
PTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
|
||||
CPU::x64::invlpg(VirtualAddress);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* https://stackoverflow.com/a/3208376/9352057 */
|
||||
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
|
||||
#define BYTE_TO_BINARY(byte) \
|
||||
(byte & 0x80 ? '1' : '0'), \
|
||||
(byte & 0x40 ? '1' : '0'), \
|
||||
(byte & 0x20 ? '1' : '0'), \
|
||||
(byte & 0x10 ? '1' : '0'), \
|
||||
(byte & 0x08 ? '1' : '0'), \
|
||||
(byte & 0x04 ? '1' : '0'), \
|
||||
(byte & 0x02 ? '1' : '0'), \
|
||||
(byte & 0x01 ? '1' : '0')
|
||||
|
||||
if (!this->Check(VirtualAddress, (PTFlag)Flags)) // quick workaround just to see where it fails
|
||||
warn("Failed to map v:%#lx p:%#lx with flags: " BYTE_TO_BINARY_PATTERN, VirtualAddress, PhysicalAddress, BYTE_TO_BINARY(Flags));
|
||||
#endif
|
||||
}
|
||||
|
||||
void Virtual::Unmap(void *VirtualAddress, MapType Type)
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
if (!this->pTable)
|
||||
{
|
||||
error("No page table");
|
||||
return;
|
||||
}
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
|
||||
PageMapLevel4 *PML4 = &this->pTable->Entries[Index.PMLIndex];
|
||||
if (!PML4->Present)
|
||||
return;
|
||||
|
||||
PageDirectoryPointerTableEntryPtr *PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)((uintptr_t)PML4->Address << 12);
|
||||
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
|
||||
if (!PDPTE->Present)
|
||||
return;
|
||||
|
||||
if (Type == MapType::OneGiB && PDPTE->PageSize)
|
||||
{
|
||||
PDPTE->Present = false;
|
||||
return;
|
||||
}
|
||||
|
||||
PageDirectoryEntryPtr *PDEPtr = (PageDirectoryEntryPtr *)((uintptr_t)PDPTE->Address << 12);
|
||||
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
|
||||
if (!PDE->Present)
|
||||
return;
|
||||
|
||||
if (Type == MapType::TwoMiB && PDE->PageSize)
|
||||
{
|
||||
PDE->Present = false;
|
||||
return;
|
||||
}
|
||||
|
||||
PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE->Address << 12);
|
||||
PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex];
|
||||
if (!PTE.Present)
|
||||
return;
|
||||
|
||||
PTE.Present = false;
|
||||
PTEPtr->Entries[Index.PTEIndex] = PTE;
|
||||
CPU::x64::invlpg(VirtualAddress);
|
||||
}
|
||||
|
||||
void Virtual::Remap(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type)
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
if (unlikely(!this->pTable))
|
||||
{
|
||||
error("No page table");
|
||||
return;
|
||||
}
|
||||
|
||||
Flags |= PTFlag::P;
|
||||
|
||||
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 = &this->pTable->Entries[Index.PMLIndex];
|
||||
PageDirectoryPointerTableEntryPtr *PDPTEPtr = nullptr;
|
||||
if (!PML4->Present)
|
||||
{
|
||||
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryPointerTableEntryPtr) + 1));
|
||||
memset(PDPTEPtr, 0, sizeof(PageDirectoryPointerTableEntryPtr));
|
||||
PML4->Present = true;
|
||||
PML4->SetAddress((uintptr_t)PDPTEPtr >> 12);
|
||||
}
|
||||
else
|
||||
PDPTEPtr = (PageDirectoryPointerTableEntryPtr *)(PML4->GetAddress() << 12);
|
||||
PML4->raw |= DirectoryFlags;
|
||||
|
||||
PageDirectoryPointerTableEntry *PDPTE = &PDPTEPtr->Entries[Index.PDPTEIndex];
|
||||
if (Type == MapType::OneGiB)
|
||||
{
|
||||
PDPTE->raw &= 0xFFF;
|
||||
PDPTE->raw |= Flags;
|
||||
PDPTE->PageSize = true;
|
||||
PDPTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
|
||||
debug("Mapped 1GB page at %p to %p", VirtualAddress, PhysicalAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
PageDirectoryEntryPtr *PDEPtr = nullptr;
|
||||
if (!PDPTE->Present)
|
||||
{
|
||||
PDEPtr = (PageDirectoryEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageDirectoryEntryPtr) + 1));
|
||||
memset(PDEPtr, 0, sizeof(PageDirectoryEntryPtr));
|
||||
PDPTE->Present = true;
|
||||
PDPTE->SetAddress((uintptr_t)PDEPtr >> 12);
|
||||
}
|
||||
else
|
||||
PDEPtr = (PageDirectoryEntryPtr *)(PDPTE->GetAddress() << 12);
|
||||
PDPTE->raw |= DirectoryFlags;
|
||||
|
||||
PageDirectoryEntry *PDE = &PDEPtr->Entries[Index.PDEIndex];
|
||||
if (Type == MapType::TwoMiB)
|
||||
{
|
||||
PDE->raw &= 0xFFF;
|
||||
PDE->raw |= Flags;
|
||||
PDE->PageSize = true;
|
||||
PDE->SetAddress((uintptr_t)PhysicalAddress >> 12);
|
||||
debug("Mapped 2MB page at %p to %p", VirtualAddress, PhysicalAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
PageTableEntryPtr *PTEPtr = nullptr;
|
||||
if (!PDE->Present)
|
||||
{
|
||||
PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr) + 1));
|
||||
memset(PTEPtr, 0, sizeof(PageTableEntryPtr));
|
||||
PDE->Present = true;
|
||||
PDE->SetAddress((uintptr_t)PTEPtr >> 12);
|
||||
}
|
||||
else
|
||||
PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12);
|
||||
PDE->raw |= DirectoryFlags;
|
||||
|
||||
PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex];
|
||||
PTE->raw &= 0xFFF;
|
||||
PTE->raw |= Flags;
|
||||
PTE->Present = true;
|
||||
PTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
|
||||
CPU::x64::invlpg(VirtualAddress);
|
||||
}
|
||||
}
|
99
Kernel/arch/amd64/syscalls.cpp
Normal file
99
Kernel/arch/amd64/syscalls.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
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 <syscalls.hpp>
|
||||
|
||||
#include <cpu.hpp>
|
||||
|
||||
#include "cpu/gdt.hpp"
|
||||
|
||||
// https://supercip971.github.io/02-wingos-syscalls.html
|
||||
using namespace CPU::x64;
|
||||
|
||||
// "core/SystemCalls.cpp"
|
||||
extern "C" uint64_t SystemCallsHandler(SyscallsFrame *regs);
|
||||
|
||||
extern "C" void SystemCallHandlerStub();
|
||||
|
||||
extern "C" __naked __used __no_stack_protector __aligned(16) void SystemCallHandlerStub()
|
||||
{
|
||||
asmv("swapgs\n"); /* Swap GS to get the gsTCB */
|
||||
asmv("mov %rsp, %gs:0x8\n"); /* We save the current rsp to gsTCB->TempStack */
|
||||
asmv("mov %gs:0x0, %rsp\n"); /* Get gsTCB->SystemCallStack and set it as rsp */
|
||||
asmv("push $0x1b\n"); /* Push user data segment for SyscallsFrame */
|
||||
asmv("push %gs:0x8\n"); /* Push gsTCB->TempStack (old rsp) for SyscallsFrame */
|
||||
asmv("push %r11\n"); /* Push the flags for SyscallsFrame */
|
||||
asmv("push $0x23\n"); /* Push user code segment for SyscallsFrame */
|
||||
asmv("push %rcx\n"); /* Push the return address for SyscallsFrame + sysretq (https://www.felixcloutier.com/x86/sysret) */
|
||||
|
||||
/* Push registers */
|
||||
asmv("push %rax\n"
|
||||
"push %rbx\n"
|
||||
"push %rcx\n"
|
||||
"push %rdx\n"
|
||||
"push %rsi\n"
|
||||
"push %rdi\n"
|
||||
"push %rbp\n"
|
||||
"push %r8\n"
|
||||
"push %r9\n"
|
||||
"push %r10\n"
|
||||
"push %r11\n"
|
||||
"push %r12\n"
|
||||
"push %r13\n"
|
||||
"push %r14\n"
|
||||
"push %r15\n");
|
||||
|
||||
/* Set the first argument to the SyscallsFrame pointer */
|
||||
asmv("mov %rsp, %rdi\n");
|
||||
asmv("mov $0, %rbp\n");
|
||||
asmv("call SystemCallsHandler\n");
|
||||
|
||||
/* Pop registers except rax */
|
||||
asmv("pop %r15\n"
|
||||
"pop %r14\n"
|
||||
"pop %r13\n"
|
||||
"pop %r12\n"
|
||||
"pop %r11\n"
|
||||
"pop %r10\n"
|
||||
"pop %r9\n"
|
||||
"pop %r8\n"
|
||||
"pop %rbp\n"
|
||||
"pop %rdi\n"
|
||||
"pop %rsi\n"
|
||||
"pop %rdx\n"
|
||||
"pop %rcx\n"
|
||||
"pop %rbx\n");
|
||||
|
||||
/* Restore rsp from gsTCB->TempStack */
|
||||
asmv("mov %gs:0x8, %rsp\n");
|
||||
#ifdef DEBUG
|
||||
/* Easier to debug stacks */
|
||||
asmv("movq $0, %gs:0x8\n");
|
||||
#endif
|
||||
|
||||
asmv("swapgs\n"); /* Swap GS back to the user GS */
|
||||
asmv("sti\n"); /* Enable interrupts */
|
||||
asmv("sysretq\n"); /* Return to rcx address in user mode */
|
||||
}
|
||||
|
||||
void InitializeSystemCalls()
|
||||
{
|
||||
wrmsr(MSR_EFER, rdmsr(MSR_EFER) | 1);
|
||||
wrmsr(MSR_STAR, ((uint64_t)(GDT_KERNEL_CODE) << 32) | ((uint64_t)(GDT_KERNEL_DATA | 3) << 48));
|
||||
wrmsr(MSR_LSTAR, (uint64_t)SystemCallHandlerStub);
|
||||
wrmsr(MSR_SYSCALL_MASK, (uint64_t)(1 << 9));
|
||||
}
|
38
Kernel/arch/amd64/tasking/signal_trampoline.s
Normal file
38
Kernel/arch/amd64/tasking/signal_trampoline.s
Normal 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/>.
|
||||
*/
|
||||
|
||||
.code64
|
||||
|
||||
.global _sig_native_trampoline_start
|
||||
_sig_native_trampoline_start:
|
||||
int $0x3
|
||||
|
||||
.global _sig_native_trampoline_end
|
||||
_sig_native_trampoline_end:
|
||||
|
||||
.global _sig_linux_trampoline_start
|
||||
_sig_linux_trampoline_start:
|
||||
movq %rsp, %rbp
|
||||
movq (%rbp), %rax
|
||||
call *%rax
|
||||
mov %rbp, %rsp
|
||||
/* rt_sigreturn = 15 */
|
||||
movq $15, %rax
|
||||
syscall
|
||||
|
||||
.global _sig_linux_trampoline_end
|
||||
_sig_linux_trampoline_end:
|
379
Kernel/arch/i386/arithmetic_operations.c
Normal file
379
Kernel/arch/i386/arithmetic_operations.c
Normal file
@ -0,0 +1,379 @@
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
|
||||
/* Source: https://github.com/glitchub/arith64 */
|
||||
#define arith64_u64 unsigned long long int
|
||||
#define arith64_s64 signed long long int
|
||||
#define arith64_u32 unsigned int
|
||||
#define arith64_s32 int
|
||||
|
||||
typedef union
|
||||
{
|
||||
arith64_u64 u64;
|
||||
arith64_s64 s64;
|
||||
struct
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
arith64_u32 hi;
|
||||
arith64_u32 lo;
|
||||
#else
|
||||
arith64_u32 lo;
|
||||
arith64_u32 hi;
|
||||
#endif
|
||||
} u32;
|
||||
struct
|
||||
{
|
||||
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
arith64_s32 hi;
|
||||
arith64_s32 lo;
|
||||
#else
|
||||
arith64_s32 lo;
|
||||
arith64_s32 hi;
|
||||
#endif
|
||||
} s32;
|
||||
} arith64_word;
|
||||
|
||||
#define arith64_hi(n) (arith64_word){.u64 = n}.u32.hi
|
||||
#define arith64_lo(n) (arith64_word){.u64 = n}.u32.lo
|
||||
#define arith64_neg(a, b) (((a) ^ ((((arith64_s64)(b)) >= 0) - 1)) + (((arith64_s64)(b)) < 0))
|
||||
#define arith64_abs(a) arith64_neg(a, a)
|
||||
|
||||
arith64_s64 __absvdi2(arith64_s64 a)
|
||||
{
|
||||
return arith64_abs(a);
|
||||
}
|
||||
|
||||
arith64_s64 __ashldi3(arith64_s64 a, int b)
|
||||
{
|
||||
arith64_word w = {.s64 = a};
|
||||
|
||||
b &= 63;
|
||||
|
||||
if (b >= 32)
|
||||
{
|
||||
w.u32.hi = w.u32.lo << (b - 32);
|
||||
w.u32.lo = 0;
|
||||
}
|
||||
else if (b)
|
||||
{
|
||||
w.u32.hi = (w.u32.lo >> (32 - b)) | (w.u32.hi << b);
|
||||
w.u32.lo <<= b;
|
||||
}
|
||||
return w.s64;
|
||||
}
|
||||
|
||||
arith64_s64 __ashrdi3(arith64_s64 a, int b)
|
||||
{
|
||||
arith64_word w = {.s64 = a};
|
||||
|
||||
b &= 63;
|
||||
|
||||
if (b >= 32)
|
||||
{
|
||||
w.s32.lo = w.s32.hi >> (b - 32);
|
||||
w.s32.hi >>= 31; // 0xFFFFFFFF or 0
|
||||
}
|
||||
else if (b)
|
||||
{
|
||||
w.u32.lo = (w.u32.hi << (32 - b)) | (w.u32.lo >> b);
|
||||
w.s32.hi >>= b;
|
||||
}
|
||||
return w.s64;
|
||||
}
|
||||
|
||||
int __clzsi2(arith64_u32 a)
|
||||
{
|
||||
int b, n = 0;
|
||||
b = !(a & 0xffff0000) << 4;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xff000000) << 3;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xf0000000) << 2;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xc0000000) << 1;
|
||||
n += b;
|
||||
a <<= b;
|
||||
return n + !(a & 0x80000000);
|
||||
}
|
||||
|
||||
int __clzdi2(arith64_u64 a)
|
||||
{
|
||||
int b, n = 0;
|
||||
b = !(a & 0xffffffff00000000ULL) << 5;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xffff000000000000ULL) << 4;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xff00000000000000ULL) << 3;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xf000000000000000ULL) << 2;
|
||||
n += b;
|
||||
a <<= b;
|
||||
b = !(a & 0xc000000000000000ULL) << 1;
|
||||
n += b;
|
||||
a <<= b;
|
||||
return n + !(a & 0x8000000000000000ULL);
|
||||
}
|
||||
|
||||
int __ctzsi2(arith64_u32 a)
|
||||
{
|
||||
int b, n = 0;
|
||||
b = !(a & 0x0000ffff) << 4;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x000000ff) << 3;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x0000000f) << 2;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x00000003) << 1;
|
||||
n += b;
|
||||
a >>= b;
|
||||
return n + !(a & 0x00000001);
|
||||
}
|
||||
|
||||
int __ctzdi2(arith64_u64 a)
|
||||
{
|
||||
int b, n = 0;
|
||||
b = !(a & 0x00000000ffffffffULL) << 5;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x000000000000ffffULL) << 4;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x00000000000000ffULL) << 3;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x000000000000000fULL) << 2;
|
||||
n += b;
|
||||
a >>= b;
|
||||
b = !(a & 0x0000000000000003ULL) << 1;
|
||||
n += b;
|
||||
a >>= b;
|
||||
return n + !(a & 0x0000000000000001ULL);
|
||||
}
|
||||
|
||||
arith64_u64 __divmoddi4(arith64_u64 a, arith64_u64 b, arith64_u64 *c)
|
||||
{
|
||||
if (b > a)
|
||||
{
|
||||
if (c)
|
||||
*c = a;
|
||||
return 0;
|
||||
}
|
||||
if (!arith64_hi(b))
|
||||
{
|
||||
if (b == 0)
|
||||
{
|
||||
volatile char x = 0;
|
||||
x = 1 / x;
|
||||
}
|
||||
if (b == 1)
|
||||
{
|
||||
if (c)
|
||||
*c = 0;
|
||||
return a;
|
||||
}
|
||||
if (!arith64_hi(a))
|
||||
{
|
||||
if (c)
|
||||
*c = arith64_lo(a) % arith64_lo(b);
|
||||
return arith64_lo(a) / arith64_lo(b);
|
||||
}
|
||||
}
|
||||
|
||||
char bits = __clzdi2(b) - __clzdi2(a) + 1;
|
||||
arith64_u64 rem = a >> bits;
|
||||
a <<= 64 - bits;
|
||||
arith64_u64 wrap = 0;
|
||||
while (bits-- > 0)
|
||||
{
|
||||
rem = (rem << 1) | (a >> 63);
|
||||
a = (a << 1) | (wrap & 1);
|
||||
wrap = ((arith64_s64)(b - rem - 1) >> 63);
|
||||
rem -= b & wrap;
|
||||
}
|
||||
if (c)
|
||||
*c = rem;
|
||||
return (a << 1) | (wrap & 1);
|
||||
}
|
||||
|
||||
arith64_s64 __divdi3(arith64_s64 a, arith64_s64 b)
|
||||
{
|
||||
arith64_u64 q = __divmoddi4(arith64_abs(a), arith64_abs(b), (void *)0);
|
||||
return arith64_neg(q, a ^ b);
|
||||
}
|
||||
|
||||
int __ffsdi2(arith64_u64 a) { return a ? __ctzdi2(a) + 1 : 0; }
|
||||
|
||||
arith64_u64 __lshrdi3(arith64_u64 a, int b)
|
||||
{
|
||||
arith64_word w = {.u64 = a};
|
||||
|
||||
b &= 63;
|
||||
|
||||
if (b >= 32)
|
||||
{
|
||||
w.u32.lo = w.u32.hi >> (b - 32);
|
||||
w.u32.hi = 0;
|
||||
}
|
||||
else if (b)
|
||||
{
|
||||
w.u32.lo = (w.u32.hi << (32 - b)) | (w.u32.lo >> b);
|
||||
w.u32.hi >>= b;
|
||||
}
|
||||
return w.u64;
|
||||
}
|
||||
|
||||
arith64_s64 __moddi3(arith64_s64 a, arith64_s64 b)
|
||||
{
|
||||
arith64_u64 r;
|
||||
__divmoddi4(arith64_abs(a), arith64_abs(b), &r);
|
||||
return arith64_neg(r, a);
|
||||
}
|
||||
|
||||
int __popcountsi2(arith64_u32 a)
|
||||
{
|
||||
|
||||
a = a - ((a >> 1) & 0x55555555);
|
||||
a = ((a >> 2) & 0x33333333) + (a & 0x33333333);
|
||||
a = (a + (a >> 4)) & 0x0F0F0F0F;
|
||||
a = (a + (a >> 16));
|
||||
|
||||
return (a + (a >> 8)) & 63;
|
||||
}
|
||||
|
||||
int __popcountdi2(arith64_u64 a)
|
||||
{
|
||||
|
||||
a = a - ((a >> 1) & 0x5555555555555555ULL);
|
||||
a = ((a >> 2) & 0x3333333333333333ULL) + (a & 0x3333333333333333ULL);
|
||||
a = (a + (a >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
|
||||
a = (a + (a >> 32));
|
||||
a = (a + (a >> 16));
|
||||
|
||||
return (a + (a >> 8)) & 127;
|
||||
}
|
||||
|
||||
arith64_u64 __udivdi3(arith64_u64 a, arith64_u64 b) { return __divmoddi4(a, b, (void *)0); }
|
||||
|
||||
arith64_u64 __umoddi3(arith64_u64 a, arith64_u64 b)
|
||||
{
|
||||
arith64_u64 r;
|
||||
__divmoddi4(a, b, &r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Good documentation: https://splichal.eu/scripts/sphinx/gccint/_build/html/the-gcc-low-level-runtime-library/routines-for-floating-point-emulation.html */
|
||||
|
||||
double __adddf3(double a, double b) { return a + b; }
|
||||
double __muldf3(double a, double b) { return a * b; }
|
||||
double __floatsidf(int i) { return (double)i; }
|
||||
int __ltdf2(double a, double b) { return a < b; }
|
||||
int __gtdf2(double a, double b) { return a > b; }
|
||||
int __nedf2(double a, double b) { return a != b; }
|
||||
int __eqdf2(double a, double b) { return a == b; }
|
||||
double __floatdidf(long i) { return (double)i; }
|
||||
double __divdf3(double a, double b) { return a / b; }
|
||||
double __subdf3(double a, double b) { return a - b; }
|
||||
int __gedf2(double a, double b) { return a >= b; }
|
||||
int __fixdfsi(double a) { return (int)a; }
|
||||
long __fixdfdi(double a) { return (long)a; }
|
||||
int __ledf2(double a, double b) { return a <= b; }
|
||||
|
||||
/* FIXME: Check if these functions are implemented correctly */
|
||||
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef struct
|
||||
{
|
||||
uint64_t value;
|
||||
} atomic_uint64_t;
|
||||
|
||||
/* No longer needed? */
|
||||
|
||||
// uint64_t __atomic_load_8(const atomic_uint64_t *p)
|
||||
// {
|
||||
// uint64_t value;
|
||||
// __asm__ volatile("lock cmpxchg8b %1"
|
||||
// : "=A"(value)
|
||||
// : "m"(*p)
|
||||
// : "memory");
|
||||
// return value;
|
||||
// }
|
||||
|
||||
// void __atomic_store_8(atomic_uint64_t *p, uint64_t value)
|
||||
// {
|
||||
// __asm__ volatile("lock cmpxchg8b %0"
|
||||
// : "=m"(p->value)
|
||||
// : "a"((uint32_t)value), "d"((uint32_t)(value >> 32)), "m"(*p)
|
||||
// : "memory");
|
||||
// }
|
||||
|
||||
int __fixsfsi(float a)
|
||||
{
|
||||
return (int)a;
|
||||
}
|
||||
|
||||
int __ltsf2(float a, float b)
|
||||
{
|
||||
return -(a < b);
|
||||
}
|
||||
|
||||
int __nesf2(float a, float b)
|
||||
{
|
||||
return a == b;
|
||||
}
|
||||
|
||||
int __eqsf2(float a, float b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
float __divsf3(float a, float b)
|
||||
{
|
||||
return (a / b);
|
||||
}
|
||||
|
||||
double __extendsfdf2(float a)
|
||||
{
|
||||
return (double)a;
|
||||
}
|
||||
|
||||
float __truncdfsf2(double a)
|
||||
{
|
||||
return (float)a;
|
||||
}
|
||||
|
||||
float __subsf3(float a, float b)
|
||||
{
|
||||
return (a - b);
|
||||
}
|
||||
|
||||
float __floatsisf(int a)
|
||||
{
|
||||
return (float)a;
|
||||
}
|
||||
|
||||
int __fixunssfsi(float a)
|
||||
{
|
||||
return (int)a;
|
||||
}
|
||||
|
||||
float __mulsf3(float a, float b)
|
||||
{
|
||||
return (a * b);
|
||||
}
|
||||
|
||||
float __addsf3(float a, float b)
|
||||
{
|
||||
return (a + b);
|
||||
}
|
51
Kernel/arch/i386/bootstrap/Multiboot/Paging/mb_pt.s
Normal file
51
Kernel/arch/i386/bootstrap/Multiboot/Paging/mb_pt.s
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
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_VIRTUAL_BASE = 0xC0000000 /* 3GB */
|
||||
KERNEL_PAGE_NUMBER = 768 /* KERNEL_VIRTUAL_BASE >> 22 */
|
||||
|
||||
.section .bootstrap.data, "a"
|
||||
.align 0x1000
|
||||
.global BootPageTable
|
||||
BootPageTable:
|
||||
.long 0x00000083
|
||||
.long 0x00400083
|
||||
.long 0x00800083
|
||||
.long 0x00C00083
|
||||
.long 0x01000083
|
||||
.long 0x01400083
|
||||
.long 0x01800083
|
||||
.long 0x01C00083
|
||||
.long 0x02000083
|
||||
.long 0x02400083
|
||||
.rept (KERNEL_PAGE_NUMBER - 10)
|
||||
.long 0
|
||||
.endr
|
||||
.long 0x00000083
|
||||
.long 0x00400083
|
||||
.long 0x00800083
|
||||
.long 0x00C00083
|
||||
.long 0x01000083
|
||||
.long 0x01400083
|
||||
.long 0x01800083
|
||||
.long 0x01C00083
|
||||
.long 0x02000083
|
||||
.long 0x02400083
|
||||
.rept (1024 - KERNEL_PAGE_NUMBER - 10)
|
||||
.long 0
|
||||
.endr
|
38
Kernel/arch/i386/bootstrap/Multiboot/_start.s
Normal file
38
Kernel/arch/i386/bootstrap/Multiboot/_start.s
Normal 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
|
27
Kernel/arch/i386/bootstrap/Multiboot/headers/header1.s
Normal file
27
Kernel/arch/i386/bootstrap/Multiboot/headers/header1.s
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
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 .multiboot, "a"
|
||||
.align 4
|
||||
|
||||
MULTIBOOT_HEADER:
|
||||
.long 0x1BADB002
|
||||
.long 1 << 0 | 1 << 1
|
||||
.long -(0x1BADB002 + (1 << 0 | 1 << 1))
|
93
Kernel/arch/i386/bootstrap/Multiboot/headers/header2.s
Normal file
93
Kernel/arch/i386/bootstrap/Multiboot/headers/header2.s
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
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
|
||||
.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:
|
81
Kernel/arch/i386/bootstrap/Multiboot/helper/detect.s
Normal file
81
Kernel/arch/i386/bootstrap/Multiboot/helper/detect.s
Normal 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, 1 << 21
|
||||
push eax
|
||||
popfd
|
||||
pushfd
|
||||
pop eax
|
||||
push ecx
|
||||
popfd
|
||||
xor eax, ecx
|
||||
jz .NoCPUID
|
||||
mov eax, 1
|
||||
ret
|
||||
.NoCPUID:
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.global Detect64Bit
|
||||
Detect64Bit:
|
||||
mov eax, 0x80000000
|
||||
cpuid
|
||||
cmp eax, 0x80000001
|
||||
jb .NoLongMode
|
||||
mov eax, 0x80000001
|
||||
cpuid
|
||||
test edx, 1 << 29
|
||||
jz .NoLongMode
|
||||
mov eax, 1
|
||||
ret
|
||||
.NoLongMode:
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.global DetectPSE
|
||||
DetectPSE:
|
||||
mov eax, 0x00000001
|
||||
cpuid
|
||||
test edx, 0x00000008
|
||||
jz .NoPSE
|
||||
mov eax, 1
|
||||
ret
|
||||
.NoPSE:
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
.global DetectPAE
|
||||
DetectPAE:
|
||||
mov eax, 0x00000001
|
||||
cpuid
|
||||
test edx, 0x00000040
|
||||
jz .NoPAE
|
||||
mov eax, 1
|
||||
ret
|
||||
.NoPAE:
|
||||
xor eax, eax
|
||||
ret
|
64
Kernel/arch/i386/bootstrap/Multiboot/helper/gdt32.s
Normal file
64
Kernel/arch/i386/bootstrap/Multiboot/helper/gdt32.s
Normal 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
|
210
Kernel/arch/i386/bootstrap/Multiboot/mb1_parse.cpp
Normal file
210
Kernel/arch/i386/bootstrap/Multiboot/mb1_parse.cpp
Normal 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 *)(uint32_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 += (__SIZE_TYPE__)entry.len;
|
||||
switch (entry.type)
|
||||
{
|
||||
case MULTIBOOT_MEMORY_AVAILABLE:
|
||||
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
|
||||
mb2binfo.Memory.Entry[i].Length = (__SIZE_TYPE__)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 = (__SIZE_TYPE__)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 = (__SIZE_TYPE__)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 = (__SIZE_TYPE__)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 = (__SIZE_TYPE__)entry.len;
|
||||
mb2binfo.Memory.Entry[i].Type = BadMemory;
|
||||
break;
|
||||
default:
|
||||
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
|
||||
mb2binfo.Memory.Entry[i].Length = (__SIZE_TYPE__)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 *)(uint32_t)((uint32_t)&_bootstrap_start + 0xC0000000);
|
||||
mb2binfo.Kernel.Size = ((uint32_t)&_kernel_end - (uint32_t)&_kernel_start) + ((uint32_t)&_bootstrap_end - (uint32_t)&_bootstrap_start);
|
||||
debug("Kernel base: %p (physical) %p (virtual)", mb2binfo.Kernel.PhysicalBase, mb2binfo.Kernel.VirtualBase);
|
||||
|
||||
Entry(&mb2binfo);
|
||||
}
|
300
Kernel/arch/i386/bootstrap/Multiboot/mb2_parse.cpp
Normal file
300
Kernel/arch/i386/bootstrap/Multiboot/mb2_parse.cpp
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
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 <boot/protocol/multiboot2.h>
|
||||
#include "../../../../kernel.h"
|
||||
|
||||
void multiboot2_parse(BootInfo &mb2binfo, uintptr_t Magic, uintptr_t Info)
|
||||
{
|
||||
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 != MULTIBOOT2_BOOTLOADER_MAGIC)
|
||||
{
|
||||
error("Multiboot magic is invalid (%#x != %#x)", Magic, MULTIBOOT2_BOOTLOADER_MAGIC);
|
||||
CPU::Stop();
|
||||
}
|
||||
|
||||
{
|
||||
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 *)(uint32_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 += (size_t)entry.len;
|
||||
switch (entry.type)
|
||||
{
|
||||
case MULTIBOOT_MEMORY_AVAILABLE:
|
||||
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
|
||||
mb2binfo.Memory.Entry[i].Length = (size_t)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 = (size_t)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 = (size_t)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 = (size_t)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 = (size_t)entry.len;
|
||||
mb2binfo.Memory.Entry[i].Type = BadMemory;
|
||||
break;
|
||||
default:
|
||||
mb2binfo.Memory.Entry[i].BaseAddress = (void *)entry.addr;
|
||||
mb2binfo.Memory.Entry[i].Length = (size_t)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 = (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 *)(uint32_t)load_base_addr->load_base_addr;
|
||||
mb2binfo.Kernel.VirtualBase = (void *)(uint32_t)(load_base_addr->load_base_addr + 0xC0000000);
|
||||
mb2binfo.Kernel.Size = (size_t)(((uint32_t)&_kernel_end - (uint32_t)&_kernel_start) + ((uint32_t)&_bootstrap_end - (uint32_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);
|
||||
}
|
53
Kernel/arch/i386/bootstrap/Multiboot/multiboot.cpp
Normal file
53
Kernel/arch/i386/bootstrap/Multiboot/multiboot.cpp
Normal 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();
|
||||
}
|
||||
}
|
79
Kernel/arch/i386/bootstrap/Multiboot/start.s
Normal file
79
Kernel/arch/i386/bootstrap/Multiboot/start.s
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
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 DetectPSE
|
||||
.extern multiboot_main
|
||||
.extern LoadGDT32
|
||||
.extern BootPageTable
|
||||
|
||||
.section .bootstrap.data, "a"
|
||||
MB_HeaderMagic:
|
||||
.quad 0
|
||||
|
||||
MB_HeaderInfo:
|
||||
.quad 0
|
||||
|
||||
.section .bootstrap.text, "a"
|
||||
|
||||
.global Multiboot_start
|
||||
Multiboot_start:
|
||||
cli
|
||||
|
||||
mov %eax, [MB_HeaderMagic]
|
||||
mov %ebx, [MB_HeaderInfo]
|
||||
|
||||
call DetectCPUID
|
||||
cmp $0, %eax
|
||||
je .
|
||||
|
||||
call DetectPSE
|
||||
cmp $0, %eax
|
||||
je .
|
||||
|
||||
mov %cr4, %ecx
|
||||
or $0x00000010, %ecx /* PSE */
|
||||
mov %ecx, %cr4
|
||||
|
||||
call LoadGDT32
|
||||
|
||||
mov $BootPageTable, %ecx
|
||||
mov %ecx, %cr3
|
||||
|
||||
mov %cr0, %ecx
|
||||
or $0x80000000, %ecx /* PG */
|
||||
mov %ecx, %cr0
|
||||
|
||||
mov $(KernelStack + KERNEL_STACK_SIZE), %esp
|
||||
mov $0x0, %ebp
|
||||
|
||||
mov [MB_HeaderMagic], %eax
|
||||
mov [MB_HeaderInfo], %ebx
|
||||
push %ebx
|
||||
push %eax
|
||||
call multiboot_main
|
||||
.Hang:
|
||||
hlt
|
||||
jmp .Hang
|
||||
|
||||
.section .bootstrap.bss, "a"
|
||||
.align 16
|
||||
KernelStack:
|
||||
.space KERNEL_STACK_SIZE
|
409
Kernel/arch/i386/cpu/apic.cpp
Normal file
409
Kernel/arch/i386/cpu/apic.cpp
Normal file
@ -0,0 +1,409 @@
|
||||
/*
|
||||
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 "apic.hpp"
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <uart.hpp>
|
||||
#include <lock.hpp>
|
||||
#include <acpi.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <smp.hpp>
|
||||
#include <io.h>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
|
||||
NewLock(APICLock);
|
||||
|
||||
using namespace CPU::x32;
|
||||
using namespace CPU::x86;
|
||||
|
||||
/*
|
||||
In constructor 'APIC::APIC::APIC(int)':
|
||||
warning: left shift count >= width of type
|
||||
| APICBaseAddress = BaseStruct.ApicBaseLo << 12u | BaseStruct.ApicBaseHi << 32u;
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~^~~~~~
|
||||
*/
|
||||
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
|
||||
|
||||
namespace APIC
|
||||
{
|
||||
// headache
|
||||
// https://www.amd.com/system/files/TechDocs/24593.pdf
|
||||
// https://www.naic.edu/~phil/software/intel/318148.pdf
|
||||
|
||||
uint32_t APIC::Read(uint32_t Register)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (Register != APIC_ICRLO &&
|
||||
Register != APIC_ICRHI &&
|
||||
Register != APIC_ID)
|
||||
debug("APIC::Read(%#lx) [x2=%d]", Register, x2APICSupported ? 1 : 0);
|
||||
#endif
|
||||
if (x2APICSupported)
|
||||
{
|
||||
if (Register != APIC_ICRHI)
|
||||
return s_cst(uint32_t, rdmsr((Register >> 4) + 0x800));
|
||||
else
|
||||
return s_cst(uint32_t, rdmsr(0x30 + 0x800));
|
||||
}
|
||||
else
|
||||
{
|
||||
CPU::MemBar::Barrier();
|
||||
uint32_t ret = *((volatile uint32_t *)((uintptr_t)APICBaseAddress + Register));
|
||||
CPU::MemBar::Barrier();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void APIC::Write(uint32_t Register, uint32_t Value)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (Register != APIC_EOI &&
|
||||
Register != APIC_TDCR &&
|
||||
Register != APIC_TIMER &&
|
||||
Register != APIC_TICR &&
|
||||
Register != APIC_ICRLO &&
|
||||
Register != APIC_ICRHI)
|
||||
debug("APIC::Write(%#lx, %#lx) [x2=%d]", Register, Value, x2APICSupported ? 1 : 0);
|
||||
#endif
|
||||
if (x2APICSupported)
|
||||
{
|
||||
if (Register != APIC_ICRHI)
|
||||
wrmsr((Register >> 4) + 0x800, Value);
|
||||
else
|
||||
wrmsr(MSR_X2APIC_ICR, Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPU::MemBar::Barrier();
|
||||
*((volatile uint32_t *)(((uintptr_t)APICBaseAddress) + Register)) = Value;
|
||||
CPU::MemBar::Barrier();
|
||||
}
|
||||
}
|
||||
|
||||
void APIC::IOWrite(uint64_t Base, uint32_t Register, uint32_t Value)
|
||||
{
|
||||
debug("APIC::IOWrite(%#lx, %#lx, %#lx)", Base, Register, Value);
|
||||
CPU::MemBar::Barrier();
|
||||
*((volatile uint32_t *)(((uintptr_t)Base))) = Register;
|
||||
CPU::MemBar::Barrier();
|
||||
*((volatile uint32_t *)(((uintptr_t)Base + 16))) = Value;
|
||||
CPU::MemBar::Barrier();
|
||||
}
|
||||
|
||||
uint32_t APIC::IORead(uint64_t Base, uint32_t Register)
|
||||
{
|
||||
debug("APIC::IORead(%#lx, %#lx)", Base, Register);
|
||||
CPU::MemBar::Barrier();
|
||||
*((volatile uint32_t *)(((uintptr_t)Base))) = Register;
|
||||
CPU::MemBar::Barrier();
|
||||
uint32_t ret = *((volatile uint32_t *)(((uintptr_t)Base + 16)));
|
||||
CPU::MemBar::Barrier();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void APIC::EOI() { this->Write(APIC_EOI, 0); }
|
||||
|
||||
void APIC::WaitForIPI()
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
do
|
||||
{
|
||||
icr.raw = this->Read(APIC_ICRLO);
|
||||
CPU::Pause();
|
||||
} while (icr.DeliveryStatus != Idle);
|
||||
}
|
||||
|
||||
void APIC::IPI(uint8_t CPU, InterruptCommandRegisterLow icr)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
if (x2APICSupported)
|
||||
{
|
||||
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
||||
this->WaitForIPI();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->Write(APIC_ICRHI, (CPU << 24));
|
||||
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
||||
this->WaitForIPI();
|
||||
}
|
||||
}
|
||||
|
||||
void APIC::SendInitIPI(uint8_t CPU)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
if (x2APICSupported)
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
icr.DeliveryMode = INIT;
|
||||
icr.Level = Assert;
|
||||
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
||||
this->WaitForIPI();
|
||||
}
|
||||
else
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
icr.DeliveryMode = INIT;
|
||||
icr.Level = Assert;
|
||||
this->Write(APIC_ICRHI, (CPU << 24));
|
||||
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
||||
this->WaitForIPI();
|
||||
}
|
||||
}
|
||||
|
||||
void APIC::SendStartupIPI(uint8_t CPU, uint64_t StartupAddress)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
if (x2APICSupported)
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
icr.Vector = s_cst(uint8_t, StartupAddress >> 12);
|
||||
icr.DeliveryMode = Startup;
|
||||
icr.Level = Assert;
|
||||
wrmsr(MSR_X2APIC_ICR, s_cst(uint32_t, icr.raw));
|
||||
this->WaitForIPI();
|
||||
}
|
||||
else
|
||||
{
|
||||
InterruptCommandRegisterLow icr = {.raw = 0};
|
||||
icr.Vector = s_cst(uint8_t, StartupAddress >> 12);
|
||||
icr.DeliveryMode = Startup;
|
||||
icr.Level = Assert;
|
||||
this->Write(APIC_ICRHI, (CPU << 24));
|
||||
this->Write(APIC_ICRLO, s_cst(uint32_t, icr.raw));
|
||||
this->WaitForIPI();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t APIC::IOGetMaxRedirect(uint32_t APICID)
|
||||
{
|
||||
uint32_t TableAddress = (this->IORead((((ACPI::MADT *)PowerManager->GetMADT())->ioapic[APICID]->Address), GetIOAPICVersion));
|
||||
return ((IOAPICVersion *)&TableAddress)->MaximumRedirectionEntry;
|
||||
}
|
||||
|
||||
void APIC::RawRedirectIRQ(uint16_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status)
|
||||
{
|
||||
uint64_t Value = Vector;
|
||||
|
||||
int64_t IOAPICTarget = -1;
|
||||
for (uint64_t i = 0; ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[std::size_t(i)] != 0; i++)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[std::size_t(i)]->GSIBase <= GSI)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->ioapic[std::size_t(i)]->GSIBase + IOGetMaxRedirect(s_cst(uint32_t, i)) > GSI)
|
||||
{
|
||||
IOAPICTarget = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IOAPICTarget == -1)
|
||||
{
|
||||
error("No ISO table found for I/O APIC");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: IOAPICRedirectEntry Entry = {.raw = 0};
|
||||
|
||||
if (Flags & ActiveHighLow)
|
||||
Value |= (1 << 13);
|
||||
|
||||
if (Flags & EdgeLevel)
|
||||
Value |= (1 << 15);
|
||||
|
||||
if (!Status)
|
||||
Value |= (1 << 16);
|
||||
|
||||
Value |= (((uintptr_t)CPU) << 56);
|
||||
uint32_t IORegister = (GSI - ((ACPI::MADT *)PowerManager->GetMADT())->ioapic[std::size_t(IOAPICTarget)]->GSIBase) * 2 + 16;
|
||||
|
||||
this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[std::size_t(IOAPICTarget)]->Address,
|
||||
IORegister, (uint32_t)Value);
|
||||
this->IOWrite(((ACPI::MADT *)PowerManager->GetMADT())->ioapic[std::size_t(IOAPICTarget)]->Address,
|
||||
IORegister + 1, (uint32_t)(Value >> 32));
|
||||
}
|
||||
|
||||
void APIC::RedirectIRQ(int CPU, uint16_t IRQ, int Status)
|
||||
{
|
||||
for (uint64_t i = 0; i < ((ACPI::MADT *)PowerManager->GetMADT())->iso.size(); i++)
|
||||
if (((ACPI::MADT *)PowerManager->GetMADT())->iso[std::size_t(i)]->IRQSource == IRQ)
|
||||
{
|
||||
debug("[ISO %d] Mapping to source IRQ%#d GSI:%#lx on CPU %d",
|
||||
i, ((ACPI::MADT *)PowerManager->GetMADT())->iso[std::size_t(i)]->IRQSource,
|
||||
((ACPI::MADT *)PowerManager->GetMADT())->iso[std::size_t(i)]->GSI,
|
||||
CPU);
|
||||
|
||||
this->RawRedirectIRQ(((ACPI::MADT *)PowerManager->GetMADT())->iso[std::size_t(i)]->IRQSource + 0x20,
|
||||
((ACPI::MADT *)PowerManager->GetMADT())->iso[std::size_t(i)]->GSI,
|
||||
((ACPI::MADT *)PowerManager->GetMADT())->iso[std::size_t(i)]->Flags,
|
||||
CPU, Status);
|
||||
return;
|
||||
}
|
||||
debug("Mapping IRQ%d on CPU %d", IRQ, CPU);
|
||||
this->RawRedirectIRQ(IRQ + 0x20, IRQ, 0, CPU, Status);
|
||||
}
|
||||
|
||||
void APIC::RedirectIRQs(int CPU)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
debug("Redirecting IRQs...");
|
||||
for (uint8_t i = 0; i < 16; i++)
|
||||
this->RedirectIRQ(CPU, i, 1);
|
||||
debug("Redirecting IRQs completed.");
|
||||
}
|
||||
|
||||
APIC::APIC(int Core)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
APIC_BASE BaseStruct = {.raw = rdmsr(MSR_APIC_BASE)};
|
||||
uint64_t BaseLow = BaseStruct.ApicBaseLo;
|
||||
uint64_t BaseHigh = BaseStruct.ApicBaseHi;
|
||||
this->APICBaseAddress = BaseLow << 12u | BaseHigh << 32u;
|
||||
trace("APIC Address: %#lx", this->APICBaseAddress);
|
||||
Memory::Virtual().Map((void *)this->APICBaseAddress, (void *)this->APICBaseAddress, Memory::PTFlag::RW | Memory::PTFlag::PCD);
|
||||
|
||||
bool x2APICSupported = false;
|
||||
if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_AMD) == 0)
|
||||
{
|
||||
CPU::x86::AMD::CPUID0x00000001 cpuid;
|
||||
if (cpuid.ECX.x2APIC)
|
||||
{
|
||||
// x2APICSupported = cpuid.ECX.x2APIC;
|
||||
fixme("x2APIC is supported");
|
||||
}
|
||||
}
|
||||
else if (strcmp(CPU::Vendor(), x86_CPUID_VENDOR_INTEL) == 0)
|
||||
{
|
||||
CPU::x86::Intel::CPUID0x00000001 cpuid;
|
||||
if (cpuid.ECX.x2APIC)
|
||||
{
|
||||
// x2APICSupported = cpuid.ECX.x2APIC;
|
||||
fixme("x2APIC is supported");
|
||||
}
|
||||
}
|
||||
|
||||
if (x2APICSupported)
|
||||
{
|
||||
this->x2APICSupported = true;
|
||||
wrmsr(MSR_APIC_BASE, (rdmsr(MSR_APIC_BASE) | (1 << 11)) & ~(1 << 10));
|
||||
BaseStruct.EN = 1;
|
||||
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseStruct.EN = 1;
|
||||
wrmsr(MSR_APIC_BASE, BaseStruct.raw);
|
||||
}
|
||||
|
||||
this->Write(APIC_TPR, 0x0);
|
||||
// this->Write(APIC_SVR, this->Read(APIC_SVR) | 0x100); // 0x1FF or 0x100 ? on https://wiki.osdev.org/APIC is 0x100
|
||||
|
||||
if (!this->x2APICSupported)
|
||||
{
|
||||
this->Write(APIC_DFR, 0xF0000000);
|
||||
this->Write(APIC_LDR, this->Read(APIC_ID));
|
||||
}
|
||||
|
||||
ACPI::MADT *madt = (ACPI::MADT *)PowerManager->GetMADT();
|
||||
|
||||
for (size_t i = 0; i < madt->nmi.size(); i++)
|
||||
{
|
||||
if (madt->nmi[std::size_t(i)]->processor != 0xFF && Core != madt->nmi[std::size_t(i)]->processor)
|
||||
return;
|
||||
|
||||
uint32_t nmi = 0x402;
|
||||
if (madt->nmi[std::size_t(i)]->flags & 2)
|
||||
nmi |= 1 << 13;
|
||||
if (madt->nmi[std::size_t(i)]->flags & 8)
|
||||
nmi |= 1 << 15;
|
||||
if (madt->nmi[std::size_t(i)]->lint == 0)
|
||||
this->Write(APIC_LINT0, nmi);
|
||||
else if (madt->nmi[std::size_t(i)]->lint == 1)
|
||||
this->Write(APIC_LINT1, nmi);
|
||||
}
|
||||
|
||||
// Setup the spurrious interrupt vector
|
||||
Spurious Spurious = {.raw = this->Read(APIC_SVR)};
|
||||
Spurious.Vector = IRQ223; // TODO: Should I map the IRQ to something?
|
||||
Spurious.Software = 1;
|
||||
this->Write(APIC_SVR, s_cst(uint32_t, Spurious.raw));
|
||||
|
||||
static int once = 0;
|
||||
if (!once++)
|
||||
{
|
||||
// Disable PIT
|
||||
outb(0x43, 0x28);
|
||||
outb(0x40, 0x0);
|
||||
|
||||
// Disable PIC
|
||||
outb(0x21, 0xFF);
|
||||
outb(0xA1, 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
APIC::~APIC() {}
|
||||
|
||||
void Timer::OnInterruptReceived(CPU::TrapFrame *Frame) { UNUSED(Frame); }
|
||||
|
||||
void Timer::OneShot(uint32_t Vector, uint64_t Miliseconds)
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
LVTTimer timer = {.raw = 0};
|
||||
timer.Vector = s_cst(uint8_t, Vector);
|
||||
timer.TimerMode = 0;
|
||||
if (strcmp(CPU::Hypervisor(), x86_CPUID_VENDOR_TCG) != 0)
|
||||
this->lapic->Write(APIC_TDCR, DivideBy128);
|
||||
else
|
||||
this->lapic->Write(APIC_TDCR, DivideBy16);
|
||||
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks * Miliseconds));
|
||||
this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw));
|
||||
}
|
||||
|
||||
Timer::Timer(APIC *apic) : Interrupts::Handler(0) /* IRQ0 */
|
||||
{
|
||||
SmartCriticalSection(APICLock);
|
||||
this->lapic = apic;
|
||||
LVTTimerDivide Divider = DivideBy16;
|
||||
|
||||
trace("Initializing APIC timer on CPU %d", GetCurrentCPU()->ID);
|
||||
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, 0xFFFFFFFF);
|
||||
|
||||
TimeManager->Sleep(1, Time::Units::Milliseconds);
|
||||
|
||||
// Mask the timer
|
||||
this->lapic->Write(APIC_TIMER, 0x10000 /* LVTTimer.Mask flag */);
|
||||
Ticks = 0xFFFFFFFF - this->lapic->Read(APIC_TCCR);
|
||||
|
||||
// Config for IRQ0 timer
|
||||
LVTTimer timer = {.raw = 0};
|
||||
timer.Vector = IRQ0;
|
||||
timer.Mask = Unmasked;
|
||||
timer.TimerMode = LVTTimerMode::OneShot;
|
||||
|
||||
// Initialize APIC timer
|
||||
this->lapic->Write(APIC_TDCR, Divider);
|
||||
this->lapic->Write(APIC_TICR, s_cst(uint32_t, Ticks));
|
||||
this->lapic->Write(APIC_TIMER, s_cst(uint32_t, timer.raw));
|
||||
trace("%d APIC Timer %d ticks in.", GetCurrentCPU()->ID, Ticks);
|
||||
KPrint("APIC Timer: \x1b[1;32m%ld\x1b[0m ticks.", Ticks);
|
||||
}
|
||||
|
||||
Timer::~Timer()
|
||||
{
|
||||
}
|
||||
}
|
356
Kernel/arch/i386/cpu/apic.hpp
Normal file
356
Kernel/arch/i386/cpu/apic.hpp
Normal file
@ -0,0 +1,356 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_KERNEL_APIC_H__
|
||||
#define __FENNIX_KERNEL_APIC_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <ints.hpp>
|
||||
#include <cpu.hpp>
|
||||
|
||||
namespace APIC
|
||||
{
|
||||
enum APICRegisters
|
||||
{
|
||||
// source from: https://github.com/pdoane/osdev/blob/master/intr/local_apic.c
|
||||
APIC_ID = 0x20, // Local APIC ID
|
||||
APIC_VER = 0x30, // Local APIC Version
|
||||
APIC_TPR = 0x80, // Task Priority
|
||||
APIC_APR = 0x90, // Arbitration Priority
|
||||
APIC_PPR = 0xA0, // Processor Priority
|
||||
APIC_EOI = 0xB0, // EOI
|
||||
APIC_RRD = 0xC0, // Remote Read
|
||||
APIC_LDR = 0xD0, // Logical Destination
|
||||
APIC_DFR = 0xE0, // Destination Format
|
||||
APIC_SVR = 0xF0, // Spurious Interrupt Vector
|
||||
APIC_ISR = 0x100, // In-Service (8 registers)
|
||||
APIC_TMR = 0x180, // Trigger Mode (8 registers)
|
||||
APIC_IRR = 0x200, // Interrupt Request (8 registers)
|
||||
APIC_ESR = 0x280, // Error Status
|
||||
APIC_ICRLO = 0x300, // Interrupt Command
|
||||
APIC_ICRHI = 0x310, // Interrupt Command [63:32]
|
||||
APIC_TIMER = 0x320, // LVT Timer
|
||||
APIC_THERMAL = 0x330, // LVT Thermal Sensor
|
||||
APIC_PERF = 0x340, // LVT Performance Counter
|
||||
APIC_LINT0 = 0x350, // LVT LINT0
|
||||
APIC_LINT1 = 0x360, // LVT LINT1
|
||||
APIC_ERROR = 0x370, // LVT Error
|
||||
APIC_TICR = 0x380, // Initial Count (for Timer)
|
||||
APIC_TCCR = 0x390, // Current Count (for Timer)
|
||||
APIC_TDCR = 0x3E0, // Divide Configuration (for Timer)
|
||||
};
|
||||
|
||||
enum IOAPICRegisters
|
||||
{
|
||||
GetIOAPICVersion = 0x1
|
||||
};
|
||||
|
||||
enum IOAPICFlags
|
||||
{
|
||||
ActiveHighLow = 2,
|
||||
EdgeLevel = 8
|
||||
};
|
||||
|
||||
enum APICDeliveryMode
|
||||
{
|
||||
Fixed = 0b000,
|
||||
LowestPriority = 0b001, /* Reserved */
|
||||
SMI = 0b010,
|
||||
APIC_DELIVERY_MODE_RESERVED0 = 0b011, /* Reserved */
|
||||
NMI = 0b100,
|
||||
INIT = 0b101,
|
||||
Startup = 0b110,
|
||||
ExtINT = 0b111 /* Reserved */
|
||||
};
|
||||
|
||||
enum APICDestinationMode
|
||||
{
|
||||
Physical = 0b0,
|
||||
Logical = 0b1
|
||||
};
|
||||
|
||||
enum APICDeliveryStatus
|
||||
{
|
||||
Idle = 0b0,
|
||||
SendPending = 0b1
|
||||
};
|
||||
|
||||
enum APICLevel
|
||||
{
|
||||
DeAssert = 0b0,
|
||||
Assert = 0b1
|
||||
};
|
||||
|
||||
enum APICTriggerMode
|
||||
{
|
||||
Edge = 0b0,
|
||||
Level = 0b1
|
||||
};
|
||||
|
||||
enum APICDestinationShorthand
|
||||
{
|
||||
NoShorthand = 0b00,
|
||||
Self = 0b01,
|
||||
AllIncludingSelf = 0b10,
|
||||
AllExcludingSelf = 0b11
|
||||
};
|
||||
|
||||
enum LVTTimerDivide
|
||||
{
|
||||
DivideBy2 = 0b000,
|
||||
DivideBy4 = 0b001,
|
||||
DivideBy8 = 0b010,
|
||||
DivideBy16 = 0b011,
|
||||
DivideBy32 = 0b100,
|
||||
DivideBy64 = 0b101,
|
||||
DivideBy128 = 0b110,
|
||||
DivideBy1 = 0b111
|
||||
};
|
||||
|
||||
enum LVTTimerMask
|
||||
{
|
||||
Unmasked = 0b0,
|
||||
Masked = 0b1
|
||||
};
|
||||
|
||||
enum LVTTimerMode
|
||||
{
|
||||
OneShot = 0b00,
|
||||
Periodic = 0b01,
|
||||
TSCDeadline = 0b10
|
||||
};
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Interrupt Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 4;
|
||||
/**
|
||||
* @brief Delivery Status
|
||||
*
|
||||
* 0: Idle
|
||||
* 1: Send Pending
|
||||
*/
|
||||
uint64_t DeliveryStatus : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 3;
|
||||
/**
|
||||
* @brief Mask
|
||||
*
|
||||
* 0: Not masked
|
||||
* 1: Masked
|
||||
*/
|
||||
uint64_t Mask : 1;
|
||||
/** @brief Timer Mode
|
||||
*
|
||||
* 0: One-shot
|
||||
* 1: Periodic
|
||||
* 2: TSC-Deadline
|
||||
*/
|
||||
uint64_t TimerMode : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved2 : 14;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __packed LVTTimer;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Spurious Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Enable or disable APIC software */
|
||||
uint64_t Software : 1;
|
||||
/** @brief Focus Processor Checking */
|
||||
uint64_t FocusProcessorChecking : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved : 2;
|
||||
/** @brief Disable EOI Broadcast */
|
||||
uint64_t DisableEOIBroadcast : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 19;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __packed Spurious;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Interrupt Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Delivery Mode */
|
||||
uint64_t DeliveryMode : 3;
|
||||
/** @brief Destination Mode
|
||||
*
|
||||
* 0: Physical
|
||||
* 1: Logical
|
||||
*/
|
||||
uint64_t DestinationMode : 1;
|
||||
/** @brief Delivery Status
|
||||
*
|
||||
* @note Reserved when in x2APIC mode
|
||||
*/
|
||||
uint64_t DeliveryStatus : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 1;
|
||||
/** @brief Level
|
||||
*
|
||||
* 0: Deassert
|
||||
* 1: Assert
|
||||
*/
|
||||
uint64_t Level : 1;
|
||||
/** @brief Trigger Mode
|
||||
*
|
||||
* 0: Edge
|
||||
* 1: Level
|
||||
*/
|
||||
uint64_t TriggerMode : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 2;
|
||||
/** @brief Destination Shorthand
|
||||
*
|
||||
* 0: No shorthand
|
||||
* 1: Self
|
||||
* 2: All including self
|
||||
* 3: All excluding self
|
||||
*/
|
||||
uint64_t DestinationShorthand : 2;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved2 : 12;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __packed InterruptCommandRegisterLow;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 24;
|
||||
/** @brief Destination */
|
||||
uint64_t Destination : 8;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __packed InterruptCommandRegisterHigh;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Interrupt Vector */
|
||||
uint64_t Vector : 8;
|
||||
/** @brief Delivery Mode */
|
||||
uint64_t DeliveryMode : 3;
|
||||
/** @brief Destination Mode
|
||||
*
|
||||
* 0: Physical
|
||||
* 1: Logical
|
||||
*/
|
||||
uint64_t DestinationMode : 1;
|
||||
/** @brief Delivery Status */
|
||||
uint64_t DeliveryStatus : 1;
|
||||
/** @brief Interrupt Input Pin Polarity
|
||||
*
|
||||
* 0: Active High
|
||||
* 1: Active Low
|
||||
*/
|
||||
uint64_t Polarity : 1;
|
||||
/** @brief Remote IRR */
|
||||
uint64_t RemoteIRR : 1;
|
||||
/** @brief Trigger Mode
|
||||
*
|
||||
* 0: Edge
|
||||
* 1: Level
|
||||
*/
|
||||
uint64_t TriggerMode : 1;
|
||||
/** @brief Mask */
|
||||
uint64_t Mask : 1;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved0 : 15;
|
||||
/** @brief Reserved */
|
||||
uint64_t Reserved1 : 24;
|
||||
/** @brief Destination */
|
||||
uint64_t DestinationID : 8;
|
||||
};
|
||||
struct
|
||||
{
|
||||
uint64_t Low;
|
||||
uint64_t High;
|
||||
} split;
|
||||
uint64_t raw;
|
||||
} __packed IOAPICRedirectEntry;
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint64_t Version : 8;
|
||||
uint64_t Reserved : 8;
|
||||
uint64_t MaximumRedirectionEntry : 8;
|
||||
uint64_t Reserved2 : 8;
|
||||
};
|
||||
uint64_t raw;
|
||||
} __packed IOAPICVersion;
|
||||
|
||||
class APIC
|
||||
{
|
||||
private:
|
||||
bool x2APICSupported = false;
|
||||
uint64_t APICBaseAddress = 0;
|
||||
|
||||
public:
|
||||
decltype(x2APICSupported) &x2APIC = x2APICSupported;
|
||||
|
||||
uint32_t Read(uint32_t Register);
|
||||
void Write(uint32_t Register, uint32_t Value);
|
||||
void IOWrite(uint64_t Base, uint32_t Register, uint32_t Value);
|
||||
uint32_t IORead(uint64_t Base, uint32_t Register);
|
||||
void EOI();
|
||||
void RedirectIRQs(int CPU = 0);
|
||||
void WaitForIPI();
|
||||
void IPI(uint8_t CPU, InterruptCommandRegisterLow icr);
|
||||
void SendInitIPI(uint8_t CPU);
|
||||
void SendStartupIPI(uint8_t CPU, uint64_t StartupAddress);
|
||||
uint32_t IOGetMaxRedirect(uint32_t APICID);
|
||||
void RawRedirectIRQ(uint16_t Vector, uint32_t GSI, uint16_t Flags, int CPU, int Status);
|
||||
void RedirectIRQ(int CPU, uint16_t IRQ, int Status);
|
||||
APIC(int Core);
|
||||
~APIC();
|
||||
};
|
||||
|
||||
class Timer : public Interrupts::Handler
|
||||
{
|
||||
private:
|
||||
APIC *lapic;
|
||||
uint64_t Ticks = 0;
|
||||
void OnInterruptReceived(CPU::TrapFrame *Frame);
|
||||
|
||||
public:
|
||||
uint64_t GetTicks() { return Ticks; }
|
||||
void OneShot(uint32_t Vector, uint64_t Miliseconds);
|
||||
Timer(APIC *apic);
|
||||
~Timer();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_APIC_H__
|
262
Kernel/arch/i386/cpu/gdt.cpp
Normal file
262
Kernel/arch/i386/cpu/gdt.cpp
Normal file
@ -0,0 +1,262 @@
|
||||
/*
|
||||
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 "gdt.hpp"
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <smp.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
namespace GlobalDescriptorTable
|
||||
{
|
||||
static GlobalDescriptorTableEntries GDTEntriesTemplate = {
|
||||
.Null =
|
||||
{
|
||||
.Limit0 = 0x0,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {.Raw = 0x0},
|
||||
// .Limit1 = 0x0,
|
||||
.Flags = {.Raw = 0x0},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.Code =
|
||||
{
|
||||
.Limit0 = 0xFFFF,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {
|
||||
.A = 0,
|
||||
.RW = 1,
|
||||
.DC = 0,
|
||||
.E = 1,
|
||||
.S = 1,
|
||||
.DPL = 0,
|
||||
.P = 1,
|
||||
},
|
||||
// .Limit1 = 0xF,
|
||||
.Flags = {
|
||||
.Reserved = 0xF, /* Workaround for Limit1 */
|
||||
|
||||
.AVL = 0,
|
||||
.L = 0,
|
||||
.DB = 1,
|
||||
.G = 1,
|
||||
},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.Data = {
|
||||
.Limit0 = 0xFFFF,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {
|
||||
.A = 0,
|
||||
.RW = 1,
|
||||
.DC = 0,
|
||||
.E = 0,
|
||||
.S = 1,
|
||||
.DPL = 0,
|
||||
.P = 1,
|
||||
},
|
||||
// .Limit1 = 0xF,
|
||||
.Flags = {
|
||||
.Reserved = 0xF, /* Workaround for Limit1 */
|
||||
|
||||
.AVL = 0,
|
||||
.L = 0,
|
||||
.DB = 1,
|
||||
.G = 1,
|
||||
},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.UserData = {
|
||||
.Limit0 = 0xFFFF,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {
|
||||
.A = 0,
|
||||
.RW = 1,
|
||||
.DC = 0,
|
||||
.E = 0,
|
||||
.S = 1,
|
||||
.DPL = 3,
|
||||
.P = 1,
|
||||
},
|
||||
// .Limit1 = 0xF,
|
||||
.Flags = {
|
||||
.Reserved = 0xF, /* Workaround for Limit1 */
|
||||
|
||||
.AVL = 0,
|
||||
.L = 0,
|
||||
.DB = 1,
|
||||
.G = 1,
|
||||
},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.UserCode = {
|
||||
.Limit0 = 0xFFFF,
|
||||
.BaseLow = 0x0,
|
||||
.BaseMiddle = 0x0,
|
||||
.Access = {
|
||||
.A = 0,
|
||||
.RW = 1,
|
||||
.DC = 0,
|
||||
.E = 1,
|
||||
.S = 1,
|
||||
.DPL = 3,
|
||||
.P = 1,
|
||||
},
|
||||
// .Limit1 = 0xF,
|
||||
.Flags = {
|
||||
.Reserved = 0xF, /* Workaround for Limit1 */
|
||||
|
||||
.AVL = 0,
|
||||
.L = 0,
|
||||
.DB = 1,
|
||||
.G = 1,
|
||||
},
|
||||
.BaseHigh = 0x0,
|
||||
},
|
||||
|
||||
.TaskStateSegment = {},
|
||||
};
|
||||
|
||||
GlobalDescriptorTableEntries GDTEntries[MAX_CPU] __aligned(16);
|
||||
GlobalDescriptorTableDescriptor gdt[MAX_CPU] __aligned(16);
|
||||
|
||||
TaskStateSegment tss[MAX_CPU] = {
|
||||
0,
|
||||
{0, 0, 0},
|
||||
0,
|
||||
{0, 0, 0, 0, 0, 0, 0},
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
void *CPUStackPointer[MAX_CPU];
|
||||
|
||||
nsa void Init(int Core)
|
||||
{
|
||||
memcpy(&GDTEntries[Core], &GDTEntriesTemplate, sizeof(GlobalDescriptorTableEntries));
|
||||
gdt[Core] = {.Length = sizeof(GlobalDescriptorTableEntries) - 1, .Entries = &GDTEntries[Core]};
|
||||
|
||||
debug("GDT: %#lx", &gdt[Core]);
|
||||
debug("GDT KERNEL: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
|
||||
GDT_KERNEL_CODE,
|
||||
GDTEntries[Core].Code.Limit0,
|
||||
GDTEntries[Core].Code.BaseLow,
|
||||
GDTEntries[Core].Code.BaseMiddle,
|
||||
GDTEntries[Core].Code.Access.Raw,
|
||||
GDTEntries[Core].Code.Flags.Reserved,
|
||||
GDTEntries[Core].Code.Flags.Raw & ~0xF,
|
||||
GDTEntries[Core].Code.BaseHigh);
|
||||
|
||||
debug("GDT KERNEL: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
|
||||
GDT_KERNEL_DATA,
|
||||
GDTEntries[Core].Data.Limit0,
|
||||
GDTEntries[Core].Data.BaseLow,
|
||||
GDTEntries[Core].Data.BaseMiddle,
|
||||
GDTEntries[Core].Data.Access.Raw,
|
||||
GDTEntries[Core].Data.Flags.Reserved,
|
||||
GDTEntries[Core].Data.Flags.Raw & ~0xF,
|
||||
GDTEntries[Core].Data.BaseHigh);
|
||||
|
||||
debug("GDT USER: CODE %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
|
||||
GDT_USER_CODE,
|
||||
GDTEntries[Core].UserCode.Limit0,
|
||||
GDTEntries[Core].UserCode.BaseLow,
|
||||
GDTEntries[Core].UserCode.BaseMiddle,
|
||||
GDTEntries[Core].UserCode.Access.Raw,
|
||||
GDTEntries[Core].UserCode.Flags.Reserved,
|
||||
GDTEntries[Core].UserCode.Flags.Raw & ~0xF,
|
||||
GDTEntries[Core].UserCode.BaseHigh);
|
||||
|
||||
debug("GDT USER: DATA %#lx: Limit0: 0x%X, BaseLow: 0x%X, BaseMiddle: 0x%X, Access: 0x%X, Limit1: 0x%X, Flags: 0x%X, BaseHigh: 0x%X",
|
||||
GDT_USER_DATA,
|
||||
GDTEntries[Core].UserData.Limit0,
|
||||
GDTEntries[Core].UserData.BaseLow,
|
||||
GDTEntries[Core].UserData.BaseMiddle,
|
||||
GDTEntries[Core].UserData.Access.Raw,
|
||||
GDTEntries[Core].UserData.Flags.Reserved,
|
||||
GDTEntries[Core].UserData.Flags.Raw & ~0xF,
|
||||
GDTEntries[Core].UserData.BaseHigh);
|
||||
|
||||
CPU::x32::lgdt(&gdt[Core]);
|
||||
|
||||
asmv("mov %%esp, %%eax\n"
|
||||
"push $16\n"
|
||||
"push %%eax\n"
|
||||
"pushf\n"
|
||||
"push $8\n"
|
||||
"push $1f\n"
|
||||
"iret\n"
|
||||
"1:\n"
|
||||
"movw $16, %%ax\n"
|
||||
"movw %%ax, %%ds\n"
|
||||
"movw %%ax, %%es\n" ::
|
||||
: "memory", "eax");
|
||||
|
||||
CPUStackPointer[Core] = StackManager.Allocate(STACK_SIZE);
|
||||
memset(CPUStackPointer[Core], 0, STACK_SIZE);
|
||||
debug("CPU %d Stack Pointer: %#lx-%#lx (%d pages)", Core,
|
||||
CPUStackPointer[Core], (uintptr_t)CPUStackPointer[Core] + STACK_SIZE,
|
||||
TO_PAGES(STACK_SIZE + 1));
|
||||
|
||||
uintptr_t Base = (uintptr_t)&tss[Core];
|
||||
size_t Limit = Base + sizeof(TaskStateSegment);
|
||||
gdt[Core].Entries->TaskStateSegment.Limit = Limit & 0xFFFF;
|
||||
gdt[Core].Entries->TaskStateSegment.BaseLow = Base & 0xFFFF;
|
||||
gdt[Core].Entries->TaskStateSegment.BaseMiddle = uint8_t((Base >> 16) & 0xFF);
|
||||
gdt[Core].Entries->TaskStateSegment.BaseHigh = uint8_t((Base >> 24) & 0xFF);
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wshift-count-overflow"
|
||||
gdt[Core].Entries->TaskStateSegment.BaseUpper = s_cst(uint32_t, (Base >> 32) & 0xFFFFFFFF);
|
||||
|
||||
gdt[Core].Entries->TaskStateSegment.Access = {.A = 1, .RW = 0, .DC = 0, .E = 1, .S = 0, .DPL = 0, .P = 1};
|
||||
gdt[Core].Entries->TaskStateSegment.Granularity = (0 << 4) | ((Limit >> 16) & 0xF);
|
||||
|
||||
tss[Core].IOMapBaseAddressOffset = sizeof(TaskStateSegment);
|
||||
tss[Core].StackPointer[0] = (uint32_t)CPUStackPointer[Core] + STACK_SIZE;
|
||||
tss[Core].StackPointer[1] = 0x0;
|
||||
tss[Core].StackPointer[2] = 0x0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(tss[Core].InterruptStackTable) / sizeof(tss[Core].InterruptStackTable[7]); i++)
|
||||
{
|
||||
void *NewStack = StackManager.Allocate(STACK_SIZE);
|
||||
|
||||
tss[Core].InterruptStackTable[i] = (uint32_t)NewStack + STACK_SIZE;
|
||||
memset((void *)(tss[Core].InterruptStackTable[i] - STACK_SIZE), 0, STACK_SIZE);
|
||||
debug("IST-%d: %#lx-%#lx", i, NewStack, (uintptr_t)NewStack + STACK_SIZE);
|
||||
}
|
||||
|
||||
CPU::x32::ltr(GDT_TSS);
|
||||
debug("Global Descriptor Table initialized");
|
||||
}
|
||||
|
||||
nsa void SetKernelStack(void *Stack)
|
||||
{
|
||||
stub;
|
||||
}
|
||||
|
||||
void *GetKernelStack() { return (void *)nullptr; }
|
||||
}
|
224
Kernel/arch/i386/cpu/gdt.hpp
Normal file
224
Kernel/arch/i386/cpu/gdt.hpp
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_KERNEL_GDT_H__
|
||||
#define __FENNIX_KERNEL_GDT_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
namespace GlobalDescriptorTable
|
||||
{
|
||||
struct TaskStateSegmentEntry
|
||||
{
|
||||
/* LOW */
|
||||
uint16_t Limit;
|
||||
uint16_t BaseLow;
|
||||
uint8_t BaseMiddle;
|
||||
union GlobalDescriptorTableAccess
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Access bit.
|
||||
* @note The CPU sets this bit to 1 when the segment is accessed.
|
||||
*/
|
||||
uint8_t A : 1;
|
||||
|
||||
/** @brief Readable bit for code segments, writable bit for data segments.
|
||||
* @details For code segments, this bit must be 1 for the segment to be readable.
|
||||
* @details For data segments, this bit must be 1 for the segment to be writable.
|
||||
*/
|
||||
uint8_t RW : 1;
|
||||
|
||||
/** @brief Direction bit for data segments, conforming bit for code segments.
|
||||
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
|
||||
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
|
||||
*/
|
||||
uint8_t DC : 1;
|
||||
|
||||
/** @brief Executable bit.
|
||||
* @details This bit must be 1 for code-segment descriptors.
|
||||
* @details This bit must be 0 for data-segment and system descriptors.
|
||||
*/
|
||||
uint8_t E : 1;
|
||||
|
||||
/** @brief Descriptor type.
|
||||
* @details This bit must be 0 for system descriptors.
|
||||
* @details This bit must be 1 for code or data segment descriptor.
|
||||
*/
|
||||
uint8_t S : 1;
|
||||
|
||||
/** @brief Descriptor privilege level.
|
||||
* @details This field determines the privilege level of the segment.
|
||||
* @details 0 = kernel mode, 3 = user mode.
|
||||
*/
|
||||
uint8_t DPL : 2;
|
||||
|
||||
/** @brief Present bit.
|
||||
* @details This bit must be 1 for all valid descriptors.
|
||||
*/
|
||||
uint8_t P : 1;
|
||||
} __packed;
|
||||
uint8_t Raw : 8;
|
||||
} Access;
|
||||
uint8_t Granularity;
|
||||
uint8_t BaseHigh;
|
||||
/* HIGH */
|
||||
uint32_t BaseUpper;
|
||||
uint32_t Reserved;
|
||||
} __packed;
|
||||
|
||||
struct TaskStateSegment
|
||||
{
|
||||
uint32_t Reserved0 __aligned(16);
|
||||
uint64_t StackPointer[3];
|
||||
uint64_t Reserved1;
|
||||
uint64_t InterruptStackTable[7];
|
||||
uint64_t Reserved2;
|
||||
uint16_t Reserved3;
|
||||
uint16_t IOMapBaseAddressOffset;
|
||||
} __packed;
|
||||
|
||||
struct GlobalDescriptorTableEntry
|
||||
{
|
||||
/** @brief Limit 0:15 */
|
||||
uint16_t Limit0 : 16;
|
||||
|
||||
/** @brief Low Base 0:15 */
|
||||
uint16_t BaseLow : 16;
|
||||
|
||||
/** @brief Middle Base 16:23 */
|
||||
uint8_t BaseMiddle : 8;
|
||||
|
||||
/** @brief Access */
|
||||
union GlobalDescriptorTableAccess
|
||||
{
|
||||
struct
|
||||
{
|
||||
/** @brief Access bit.
|
||||
* @note The CPU sets this bit to 1 when the segment is accessed.
|
||||
*/
|
||||
uint8_t A : 1;
|
||||
|
||||
/** @brief Readable bit for code segments, writable bit for data segments.
|
||||
* @details For code segments, this bit must be 1 for the segment to be readable.
|
||||
* @details For data segments, this bit must be 1 for the segment to be writable.
|
||||
*/
|
||||
uint8_t RW : 1;
|
||||
|
||||
/** @brief Direction bit for data segments, conforming bit for code segments.
|
||||
* @details For data segments, this bit must be 1 for the segment to grow up (higher addresses).
|
||||
* @details For code segments, this bit must be 1 for code in the segment to be able to be executed from an equal or lower privilege level.
|
||||
*/
|
||||
uint8_t DC : 1;
|
||||
|
||||
/** @brief Executable bit.
|
||||
* @details This bit must be 1 for code-segment descriptors.
|
||||
* @details This bit must be 0 for data-segment and system descriptors.
|
||||
*/
|
||||
uint8_t E : 1;
|
||||
|
||||
/** @brief Descriptor type.
|
||||
* @details This bit must be 0 for system descriptors.
|
||||
* @details This bit must be 1 for code or data segment descriptor.
|
||||
*/
|
||||
uint8_t S : 1;
|
||||
|
||||
/** @brief Descriptor privilege level.
|
||||
* @details This field determines the privilege level of the segment.
|
||||
* @details 0 = kernel mode, 3 = user mode.
|
||||
*/
|
||||
uint8_t DPL : 2;
|
||||
|
||||
/** @brief Present bit.
|
||||
* @details This bit must be 1 for all valid descriptors.
|
||||
*/
|
||||
uint8_t P : 1;
|
||||
} __packed;
|
||||
uint8_t Raw : 8;
|
||||
} Access;
|
||||
|
||||
// /** @brief Limit 16:19 */
|
||||
// uint16_t Limit1 : 4;
|
||||
|
||||
/** @brief Flags */
|
||||
union GlobalDescriptorTableFlags
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t Reserved : 4; /* FIXME: Without this, the kernel crashes. */
|
||||
/** @brief Available bit.
|
||||
* @details This bit is available for use by system software.
|
||||
*/
|
||||
uint8_t AVL : 1;
|
||||
|
||||
/** @brief Long mode.
|
||||
* @details If the long mode bit is clear, the segment is in 32-bit protected mode.
|
||||
* @details If the long mode bit is set, the segment is in 64-bit long mode.
|
||||
*/
|
||||
uint8_t L : 1;
|
||||
|
||||
/** @brief Size flag.
|
||||
* @details If the size bit is clear, the segment is in 16-bit protected mode.
|
||||
* @details If the size bit is set, the segment is in 32-bit protected mode.
|
||||
*/
|
||||
uint8_t DB : 1;
|
||||
|
||||
/** @brief Granularity bit.
|
||||
* @details If the granularity bit is clear, the segment limit is in 1 B blocks.
|
||||
* @details If the granularity bit is set, the segment limit is in 4 KiB blocks.
|
||||
*/
|
||||
uint8_t G : 1;
|
||||
} __packed;
|
||||
uint8_t Raw : 8;
|
||||
} Flags;
|
||||
|
||||
/** @brief High Base 24:31 */
|
||||
uint8_t BaseHigh : 8;
|
||||
} __packed;
|
||||
|
||||
struct GlobalDescriptorTableEntries
|
||||
{
|
||||
GlobalDescriptorTableEntry Null;
|
||||
GlobalDescriptorTableEntry Code;
|
||||
GlobalDescriptorTableEntry Data;
|
||||
GlobalDescriptorTableEntry UserData;
|
||||
GlobalDescriptorTableEntry UserCode;
|
||||
TaskStateSegmentEntry TaskStateSegment;
|
||||
} __packed;
|
||||
|
||||
struct GlobalDescriptorTableDescriptor
|
||||
{
|
||||
/** @brief GDT entries length */
|
||||
uint16_t Length;
|
||||
/** @brief GDT entries address */
|
||||
GlobalDescriptorTableEntries *Entries;
|
||||
} __packed;
|
||||
|
||||
extern void *CPUStackPointer[];
|
||||
extern TaskStateSegment tss[];
|
||||
void Init(int Core);
|
||||
void SetKernelStack(void *Stack);
|
||||
void *GetKernelStack();
|
||||
}
|
||||
|
||||
#define GDT_KERNEL_CODE offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Code)
|
||||
#define GDT_KERNEL_DATA offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, Data)
|
||||
#define GDT_USER_CODE (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, UserCode) | 3)
|
||||
#define GDT_USER_DATA (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, UserData) | 3)
|
||||
#define GDT_TSS (offsetof(GlobalDescriptorTable::GlobalDescriptorTableEntries, TaskStateSegment) | 3)
|
||||
|
||||
#endif // !__FENNIX_KERNEL_GDT_H__
|
737
Kernel/arch/i386/cpu/idt.cpp
Normal file
737
Kernel/arch/i386/cpu/idt.cpp
Normal file
@ -0,0 +1,737 @@
|
||||
/*
|
||||
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 "idt.hpp"
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <cpu.hpp>
|
||||
#include <debug.h>
|
||||
#include <io.h>
|
||||
|
||||
#include "gdt.hpp"
|
||||
#include "../../../kernel.h"
|
||||
|
||||
/* conversion from 'uint64_t' {aka 'long unsigned int'} to 'unsigned char:2' may change value */
|
||||
#pragma GCC diagnostic ignored "-Wconversion"
|
||||
|
||||
extern "C" void MainInterruptHandler(void *Data);
|
||||
extern "C" void ExceptionHandler(void *Data);
|
||||
|
||||
namespace InterruptDescriptorTable
|
||||
{
|
||||
__aligned(8) static IDTGateDescriptor Entries[0x100];
|
||||
|
||||
__aligned(8) IDTRegister IDTr = {
|
||||
.Limit = sizeof(Entries) - 1,
|
||||
.BaseAddress = Entries,
|
||||
};
|
||||
|
||||
void SetEntry(uint8_t Index,
|
||||
void (*Base)(),
|
||||
GateType Gate,
|
||||
PrivilegeLevelType Ring,
|
||||
bool Present,
|
||||
uint16_t SegmentSelector)
|
||||
{
|
||||
switch (Gate)
|
||||
{
|
||||
case INTERRUPT_GATE_32BIT:
|
||||
{
|
||||
InterruptGate gate{
|
||||
.TargetCodeSegmentOffsetLow = s_cst(uint16_t, ((uint32_t)Base & 0xFFFF)),
|
||||
.TargetCodeSegmentSelector = SegmentSelector,
|
||||
.Reserved0 = 0,
|
||||
.Type = Gate,
|
||||
.Zero = 0,
|
||||
.DescriptorPrivilegeLevel = Ring,
|
||||
.Present = Present,
|
||||
.TargetCodeSegmentOffsetHigh = s_cst(uint16_t, ((uint32_t)Base >> 16)),
|
||||
};
|
||||
Entries[Index].Interrupt = gate;
|
||||
break;
|
||||
}
|
||||
case TRAP_GATE_32BIT:
|
||||
{
|
||||
TrapGate gate{
|
||||
.TargetCodeSegmentOffsetLow = s_cst(uint16_t, ((uint32_t)Base & 0xFFFF)),
|
||||
.TargetCodeSegmentSelector = SegmentSelector,
|
||||
.Reserved0 = 0,
|
||||
.Type = Gate,
|
||||
.Zero = 0,
|
||||
.DescriptorPrivilegeLevel = Ring,
|
||||
.Present = Present,
|
||||
.TargetCodeSegmentOffsetHigh = s_cst(uint16_t, ((uint32_t)Base >> 16)),
|
||||
};
|
||||
Entries[Index].Trap = gate;
|
||||
break;
|
||||
}
|
||||
case AVAILABLE_16BIT_TSS:
|
||||
case LDT:
|
||||
case BUSY_16BIT_TSS:
|
||||
case CALL_GATE_16BIT:
|
||||
case TASK_GATE:
|
||||
case INTERRUPT_GATE_16BIT:
|
||||
case TRAP_GATE_16BIT:
|
||||
case AVAILABLE_32BIT_TSS:
|
||||
case BUSY_32BIT_TSS:
|
||||
case CALL_GATE_32BIT:
|
||||
default:
|
||||
{
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" __naked __used __no_stack_protector __aligned(16) void ExceptionHandlerStub()
|
||||
{
|
||||
asm("cld\n"
|
||||
"cli\n"
|
||||
|
||||
"pusha\n"
|
||||
|
||||
"push %esp\n"
|
||||
"call ExceptionHandler\n"
|
||||
"pop %esp\n"
|
||||
|
||||
"popa\n"
|
||||
|
||||
"add $8, %esp\n"
|
||||
|
||||
"iret");
|
||||
}
|
||||
|
||||
extern "C" __naked __used __no_stack_protector __aligned(16) void InterruptHandlerStub()
|
||||
{
|
||||
asm("cld\n"
|
||||
"cli\n"
|
||||
|
||||
"pusha\n"
|
||||
|
||||
"push %esp\n"
|
||||
"call MainInterruptHandler\n"
|
||||
"pop %esp\n"
|
||||
|
||||
"popa\n"
|
||||
|
||||
"add $8, %esp\n"
|
||||
|
||||
"sti\n"
|
||||
"iret");
|
||||
}
|
||||
|
||||
#pragma region Exceptions
|
||||
|
||||
#define EXCEPTION_HANDLER(num) \
|
||||
__naked __used __no_stack_protector __aligned(16) static void InterruptHandler_##num() \
|
||||
{ \
|
||||
asm("push $0\npush $" #num "\n" \
|
||||
"jmp ExceptionHandlerStub"); \
|
||||
}
|
||||
|
||||
#define EXCEPTION_ERROR_HANDLER(num) \
|
||||
__naked __used __no_stack_protector __aligned(16) static void InterruptHandler_##num() \
|
||||
{ \
|
||||
asm("push $" #num "\n" \
|
||||
"jmp ExceptionHandlerStub"); \
|
||||
}
|
||||
|
||||
#define INTERRUPT_HANDLER(num) \
|
||||
__naked __used __no_stack_protector __aligned(16) void InterruptHandler_##num() \
|
||||
{ \
|
||||
asm("push $0\npush $" #num "\n" \
|
||||
"jmp InterruptHandlerStub\n"); \
|
||||
}
|
||||
|
||||
/* ISR */
|
||||
|
||||
EXCEPTION_HANDLER(0x0);
|
||||
EXCEPTION_HANDLER(0x1);
|
||||
EXCEPTION_HANDLER(0x2);
|
||||
EXCEPTION_HANDLER(0x3);
|
||||
EXCEPTION_HANDLER(0x4);
|
||||
EXCEPTION_HANDLER(0x5);
|
||||
EXCEPTION_HANDLER(0x6);
|
||||
EXCEPTION_HANDLER(0x7);
|
||||
EXCEPTION_ERROR_HANDLER(0x8);
|
||||
EXCEPTION_HANDLER(0x9);
|
||||
EXCEPTION_ERROR_HANDLER(0xa);
|
||||
EXCEPTION_ERROR_HANDLER(0xb);
|
||||
EXCEPTION_ERROR_HANDLER(0xc);
|
||||
EXCEPTION_ERROR_HANDLER(0xd);
|
||||
EXCEPTION_ERROR_HANDLER(0xe);
|
||||
EXCEPTION_HANDLER(0xf);
|
||||
EXCEPTION_ERROR_HANDLER(0x10);
|
||||
EXCEPTION_HANDLER(0x11);
|
||||
EXCEPTION_HANDLER(0x12);
|
||||
EXCEPTION_HANDLER(0x13);
|
||||
EXCEPTION_HANDLER(0x14);
|
||||
EXCEPTION_HANDLER(0x15);
|
||||
EXCEPTION_HANDLER(0x16);
|
||||
EXCEPTION_HANDLER(0x17);
|
||||
EXCEPTION_HANDLER(0x18);
|
||||
EXCEPTION_HANDLER(0x19);
|
||||
EXCEPTION_HANDLER(0x1a);
|
||||
EXCEPTION_HANDLER(0x1b);
|
||||
EXCEPTION_HANDLER(0x1c);
|
||||
EXCEPTION_HANDLER(0x1d);
|
||||
EXCEPTION_HANDLER(0x1e);
|
||||
EXCEPTION_HANDLER(0x1f);
|
||||
|
||||
/* IRQ */
|
||||
|
||||
INTERRUPT_HANDLER(0x20)
|
||||
INTERRUPT_HANDLER(0x21)
|
||||
INTERRUPT_HANDLER(0x22)
|
||||
INTERRUPT_HANDLER(0x23)
|
||||
INTERRUPT_HANDLER(0x24)
|
||||
INTERRUPT_HANDLER(0x25)
|
||||
INTERRUPT_HANDLER(0x26)
|
||||
INTERRUPT_HANDLER(0x27)
|
||||
INTERRUPT_HANDLER(0x28)
|
||||
INTERRUPT_HANDLER(0x29)
|
||||
INTERRUPT_HANDLER(0x2a)
|
||||
INTERRUPT_HANDLER(0x2b)
|
||||
INTERRUPT_HANDLER(0x2c)
|
||||
INTERRUPT_HANDLER(0x2d)
|
||||
INTERRUPT_HANDLER(0x2e)
|
||||
INTERRUPT_HANDLER(0x2f)
|
||||
|
||||
/* Reserved by OS */
|
||||
|
||||
INTERRUPT_HANDLER(0x30)
|
||||
INTERRUPT_HANDLER(0x31)
|
||||
INTERRUPT_HANDLER(0x32)
|
||||
INTERRUPT_HANDLER(0x33)
|
||||
INTERRUPT_HANDLER(0x34)
|
||||
INTERRUPT_HANDLER(0x35)
|
||||
INTERRUPT_HANDLER(0x36)
|
||||
INTERRUPT_HANDLER(0x37)
|
||||
INTERRUPT_HANDLER(0x38)
|
||||
INTERRUPT_HANDLER(0x39)
|
||||
INTERRUPT_HANDLER(0x3a)
|
||||
INTERRUPT_HANDLER(0x3b)
|
||||
INTERRUPT_HANDLER(0x3c)
|
||||
INTERRUPT_HANDLER(0x3d)
|
||||
|
||||
/* Free */
|
||||
|
||||
INTERRUPT_HANDLER(0x3e)
|
||||
INTERRUPT_HANDLER(0x3f)
|
||||
INTERRUPT_HANDLER(0x40)
|
||||
INTERRUPT_HANDLER(0x41)
|
||||
INTERRUPT_HANDLER(0x42)
|
||||
INTERRUPT_HANDLER(0x43)
|
||||
INTERRUPT_HANDLER(0x44)
|
||||
INTERRUPT_HANDLER(0x45)
|
||||
INTERRUPT_HANDLER(0x46)
|
||||
INTERRUPT_HANDLER(0x47)
|
||||
INTERRUPT_HANDLER(0x48)
|
||||
INTERRUPT_HANDLER(0x49)
|
||||
INTERRUPT_HANDLER(0x4a)
|
||||
INTERRUPT_HANDLER(0x4b)
|
||||
INTERRUPT_HANDLER(0x4c)
|
||||
INTERRUPT_HANDLER(0x4d)
|
||||
INTERRUPT_HANDLER(0x4e)
|
||||
INTERRUPT_HANDLER(0x4f)
|
||||
INTERRUPT_HANDLER(0x50)
|
||||
INTERRUPT_HANDLER(0x51)
|
||||
INTERRUPT_HANDLER(0x52)
|
||||
INTERRUPT_HANDLER(0x53)
|
||||
INTERRUPT_HANDLER(0x54)
|
||||
INTERRUPT_HANDLER(0x55)
|
||||
INTERRUPT_HANDLER(0x56)
|
||||
INTERRUPT_HANDLER(0x57)
|
||||
INTERRUPT_HANDLER(0x58)
|
||||
INTERRUPT_HANDLER(0x59)
|
||||
INTERRUPT_HANDLER(0x5a)
|
||||
INTERRUPT_HANDLER(0x5b)
|
||||
INTERRUPT_HANDLER(0x5c)
|
||||
INTERRUPT_HANDLER(0x5d)
|
||||
INTERRUPT_HANDLER(0x5e)
|
||||
INTERRUPT_HANDLER(0x5f)
|
||||
INTERRUPT_HANDLER(0x60)
|
||||
INTERRUPT_HANDLER(0x61)
|
||||
INTERRUPT_HANDLER(0x62)
|
||||
INTERRUPT_HANDLER(0x63)
|
||||
INTERRUPT_HANDLER(0x64)
|
||||
INTERRUPT_HANDLER(0x65)
|
||||
INTERRUPT_HANDLER(0x66)
|
||||
INTERRUPT_HANDLER(0x67)
|
||||
INTERRUPT_HANDLER(0x68)
|
||||
INTERRUPT_HANDLER(0x69)
|
||||
INTERRUPT_HANDLER(0x6a)
|
||||
INTERRUPT_HANDLER(0x6b)
|
||||
INTERRUPT_HANDLER(0x6c)
|
||||
INTERRUPT_HANDLER(0x6d)
|
||||
INTERRUPT_HANDLER(0x6e)
|
||||
INTERRUPT_HANDLER(0x6f)
|
||||
INTERRUPT_HANDLER(0x70)
|
||||
INTERRUPT_HANDLER(0x71)
|
||||
INTERRUPT_HANDLER(0x72)
|
||||
INTERRUPT_HANDLER(0x73)
|
||||
INTERRUPT_HANDLER(0x74)
|
||||
INTERRUPT_HANDLER(0x75)
|
||||
INTERRUPT_HANDLER(0x76)
|
||||
INTERRUPT_HANDLER(0x77)
|
||||
INTERRUPT_HANDLER(0x78)
|
||||
INTERRUPT_HANDLER(0x79)
|
||||
INTERRUPT_HANDLER(0x7a)
|
||||
INTERRUPT_HANDLER(0x7b)
|
||||
INTERRUPT_HANDLER(0x7c)
|
||||
INTERRUPT_HANDLER(0x7d)
|
||||
INTERRUPT_HANDLER(0x7e)
|
||||
INTERRUPT_HANDLER(0x7f)
|
||||
INTERRUPT_HANDLER(0x80)
|
||||
INTERRUPT_HANDLER(0x81)
|
||||
INTERRUPT_HANDLER(0x82)
|
||||
INTERRUPT_HANDLER(0x83)
|
||||
INTERRUPT_HANDLER(0x84)
|
||||
INTERRUPT_HANDLER(0x85)
|
||||
INTERRUPT_HANDLER(0x86)
|
||||
INTERRUPT_HANDLER(0x87)
|
||||
INTERRUPT_HANDLER(0x88)
|
||||
INTERRUPT_HANDLER(0x89)
|
||||
INTERRUPT_HANDLER(0x8a)
|
||||
INTERRUPT_HANDLER(0x8b)
|
||||
INTERRUPT_HANDLER(0x8c)
|
||||
INTERRUPT_HANDLER(0x8d)
|
||||
INTERRUPT_HANDLER(0x8e)
|
||||
INTERRUPT_HANDLER(0x8f)
|
||||
INTERRUPT_HANDLER(0x90)
|
||||
INTERRUPT_HANDLER(0x91)
|
||||
INTERRUPT_HANDLER(0x92)
|
||||
INTERRUPT_HANDLER(0x93)
|
||||
INTERRUPT_HANDLER(0x94)
|
||||
INTERRUPT_HANDLER(0x95)
|
||||
INTERRUPT_HANDLER(0x96)
|
||||
INTERRUPT_HANDLER(0x97)
|
||||
INTERRUPT_HANDLER(0x98)
|
||||
INTERRUPT_HANDLER(0x99)
|
||||
INTERRUPT_HANDLER(0x9a)
|
||||
INTERRUPT_HANDLER(0x9b)
|
||||
INTERRUPT_HANDLER(0x9c)
|
||||
INTERRUPT_HANDLER(0x9d)
|
||||
INTERRUPT_HANDLER(0x9e)
|
||||
INTERRUPT_HANDLER(0x9f)
|
||||
INTERRUPT_HANDLER(0xa0)
|
||||
INTERRUPT_HANDLER(0xa1)
|
||||
INTERRUPT_HANDLER(0xa2)
|
||||
INTERRUPT_HANDLER(0xa3)
|
||||
INTERRUPT_HANDLER(0xa4)
|
||||
INTERRUPT_HANDLER(0xa5)
|
||||
INTERRUPT_HANDLER(0xa6)
|
||||
INTERRUPT_HANDLER(0xa7)
|
||||
INTERRUPT_HANDLER(0xa8)
|
||||
INTERRUPT_HANDLER(0xa9)
|
||||
INTERRUPT_HANDLER(0xaa)
|
||||
INTERRUPT_HANDLER(0xab)
|
||||
INTERRUPT_HANDLER(0xac)
|
||||
INTERRUPT_HANDLER(0xad)
|
||||
INTERRUPT_HANDLER(0xae)
|
||||
INTERRUPT_HANDLER(0xaf)
|
||||
INTERRUPT_HANDLER(0xb0)
|
||||
INTERRUPT_HANDLER(0xb1)
|
||||
INTERRUPT_HANDLER(0xb2)
|
||||
INTERRUPT_HANDLER(0xb3)
|
||||
INTERRUPT_HANDLER(0xb4)
|
||||
INTERRUPT_HANDLER(0xb5)
|
||||
INTERRUPT_HANDLER(0xb6)
|
||||
INTERRUPT_HANDLER(0xb7)
|
||||
INTERRUPT_HANDLER(0xb8)
|
||||
INTERRUPT_HANDLER(0xb9)
|
||||
INTERRUPT_HANDLER(0xba)
|
||||
INTERRUPT_HANDLER(0xbb)
|
||||
INTERRUPT_HANDLER(0xbc)
|
||||
INTERRUPT_HANDLER(0xbd)
|
||||
INTERRUPT_HANDLER(0xbe)
|
||||
INTERRUPT_HANDLER(0xbf)
|
||||
INTERRUPT_HANDLER(0xc0)
|
||||
INTERRUPT_HANDLER(0xc1)
|
||||
INTERRUPT_HANDLER(0xc2)
|
||||
INTERRUPT_HANDLER(0xc3)
|
||||
INTERRUPT_HANDLER(0xc4)
|
||||
INTERRUPT_HANDLER(0xc5)
|
||||
INTERRUPT_HANDLER(0xc6)
|
||||
INTERRUPT_HANDLER(0xc7)
|
||||
INTERRUPT_HANDLER(0xc8)
|
||||
INTERRUPT_HANDLER(0xc9)
|
||||
INTERRUPT_HANDLER(0xca)
|
||||
INTERRUPT_HANDLER(0xcb)
|
||||
INTERRUPT_HANDLER(0xcc)
|
||||
INTERRUPT_HANDLER(0xcd)
|
||||
INTERRUPT_HANDLER(0xce)
|
||||
INTERRUPT_HANDLER(0xcf)
|
||||
INTERRUPT_HANDLER(0xd0)
|
||||
INTERRUPT_HANDLER(0xd1)
|
||||
INTERRUPT_HANDLER(0xd2)
|
||||
INTERRUPT_HANDLER(0xd3)
|
||||
INTERRUPT_HANDLER(0xd4)
|
||||
INTERRUPT_HANDLER(0xd5)
|
||||
INTERRUPT_HANDLER(0xd6)
|
||||
INTERRUPT_HANDLER(0xd7)
|
||||
INTERRUPT_HANDLER(0xd8)
|
||||
INTERRUPT_HANDLER(0xd9)
|
||||
INTERRUPT_HANDLER(0xda)
|
||||
INTERRUPT_HANDLER(0xdb)
|
||||
INTERRUPT_HANDLER(0xdc)
|
||||
INTERRUPT_HANDLER(0xdd)
|
||||
INTERRUPT_HANDLER(0xde)
|
||||
INTERRUPT_HANDLER(0xdf)
|
||||
INTERRUPT_HANDLER(0xe0)
|
||||
INTERRUPT_HANDLER(0xe1)
|
||||
INTERRUPT_HANDLER(0xe2)
|
||||
INTERRUPT_HANDLER(0xe3)
|
||||
INTERRUPT_HANDLER(0xe4)
|
||||
INTERRUPT_HANDLER(0xe5)
|
||||
INTERRUPT_HANDLER(0xe6)
|
||||
INTERRUPT_HANDLER(0xe7)
|
||||
INTERRUPT_HANDLER(0xe8)
|
||||
INTERRUPT_HANDLER(0xe9)
|
||||
INTERRUPT_HANDLER(0xea)
|
||||
INTERRUPT_HANDLER(0xeb)
|
||||
INTERRUPT_HANDLER(0xec)
|
||||
INTERRUPT_HANDLER(0xed)
|
||||
INTERRUPT_HANDLER(0xee)
|
||||
INTERRUPT_HANDLER(0xef)
|
||||
INTERRUPT_HANDLER(0xf0)
|
||||
INTERRUPT_HANDLER(0xf1)
|
||||
INTERRUPT_HANDLER(0xf2)
|
||||
INTERRUPT_HANDLER(0xf3)
|
||||
INTERRUPT_HANDLER(0xf4)
|
||||
INTERRUPT_HANDLER(0xf5)
|
||||
INTERRUPT_HANDLER(0xf6)
|
||||
INTERRUPT_HANDLER(0xf7)
|
||||
INTERRUPT_HANDLER(0xf8)
|
||||
INTERRUPT_HANDLER(0xf9)
|
||||
INTERRUPT_HANDLER(0xfa)
|
||||
INTERRUPT_HANDLER(0xfb)
|
||||
INTERRUPT_HANDLER(0xfc)
|
||||
INTERRUPT_HANDLER(0xfd)
|
||||
INTERRUPT_HANDLER(0xfe)
|
||||
INTERRUPT_HANDLER(0xff)
|
||||
|
||||
#pragma endregion Exceptions
|
||||
|
||||
void Init(int Core)
|
||||
{
|
||||
if (Core == 0) /* Remap PIC using BSP */
|
||||
{
|
||||
// PIC
|
||||
outb(0x20, 0x10 | 0x1);
|
||||
outb(0x80, 0);
|
||||
outb(0xA0, 0x10 | 0x10);
|
||||
outb(0x80, 0);
|
||||
|
||||
outb(0x21, 0x20);
|
||||
outb(0x80, 0);
|
||||
outb(0xA1, 0x28);
|
||||
outb(0x80, 0);
|
||||
|
||||
outb(0x21, 0x04);
|
||||
outb(0x80, 0);
|
||||
outb(0xA1, 0x02);
|
||||
outb(0x80, 0);
|
||||
|
||||
outb(0x21, 1);
|
||||
outb(0x80, 0);
|
||||
outb(0xA1, 1);
|
||||
outb(0x80, 0);
|
||||
|
||||
// Masking and disabling PIC
|
||||
outb(0x21, 0xff);
|
||||
outb(0x80, 0);
|
||||
outb(0xA1, 0xff);
|
||||
}
|
||||
|
||||
/* ISR */
|
||||
|
||||
bool EnableISRs = true;
|
||||
// #ifdef DEBUG
|
||||
EnableISRs = !DebuggerIsAttached;
|
||||
if (!EnableISRs)
|
||||
KPrint("\x1b[34mThe debugger is attached, disabling all ISRs.");
|
||||
// #endif
|
||||
|
||||
SetEntry(0x0, InterruptHandler_0x0, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1, InterruptHandler_0x1, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2, InterruptHandler_0x2, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3, InterruptHandler_0x3, TRAP_GATE_32BIT, RING3, (!DebuggerIsAttached), GDT_KERNEL_CODE); /* Do not handle breakpoints if we are debugging the kernel. */
|
||||
SetEntry(0x4, InterruptHandler_0x4, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5, InterruptHandler_0x5, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6, InterruptHandler_0x6, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7, InterruptHandler_0x7, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8, InterruptHandler_0x8, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9, InterruptHandler_0x9, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa, InterruptHandler_0xa, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb, InterruptHandler_0xb, TRAP_GATE_32BIT, RING0, (!DebuggerIsAttached), GDT_KERNEL_CODE);
|
||||
SetEntry(0xc, InterruptHandler_0xc, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd, InterruptHandler_0xd, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe, InterruptHandler_0xe, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf, InterruptHandler_0xf, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x10, InterruptHandler_0x10, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x11, InterruptHandler_0x11, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x12, InterruptHandler_0x12, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x13, InterruptHandler_0x13, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x14, InterruptHandler_0x14, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x15, InterruptHandler_0x15, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x16, InterruptHandler_0x16, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x17, InterruptHandler_0x17, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x18, InterruptHandler_0x18, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x19, InterruptHandler_0x19, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1a, InterruptHandler_0x1a, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1b, InterruptHandler_0x1b, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1c, InterruptHandler_0x1c, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1d, InterruptHandler_0x1d, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1e, InterruptHandler_0x1e, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
SetEntry(0x1f, InterruptHandler_0x1f, TRAP_GATE_32BIT, RING0, EnableISRs, GDT_KERNEL_CODE);
|
||||
|
||||
/* IRQ */
|
||||
|
||||
SetEntry(0x20, InterruptHandler_0x20, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x21, InterruptHandler_0x21, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x22, InterruptHandler_0x22, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x23, InterruptHandler_0x23, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x24, InterruptHandler_0x24, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x25, InterruptHandler_0x25, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x26, InterruptHandler_0x26, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x27, InterruptHandler_0x27, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x28, InterruptHandler_0x28, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x29, InterruptHandler_0x29, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2a, InterruptHandler_0x2a, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2b, InterruptHandler_0x2b, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2c, InterruptHandler_0x2c, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2d, InterruptHandler_0x2d, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2e, InterruptHandler_0x2e, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x2f, InterruptHandler_0x2f, INTERRUPT_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
|
||||
/* Reserved by OS */
|
||||
|
||||
SetEntry(0x30, InterruptHandler_0x30, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x31, InterruptHandler_0x31, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x32, InterruptHandler_0x32, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x33, InterruptHandler_0x33, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x34, InterruptHandler_0x34, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x35, InterruptHandler_0x35, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x36, InterruptHandler_0x36, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x37, InterruptHandler_0x37, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x38, InterruptHandler_0x38, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x39, InterruptHandler_0x39, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3a, InterruptHandler_0x3a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3b, InterruptHandler_0x3b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3c, InterruptHandler_0x3c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3d, InterruptHandler_0x3d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
|
||||
/* Free */
|
||||
|
||||
SetEntry(0x3e, InterruptHandler_0x3e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x3f, InterruptHandler_0x3f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x40, InterruptHandler_0x40, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x41, InterruptHandler_0x41, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x42, InterruptHandler_0x42, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x43, InterruptHandler_0x43, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x44, InterruptHandler_0x44, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x45, InterruptHandler_0x45, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x46, InterruptHandler_0x46, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x47, InterruptHandler_0x47, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x48, InterruptHandler_0x48, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x49, InterruptHandler_0x49, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4a, InterruptHandler_0x4a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4b, InterruptHandler_0x4b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4c, InterruptHandler_0x4c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4d, InterruptHandler_0x4d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4e, InterruptHandler_0x4e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x4f, InterruptHandler_0x4f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x50, InterruptHandler_0x50, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x51, InterruptHandler_0x51, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x52, InterruptHandler_0x52, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x53, InterruptHandler_0x53, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x54, InterruptHandler_0x54, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x55, InterruptHandler_0x55, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x56, InterruptHandler_0x56, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x57, InterruptHandler_0x57, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x58, InterruptHandler_0x58, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x59, InterruptHandler_0x59, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5a, InterruptHandler_0x5a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5b, InterruptHandler_0x5b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5c, InterruptHandler_0x5c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5d, InterruptHandler_0x5d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5e, InterruptHandler_0x5e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x5f, InterruptHandler_0x5f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x60, InterruptHandler_0x60, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x61, InterruptHandler_0x61, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x62, InterruptHandler_0x62, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x63, InterruptHandler_0x63, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x64, InterruptHandler_0x64, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x65, InterruptHandler_0x65, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x66, InterruptHandler_0x66, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x67, InterruptHandler_0x67, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x68, InterruptHandler_0x68, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x69, InterruptHandler_0x69, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6a, InterruptHandler_0x6a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6b, InterruptHandler_0x6b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6c, InterruptHandler_0x6c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6d, InterruptHandler_0x6d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6e, InterruptHandler_0x6e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x6f, InterruptHandler_0x6f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x70, InterruptHandler_0x70, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x71, InterruptHandler_0x71, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x72, InterruptHandler_0x72, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x73, InterruptHandler_0x73, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x74, InterruptHandler_0x74, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x75, InterruptHandler_0x75, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x76, InterruptHandler_0x76, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x77, InterruptHandler_0x77, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x78, InterruptHandler_0x78, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x79, InterruptHandler_0x79, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7a, InterruptHandler_0x7a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7b, InterruptHandler_0x7b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7c, InterruptHandler_0x7c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7d, InterruptHandler_0x7d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7e, InterruptHandler_0x7e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x7f, InterruptHandler_0x7f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x80, InterruptHandler_0x80, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x81, InterruptHandler_0x81, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x82, InterruptHandler_0x82, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x83, InterruptHandler_0x83, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x84, InterruptHandler_0x84, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x85, InterruptHandler_0x85, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x86, InterruptHandler_0x86, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x87, InterruptHandler_0x87, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x88, InterruptHandler_0x88, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x89, InterruptHandler_0x89, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8a, InterruptHandler_0x8a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8b, InterruptHandler_0x8b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8c, InterruptHandler_0x8c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8d, InterruptHandler_0x8d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8e, InterruptHandler_0x8e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x8f, InterruptHandler_0x8f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x90, InterruptHandler_0x90, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x91, InterruptHandler_0x91, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x92, InterruptHandler_0x92, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x93, InterruptHandler_0x93, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x94, InterruptHandler_0x94, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x95, InterruptHandler_0x95, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x96, InterruptHandler_0x96, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x97, InterruptHandler_0x97, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x98, InterruptHandler_0x98, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x99, InterruptHandler_0x99, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9a, InterruptHandler_0x9a, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9b, InterruptHandler_0x9b, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9c, InterruptHandler_0x9c, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9d, InterruptHandler_0x9d, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9e, InterruptHandler_0x9e, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0x9f, InterruptHandler_0x9f, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa0, InterruptHandler_0xa0, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa1, InterruptHandler_0xa1, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa2, InterruptHandler_0xa2, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa3, InterruptHandler_0xa3, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa4, InterruptHandler_0xa4, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa5, InterruptHandler_0xa5, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa6, InterruptHandler_0xa6, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa7, InterruptHandler_0xa7, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa8, InterruptHandler_0xa8, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xa9, InterruptHandler_0xa9, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xaa, InterruptHandler_0xaa, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xab, InterruptHandler_0xab, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xac, InterruptHandler_0xac, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xad, InterruptHandler_0xad, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xae, InterruptHandler_0xae, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xaf, InterruptHandler_0xaf, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb0, InterruptHandler_0xb0, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb1, InterruptHandler_0xb1, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb2, InterruptHandler_0xb2, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb3, InterruptHandler_0xb3, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb4, InterruptHandler_0xb4, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb5, InterruptHandler_0xb5, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb6, InterruptHandler_0xb6, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb7, InterruptHandler_0xb7, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb8, InterruptHandler_0xb8, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xb9, InterruptHandler_0xb9, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xba, InterruptHandler_0xba, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbb, InterruptHandler_0xbb, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbc, InterruptHandler_0xbc, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbd, InterruptHandler_0xbd, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbe, InterruptHandler_0xbe, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xbf, InterruptHandler_0xbf, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc0, InterruptHandler_0xc0, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc1, InterruptHandler_0xc1, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc2, InterruptHandler_0xc2, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc3, InterruptHandler_0xc3, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc4, InterruptHandler_0xc4, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc5, InterruptHandler_0xc5, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc6, InterruptHandler_0xc6, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc7, InterruptHandler_0xc7, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc8, InterruptHandler_0xc8, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xc9, InterruptHandler_0xc9, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xca, InterruptHandler_0xca, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xcb, InterruptHandler_0xcb, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xcc, InterruptHandler_0xcc, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xcd, InterruptHandler_0xcd, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xce, InterruptHandler_0xce, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xcf, InterruptHandler_0xcf, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd0, InterruptHandler_0xd0, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd1, InterruptHandler_0xd1, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd2, InterruptHandler_0xd2, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd3, InterruptHandler_0xd3, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd4, InterruptHandler_0xd4, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd5, InterruptHandler_0xd5, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd6, InterruptHandler_0xd6, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd7, InterruptHandler_0xd7, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd8, InterruptHandler_0xd8, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xd9, InterruptHandler_0xd9, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xda, InterruptHandler_0xda, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xdb, InterruptHandler_0xdb, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xdc, InterruptHandler_0xdc, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xdd, InterruptHandler_0xdd, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xde, InterruptHandler_0xde, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xdf, InterruptHandler_0xdf, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe0, InterruptHandler_0xe0, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe1, InterruptHandler_0xe1, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe2, InterruptHandler_0xe2, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe3, InterruptHandler_0xe3, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe4, InterruptHandler_0xe4, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe5, InterruptHandler_0xe5, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe6, InterruptHandler_0xe6, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe7, InterruptHandler_0xe7, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe8, InterruptHandler_0xe8, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xe9, InterruptHandler_0xe9, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xea, InterruptHandler_0xea, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xeb, InterruptHandler_0xeb, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xec, InterruptHandler_0xec, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xed, InterruptHandler_0xed, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xee, InterruptHandler_0xee, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xef, InterruptHandler_0xef, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf0, InterruptHandler_0xf0, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf1, InterruptHandler_0xf1, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf2, InterruptHandler_0xf2, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf3, InterruptHandler_0xf3, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf4, InterruptHandler_0xf4, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf5, InterruptHandler_0xf5, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf6, InterruptHandler_0xf6, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf7, InterruptHandler_0xf7, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf8, InterruptHandler_0xf8, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xf9, InterruptHandler_0xf9, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfa, InterruptHandler_0xfa, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfb, InterruptHandler_0xfb, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfc, InterruptHandler_0xfc, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfd, InterruptHandler_0xfd, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xfe, InterruptHandler_0xfe, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
SetEntry(0xff, InterruptHandler_0xff, TRAP_GATE_32BIT, RING0, true, GDT_KERNEL_CODE);
|
||||
CPU::x32::lidt(&IDTr);
|
||||
}
|
||||
}
|
144
Kernel/arch/i386/cpu/idt.hpp
Normal file
144
Kernel/arch/i386/cpu/idt.hpp
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_KERNEL_IDT_H__
|
||||
#define __FENNIX_KERNEL_IDT_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
namespace InterruptDescriptorTable
|
||||
{
|
||||
/**
|
||||
* Manual: AMD Architecture Programmer's Manual Volume 2: System Programming
|
||||
* Subsection: 4.7.4 System Descriptors
|
||||
* Table: 4-5
|
||||
*
|
||||
* @note Reserved values are not listed in the table.
|
||||
*/
|
||||
enum GateType
|
||||
{
|
||||
AVAILABLE_16BIT_TSS = 0b0001,
|
||||
LDT = 0b0010,
|
||||
BUSY_16BIT_TSS = 0b0011,
|
||||
CALL_GATE_16BIT = 0b0100,
|
||||
TASK_GATE = 0b0101,
|
||||
INTERRUPT_GATE_16BIT = 0b0110,
|
||||
TRAP_GATE_16BIT = 0b0111,
|
||||
AVAILABLE_32BIT_TSS = 0b1001,
|
||||
BUSY_32BIT_TSS = 0b1011,
|
||||
CALL_GATE_32BIT = 0b1100,
|
||||
INTERRUPT_GATE_32BIT = 0b1110,
|
||||
TRAP_GATE_32BIT = 0b1111,
|
||||
};
|
||||
|
||||
enum PrivilegeLevelType
|
||||
{
|
||||
RING0 = 0b0,
|
||||
RING1 = 0b1,
|
||||
RING2 = 0b10,
|
||||
RING3 = 0b11,
|
||||
};
|
||||
|
||||
struct LDTDescriptor
|
||||
{
|
||||
/* +0 */
|
||||
uint32_t SegmentLimitLow : 16;
|
||||
uint32_t BaseAddressLow : 16;
|
||||
/* +4 */
|
||||
uint32_t BaseAddressMiddle : 8;
|
||||
uint32_t Type : 4;
|
||||
uint32_t Zero : 1;
|
||||
uint32_t DescriptorPrivilegeLevel : 2;
|
||||
uint32_t Present : 1;
|
||||
uint32_t SegmentLimitHigh : 4;
|
||||
uint32_t Available : 1;
|
||||
uint32_t Zero1 : 2;
|
||||
uint32_t Granularity : 1;
|
||||
uint32_t BaseAddressHigh : 8;
|
||||
} __packed;
|
||||
|
||||
typedef LDTDescriptor TSSDescriptor;
|
||||
|
||||
struct CallGate
|
||||
{
|
||||
/* +0 */
|
||||
uint32_t TargetCodeSegmentOffsetLow : 16;
|
||||
uint32_t TargetCodeSegmentSelector : 16;
|
||||
/* +4 */
|
||||
uint32_t ParameterCount : 4;
|
||||
uint32_t Reserved0 : 3;
|
||||
uint32_t Type : 4;
|
||||
uint32_t Zero : 1;
|
||||
uint32_t DescriptorPrivilegeLevel : 2;
|
||||
uint32_t Present : 1;
|
||||
uint32_t TargetCodeSegmentOffsetHigh : 16;
|
||||
} __packed;
|
||||
|
||||
struct InterruptGate
|
||||
{
|
||||
/* +0 */
|
||||
uint32_t TargetCodeSegmentOffsetLow : 16;
|
||||
uint32_t TargetCodeSegmentSelector : 16;
|
||||
/* +4 */
|
||||
uint32_t Reserved0 : 8;
|
||||
uint32_t Type : 4;
|
||||
uint32_t Zero : 1;
|
||||
uint32_t DescriptorPrivilegeLevel : 2;
|
||||
uint32_t Present : 1;
|
||||
uint32_t TargetCodeSegmentOffsetHigh : 16;
|
||||
} __packed;
|
||||
|
||||
typedef InterruptGate TrapGate;
|
||||
|
||||
struct TaskGate
|
||||
{
|
||||
/* +0 */
|
||||
uint32_t Reserved0 : 16;
|
||||
uint32_t TSSSelector : 16;
|
||||
/* +4 */
|
||||
uint32_t Reserved1 : 8;
|
||||
uint32_t Type : 4;
|
||||
uint32_t Zero : 1;
|
||||
uint32_t DescriptorPrivilegeLevel : 2;
|
||||
uint32_t Present : 1;
|
||||
uint32_t Reserved2 : 16;
|
||||
} __packed;
|
||||
|
||||
union IDTGateDescriptor
|
||||
{
|
||||
InterruptGate Interrupt;
|
||||
TrapGate Trap;
|
||||
CallGate Call;
|
||||
};
|
||||
|
||||
struct IDTRegister
|
||||
{
|
||||
uint16_t Limit;
|
||||
IDTGateDescriptor *BaseAddress;
|
||||
} __packed;
|
||||
|
||||
void SetEntry(uint8_t Index,
|
||||
void (*Base)(),
|
||||
GateType Gate,
|
||||
PrivilegeLevelType Ring,
|
||||
bool Present,
|
||||
uint16_t SegmentSelector);
|
||||
|
||||
void Init(int Core);
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_IDT_H__
|
93
Kernel/arch/i386/cpu/smp.cpp
Normal file
93
Kernel/arch/i386/cpu/smp.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
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 <smp.hpp>
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <acpi.hpp>
|
||||
#include <ints.hpp>
|
||||
#include <assert.h>
|
||||
#include <cpu.hpp>
|
||||
#include <atomic>
|
||||
|
||||
#include "../../../kernel.h"
|
||||
#include "apic.hpp"
|
||||
|
||||
enum SMPTrampolineAddress
|
||||
{
|
||||
PAGE_TABLE = 0x500,
|
||||
START_ADDR = 0x520,
|
||||
STACK = 0x570,
|
||||
GDT = 0x580,
|
||||
IDT = 0x590,
|
||||
CORE = 0x600,
|
||||
TRAMPOLINE_START = 0x2000
|
||||
};
|
||||
|
||||
std::atomic_bool CPUEnabled = false;
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
|
||||
static __aligned(PAGE_SIZE) CPUData CPUs[MAX_CPU] = {0};
|
||||
|
||||
nsa CPUData *GetCPU(long id) { return &CPUs[id]; }
|
||||
|
||||
nsa CPUData *GetCurrentCPU()
|
||||
{
|
||||
if (unlikely(!Interrupts::apic[0]))
|
||||
return &CPUs[0]; /* No APIC means we are on the BSP. */
|
||||
|
||||
APIC::APIC *apic = (APIC::APIC *)Interrupts::apic[0];
|
||||
int CoreID = 0;
|
||||
if (CPUEnabled.load(std::memory_order_acquire) == true)
|
||||
{
|
||||
if (apic->x2APIC)
|
||||
CoreID = int(CPU::x32::rdmsr(CPU::x32::MSR_X2APIC_APICID));
|
||||
else
|
||||
CoreID = apic->Read(APIC::APIC_ID) >> 24;
|
||||
}
|
||||
|
||||
if (unlikely((&CPUs[CoreID])->IsActive != true))
|
||||
{
|
||||
error("CPU %d is not active!", CoreID);
|
||||
assert((&CPUs[0])->IsActive == true); /* We can't continue without the BSP. */
|
||||
return &CPUs[0];
|
||||
}
|
||||
|
||||
assert((&CPUs[CoreID])->Checksum == CPU_DATA_CHECKSUM); /* This should never happen. */
|
||||
return &CPUs[CoreID];
|
||||
}
|
||||
|
||||
namespace SMP
|
||||
{
|
||||
int CPUCores = 0;
|
||||
|
||||
void Initialize(void *_madt)
|
||||
{
|
||||
ACPI::MADT *madt = (ACPI::MADT *)_madt;
|
||||
|
||||
int Cores = madt->CPUCores + 1;
|
||||
|
||||
if (Config.Cores > madt->CPUCores + 1)
|
||||
KPrint("More cores requested than available. Using %d cores", madt->CPUCores + 1);
|
||||
else if (Config.Cores != 0)
|
||||
Cores = Config.Cores;
|
||||
|
||||
CPUCores = Cores;
|
||||
|
||||
fixme("SMP::Initialize() is not implemented!");
|
||||
}
|
||||
}
|
0
Kernel/arch/i386/include/.gitkeep
Normal file
0
Kernel/arch/i386/include/.gitkeep
Normal file
140
Kernel/arch/i386/interrupts/8259PIC.cpp
Normal file
140
Kernel/arch/i386/interrupts/8259PIC.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
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 "pic.hpp"
|
||||
|
||||
#include <io.h>
|
||||
|
||||
namespace PIC
|
||||
{
|
||||
PIC::PIC(uint8_t MasterCommandPort, uint8_t MasterDataPort, uint8_t SlaveCommandPort, uint8_t SlaveDataPort, uint8_t MasterOffset, uint8_t SlaveOffset)
|
||||
{
|
||||
this->MasterCommandPort = MasterCommandPort;
|
||||
this->MasterDataPort = MasterDataPort;
|
||||
this->SlaveCommandPort = SlaveCommandPort;
|
||||
this->SlaveDataPort = SlaveDataPort;
|
||||
this->MasterOffset = MasterOffset;
|
||||
this->SlaveOffset = SlaveOffset;
|
||||
|
||||
MasterMask = 0xFF;
|
||||
SlaveMask = 0xFF;
|
||||
|
||||
// ICW1
|
||||
outb(MasterCommandPort, 0x11);
|
||||
outb(SlaveCommandPort, 0x11);
|
||||
|
||||
// ICW2
|
||||
outb(MasterDataPort, MasterOffset);
|
||||
outb(SlaveDataPort, SlaveOffset);
|
||||
|
||||
// ICW3
|
||||
outb(MasterDataPort, 0x04);
|
||||
outb(SlaveDataPort, 0x02);
|
||||
|
||||
// ICW4
|
||||
outb(MasterDataPort, 0x01);
|
||||
outb(SlaveDataPort, 0x01);
|
||||
|
||||
// OCW1
|
||||
outb(MasterDataPort, MasterMask);
|
||||
outb(SlaveDataPort, SlaveMask);
|
||||
}
|
||||
|
||||
PIC::~PIC()
|
||||
{
|
||||
outb(MasterDataPort, 0xFF);
|
||||
outb(SlaveDataPort, 0xFF);
|
||||
}
|
||||
|
||||
void PIC::Mask(uint8_t IRQ)
|
||||
{
|
||||
uint16_t Port;
|
||||
uint8_t Value;
|
||||
|
||||
if (IRQ < 8)
|
||||
{
|
||||
Port = MasterDataPort;
|
||||
Value = (uint8_t)(MasterMask & ~(1 << IRQ));
|
||||
MasterMask = Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Port = SlaveDataPort;
|
||||
Value = (uint8_t)(SlaveMask & ~(1 << (IRQ - 8)));
|
||||
SlaveMask = Value;
|
||||
}
|
||||
|
||||
outb(Port, Value);
|
||||
}
|
||||
|
||||
void PIC::Unmask(uint8_t IRQ)
|
||||
{
|
||||
uint16_t Port;
|
||||
uint8_t Value;
|
||||
|
||||
if (IRQ < 8)
|
||||
{
|
||||
Port = MasterDataPort;
|
||||
Value = MasterMask | (1 << IRQ);
|
||||
MasterMask = Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Port = SlaveDataPort;
|
||||
Value = SlaveMask | (1 << (IRQ - 8));
|
||||
SlaveMask = Value;
|
||||
}
|
||||
|
||||
outb(Port, Value);
|
||||
}
|
||||
|
||||
void PIC::SendEOI(uint8_t IRQ)
|
||||
{
|
||||
if (IRQ >= 8)
|
||||
outb(SlaveCommandPort, 0x20);
|
||||
|
||||
outb(MasterCommandPort, 0x20);
|
||||
}
|
||||
|
||||
PIT::PIT(uint16_t Port, uint16_t Frequency)
|
||||
{
|
||||
this->Port = Port;
|
||||
this->Frequency = Frequency;
|
||||
}
|
||||
|
||||
PIT::~PIT()
|
||||
{
|
||||
}
|
||||
|
||||
void PIT::PrepareSleep(uint32_t Milliseconds)
|
||||
{
|
||||
uint16_t Divisor = (uint16_t)(1193182 / Frequency);
|
||||
uint8_t Low = (uint8_t)(Divisor & 0xFF);
|
||||
uint8_t High = (uint8_t)((Divisor >> 8) & 0xFF);
|
||||
|
||||
outb(Port + 3, 0x36);
|
||||
outb(Port + 0, Low);
|
||||
outb(Port + 1, High);
|
||||
}
|
||||
|
||||
void PIT::PerformSleep()
|
||||
{
|
||||
uint8_t Value = inb(Port + 0);
|
||||
while (Value != 0)
|
||||
Value = inb(Port + 0);
|
||||
}
|
||||
}
|
59
Kernel/arch/i386/interrupts/pic.hpp
Normal file
59
Kernel/arch/i386/interrupts/pic.hpp
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef __FENNIX_KERNEL_8259PIC_H__
|
||||
#define __FENNIX_KERNEL_8259PIC_H__
|
||||
|
||||
#include <types.h>
|
||||
|
||||
namespace PIC
|
||||
{
|
||||
class PIC
|
||||
{
|
||||
private:
|
||||
uint8_t MasterCommandPort;
|
||||
uint8_t MasterDataPort;
|
||||
uint8_t SlaveCommandPort;
|
||||
uint8_t SlaveDataPort;
|
||||
uint8_t MasterOffset;
|
||||
uint8_t SlaveOffset;
|
||||
uint8_t MasterMask;
|
||||
uint8_t SlaveMask;
|
||||
|
||||
public:
|
||||
PIC(uint8_t MasterCommandPort, uint8_t MasterDataPort, uint8_t SlaveCommandPort, uint8_t SlaveDataPort, uint8_t MasterOffset, uint8_t SlaveOffset);
|
||||
~PIC();
|
||||
void Mask(uint8_t IRQ);
|
||||
void Unmask(uint8_t IRQ);
|
||||
void SendEOI(uint8_t IRQ);
|
||||
};
|
||||
|
||||
class PIT
|
||||
{
|
||||
private:
|
||||
uint16_t Port;
|
||||
uint16_t Frequency;
|
||||
|
||||
public:
|
||||
PIT(uint16_t Port, uint16_t Frequency);
|
||||
~PIT();
|
||||
void PrepareSleep(uint32_t Milliseconds);
|
||||
void PerformSleep();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // !__FENNIX_KERNEL_8259PIC_H__
|
129
Kernel/arch/i386/linker.ld
Normal file
129
Kernel/arch/i386/linker.ld
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT(elf32-i386)
|
||||
OUTPUT_ARCH(i386)
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
PF_R = 0x4;
|
||||
PF_W = 0x2;
|
||||
PF_X = 0x1;
|
||||
|
||||
PHDRS
|
||||
{
|
||||
bootstrap PT_LOAD FLAGS( PF_R | PF_W /*| PF_X*/ );
|
||||
text PT_LOAD FLAGS( PF_R | PF_X );
|
||||
data PT_LOAD FLAGS( PF_R | PF_W );
|
||||
rodata PT_LOAD FLAGS( PF_R );
|
||||
bss PT_LOAD FLAGS( PF_R | PF_W );
|
||||
}
|
||||
|
||||
KERNEL_VMA = 0xC0000000;
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x100000;
|
||||
_bootstrap_start = .;
|
||||
.bootstrap ALIGN(CONSTANT(MAXPAGESIZE)) :
|
||||
{
|
||||
*(.multiboot)
|
||||
*(.multiboot2)
|
||||
*(.bootstrap .bootstrap.*)
|
||||
} :bootstrap
|
||||
_bootstrap_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
. += KERNEL_VMA;
|
||||
|
||||
_kernel_start = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
_kernel_text_start = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
.text ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.text) - KERNEL_VMA)
|
||||
{
|
||||
*(.text .text.*)
|
||||
} :text
|
||||
_kernel_text_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
_kernel_data_start = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
.data ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.data) - KERNEL_VMA)
|
||||
{
|
||||
*(.data .data.*)
|
||||
} :data
|
||||
|
||||
.eh_frame : AT(ADDR(.eh_frame) - KERNEL_VMA) ONLY_IF_RW
|
||||
{
|
||||
KEEP (*(.eh_frame .eh_frame.*))
|
||||
} :data
|
||||
|
||||
.gcc_except_table : AT(ADDR(.gcc_except_table) - KERNEL_VMA) ONLY_IF_RW
|
||||
{
|
||||
KEEP (*(.gcc_except_table .gcc_except_table.*))
|
||||
} :data
|
||||
_kernel_data_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
_kernel_rodata_start = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
.rodata ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.rodata) - KERNEL_VMA)
|
||||
{
|
||||
*(.rodata .rodata.*)
|
||||
} :rodata
|
||||
|
||||
.init_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.init_array) - KERNEL_VMA)
|
||||
{
|
||||
PROVIDE_HIDDEN(__init_array_start = .);
|
||||
KEEP(*(.init_array .ctors))
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
} :rodata
|
||||
|
||||
.fini_array ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.fini_array) - KERNEL_VMA)
|
||||
{
|
||||
PROVIDE_HIDDEN(__fini_array_start = .);
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||
KEEP(*(.fini_array .dtors))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
} :rodata
|
||||
|
||||
.eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - KERNEL_VMA)
|
||||
{
|
||||
*(.eh_frame_hdr .eh_frame_hdr.*)
|
||||
} :rodata
|
||||
|
||||
.eh_frame : AT(ADDR(.eh_frame) - KERNEL_VMA) ONLY_IF_RO
|
||||
{
|
||||
KEEP (*(.eh_frame .eh_frame.*))
|
||||
} :rodata
|
||||
|
||||
.gcc_except_table : AT(ADDR(.gcc_except_table) - KERNEL_VMA) ONLY_IF_RO
|
||||
{
|
||||
KEEP (*(.gcc_except_table .gcc_except_table.*))
|
||||
} :rodata
|
||||
_kernel_rodata_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
_kernel_bss_start = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
.bss ALIGN(CONSTANT(MAXPAGESIZE)) : AT(ADDR(.bss) - KERNEL_VMA)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss .bss.*)
|
||||
} :bss
|
||||
_kernel_bss_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
_kernel_end = ALIGN(CONSTANT(MAXPAGESIZE));
|
||||
|
||||
/DISCARD/ :
|
||||
{
|
||||
*(.comment*)
|
||||
*(.note*)
|
||||
}
|
||||
}
|
91
Kernel/arch/i386/madt.cpp
Normal file
91
Kernel/arch/i386/madt.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
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 "acpi.hpp"
|
||||
|
||||
#include <memory.hpp>
|
||||
#include <debug.h>
|
||||
|
||||
#include "../../kernel.h"
|
||||
|
||||
namespace ACPI
|
||||
{
|
||||
MADT::MADT(ACPI::MADTHeader *madt)
|
||||
{
|
||||
trace("Initializing MADT");
|
||||
CPUCores = 0;
|
||||
LAPICAddress = (LAPIC *)(uintptr_t)madt->LocalControllerAddress;
|
||||
for (uint8_t *ptr = (uint8_t *)(madt->Entries);
|
||||
(uintptr_t)(ptr) < (uintptr_t)(madt) + madt->Header.Length;
|
||||
ptr += *(ptr + 1))
|
||||
{
|
||||
switch (*(ptr))
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (ptr[4] & 1)
|
||||
{
|
||||
lapic.push_back((LocalAPIC *)ptr);
|
||||
KPrint("Local APIC %d (APIC %d) found.", lapic.back()->ACPIProcessorId, lapic.back()->APICId);
|
||||
CPUCores++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
ioapic.push_back((MADTIOApic *)ptr);
|
||||
KPrint("I/O APIC %d (Address %#lx) found.", ioapic.back()->APICID, ioapic.back()->Address);
|
||||
Memory::Virtual(KernelPageTable).Map((void *)(uintptr_t)ioapic.back()->Address, (void *)(uintptr_t)ioapic.back()->Address, Memory::PTFlag::RW | Memory::PTFlag::PCD); // Make sure that the address is mapped.
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
iso.push_back((MADTIso *)ptr);
|
||||
KPrint("ISO (IRQ:%#lx, BUS:%#lx, GSI:%#lx, %s/%s) found.",
|
||||
iso.back()->IRQSource, iso.back()->BuSSource, iso.back()->GSI,
|
||||
iso.back()->Flags & 0x00000004 ? "Active High" : "Active Low",
|
||||
iso.back()->Flags & 0x00000100 ? "Edge Triggered" : "Level Triggered");
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
nmi.push_back((MADTNmi *)ptr);
|
||||
KPrint("NMI %#lx (lint:%#lx) found.", nmi.back()->processor, nmi.back()->lint);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
LAPICAddress = (LAPIC *)ptr;
|
||||
KPrint("APIC found at %#lx", LAPICAddress);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
KPrint("Unknown MADT entry %#lx", *(ptr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
Memory::Virtual(KernelPageTable).Map((void *)LAPICAddress, (void *)LAPICAddress, Memory::PTFlag::RW | Memory::PTFlag::PCD); // I should map more than one page?
|
||||
}
|
||||
CPUCores--; // We start at 0 (BSP) and end at 11 (APs), so we have 12 cores.
|
||||
KPrint("Total CPU cores: %d", CPUCores + 1);
|
||||
}
|
||||
|
||||
MADT::~MADT()
|
||||
{
|
||||
}
|
||||
}
|
226
Kernel/arch/i386/memory/vmm.cpp
Normal file
226
Kernel/arch/i386/memory/vmm.cpp
Normal file
@ -0,0 +1,226 @@
|
||||
/*
|
||||
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 <memory.hpp>
|
||||
|
||||
#include <convert.h>
|
||||
#include <debug.h>
|
||||
|
||||
namespace Memory
|
||||
{
|
||||
bool Virtual::Check(void *VirtualAddress, PTFlag Flag, MapType Type)
|
||||
{
|
||||
// 0x1000 aligned
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex];
|
||||
PageTableEntryPtr *PTE = nullptr;
|
||||
|
||||
if ((PDE->raw & Flag) > 0)
|
||||
{
|
||||
if (Type == MapType::FourMiB && PDE->PageSize)
|
||||
return true;
|
||||
|
||||
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12);
|
||||
if (PTE)
|
||||
{
|
||||
if ((PTE->Entries[Index.PTEIndex].Present))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void *Virtual::GetPhysical(void *VirtualAddress)
|
||||
{
|
||||
// 0x1000 aligned
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex];
|
||||
PageTableEntryPtr *PTE = nullptr;
|
||||
|
||||
if (PDE->Present)
|
||||
{
|
||||
if (PDE->PageSize)
|
||||
return (void *)((uintptr_t)PDE->GetAddress() << 12);
|
||||
|
||||
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12);
|
||||
if (PTE)
|
||||
{
|
||||
if (PTE->Entries[Index.PTEIndex].Present)
|
||||
return (void *)((uintptr_t)PTE->Entries[Index.PTEIndex].GetAddress() << 12);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Virtual::MapType Virtual::GetMapType(void *VirtualAddress)
|
||||
{
|
||||
// 0x1000 aligned
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
|
||||
PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex];
|
||||
PageTableEntryPtr *PTE = nullptr;
|
||||
|
||||
if (PDE->Present)
|
||||
{
|
||||
if (PDE->PageSize)
|
||||
return MapType::FourMiB;
|
||||
|
||||
PTE = (PageTableEntryPtr *)((uintptr_t)PDE->GetAddress() << 12);
|
||||
if (PTE)
|
||||
{
|
||||
if (PTE->Entries[Index.PTEIndex].Present)
|
||||
return MapType::FourKiB;
|
||||
}
|
||||
}
|
||||
return MapType::NoMapType;
|
||||
}
|
||||
|
||||
PageDirectoryEntry *Virtual::GetPDE(void *VirtualAddress, MapType Type)
|
||||
{
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex];
|
||||
if (PDE->Present)
|
||||
return PDE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PageTableEntry *Virtual::GetPTE(void *VirtualAddress, MapType Type)
|
||||
{
|
||||
uintptr_t Address = (uintptr_t)VirtualAddress;
|
||||
Address &= 0xFFFFF000;
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer(Address);
|
||||
PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex];
|
||||
if (!PDE->Present)
|
||||
return nullptr;
|
||||
|
||||
PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12);
|
||||
PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex];
|
||||
if (PTE->Present)
|
||||
return PTE;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags, MapType Type)
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
if (unlikely(!this->Table))
|
||||
{
|
||||
error("No page table");
|
||||
return;
|
||||
}
|
||||
|
||||
Flags |= PTFlag::P;
|
||||
|
||||
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;
|
||||
|
||||
PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex];
|
||||
if (Type == MapType::FourMiB)
|
||||
{
|
||||
PDE->raw |= (uintptr_t)Flags;
|
||||
PDE->PageSize = true;
|
||||
PDE->SetAddress((uintptr_t)PhysicalAddress >> 12);
|
||||
debug("Mapped 4MB page at %p to %p", VirtualAddress, PhysicalAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
PageTableEntryPtr *PTEPtr = nullptr;
|
||||
if (!PDE->Present)
|
||||
{
|
||||
PTEPtr = (PageTableEntryPtr *)KernelAllocator.RequestPages(TO_PAGES(sizeof(PageTableEntryPtr) + 1));
|
||||
memset(PTEPtr, 0, sizeof(PageTableEntryPtr));
|
||||
PDE->Present = true;
|
||||
PDE->SetAddress((uintptr_t)PTEPtr >> 12);
|
||||
}
|
||||
else
|
||||
PTEPtr = (PageTableEntryPtr *)(PDE->GetAddress() << 12);
|
||||
PDE->raw |= (uintptr_t)DirectoryFlags;
|
||||
|
||||
PageTableEntry *PTE = &PTEPtr->Entries[Index.PTEIndex];
|
||||
PTE->Present = true;
|
||||
PTE->raw |= (uintptr_t)Flags;
|
||||
PTE->SetAddress((uintptr_t)PhysicalAddress >> 12);
|
||||
CPU::x32::invlpg(VirtualAddress);
|
||||
|
||||
#ifdef DEBUG
|
||||
/* https://stackoverflow.com/a/3208376/9352057 */
|
||||
#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
|
||||
#define BYTE_TO_BINARY(byte) \
|
||||
(byte & 0x80 ? '1' : '0'), \
|
||||
(byte & 0x40 ? '1' : '0'), \
|
||||
(byte & 0x20 ? '1' : '0'), \
|
||||
(byte & 0x10 ? '1' : '0'), \
|
||||
(byte & 0x08 ? '1' : '0'), \
|
||||
(byte & 0x04 ? '1' : '0'), \
|
||||
(byte & 0x02 ? '1' : '0'), \
|
||||
(byte & 0x01 ? '1' : '0')
|
||||
|
||||
if (!this->Check(VirtualAddress, (PTFlag)Flags, Type)) // quick workaround just to see where it fails
|
||||
warn("Failed to map v:%#lx p:%#lx with flags: " BYTE_TO_BINARY_PATTERN, VirtualAddress, PhysicalAddress, BYTE_TO_BINARY(Flags));
|
||||
#endif
|
||||
}
|
||||
|
||||
void Virtual::Unmap(void *VirtualAddress, MapType Type)
|
||||
{
|
||||
SmartLock(this->MemoryLock);
|
||||
if (!this->Table)
|
||||
{
|
||||
error("No page table");
|
||||
return;
|
||||
}
|
||||
|
||||
PageMapIndexer Index = PageMapIndexer((uintptr_t)VirtualAddress);
|
||||
PageDirectoryEntry *PDE = &this->Table->Entries[Index.PDEIndex];
|
||||
if (!PDE->Present)
|
||||
{
|
||||
warn("Page %#lx not present", PDE->GetAddress());
|
||||
return;
|
||||
}
|
||||
|
||||
if (Type == MapType::FourMiB && PDE->PageSize)
|
||||
{
|
||||
PDE->Present = false;
|
||||
return;
|
||||
}
|
||||
|
||||
PageTableEntryPtr *PTEPtr = (PageTableEntryPtr *)((uintptr_t)PDE->Address << 12);
|
||||
PageTableEntry PTE = PTEPtr->Entries[Index.PTEIndex];
|
||||
if (!PTE.Present)
|
||||
{
|
||||
warn("Page %#lx not present", PTE.GetAddress());
|
||||
return;
|
||||
}
|
||||
|
||||
PTE.Present = false;
|
||||
PTEPtr->Entries[Index.PTEIndex] = PTE;
|
||||
CPU::x32::invlpg(VirtualAddress);
|
||||
}
|
||||
}
|
30
Kernel/arch/i386/syscalls.cpp
Normal file
30
Kernel/arch/i386/syscalls.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
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 <syscalls.hpp>
|
||||
|
||||
#include <cpu.hpp>
|
||||
|
||||
#include "cpu/gdt.hpp"
|
||||
|
||||
using namespace CPU::x32;
|
||||
|
||||
extern "C" uint32_t SystemCallsHandler(SyscallsFrame *regs);
|
||||
|
||||
void InitializeSystemCalls()
|
||||
{
|
||||
}
|
Reference in New Issue
Block a user