feat: add page table
This commit is contained in:
parent
61dfda6a70
commit
ada1859910
8 changed files with 435 additions and 13 deletions
7
kernel/include/apic/core.h
Normal file
7
kernel/include/apic/core.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "memory/pointer.h"
|
||||
|
||||
namespace apic {
|
||||
void startupCore(paddr_t code, paddr_t stack);
|
||||
}
|
||||
36
kernel/include/memory/pagetable.h
Normal file
36
kernel/include/memory/pagetable.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include "memory/pointer.h"
|
||||
#include "util/optional.h"
|
||||
|
||||
struct PageTable {
|
||||
struct flags_t {
|
||||
enum class granularity_t : uint8_t {
|
||||
page_4KiB,
|
||||
page_2MiB,
|
||||
page_1GiB,
|
||||
};
|
||||
|
||||
bool writeable : 1; // allow writes
|
||||
bool user_accessible : 1; // allow ring-3 access
|
||||
bool write_through : 1; // write-through instead of write-back
|
||||
bool cache_disabled : 1; // uncached (MMIO)
|
||||
bool execute_disabled : 1; // forbid instruction fetch
|
||||
bool global : 1; // keep in TLB across CR3 switches
|
||||
granularity_t granularity : 2; // mapping size
|
||||
};
|
||||
struct info_t {
|
||||
flags_t flags;
|
||||
paddr_t address;
|
||||
};
|
||||
|
||||
static PageTable fromCurrent();
|
||||
|
||||
void activate();
|
||||
bool map(void* vaddress, paddr_t paddress, flags_t flags);
|
||||
void unmap(void* vaddress);
|
||||
optional<info_t> get(void* vaddress);
|
||||
|
||||
private:
|
||||
paddr_t l4;
|
||||
};
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
#include "util/number.h"
|
||||
|
||||
constexpr uint64_t high_base = 0xFFFF800000000000;
|
||||
constexpr uint64_t uncached_base = high_base + (uint64_t{1} << 38);
|
||||
|
||||
#define read_symbol(symbol) \
|
||||
[]() { \
|
||||
|
|
@ -18,6 +19,11 @@ struct paddr_t {
|
|||
T* access() {
|
||||
return reinterpret_cast<T*>(address + high_base);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* access_uc() {
|
||||
return reinterpret_cast<T*>(address + uncached_base);
|
||||
}
|
||||
};
|
||||
|
||||
inline void* operator new(size_t, void* p) {
|
||||
|
|
|
|||
|
|
@ -33,13 +33,13 @@ SECTIONS
|
|||
} > START_MEMORY_PV
|
||||
.text : AT(ADDR(.text) - high_base) {
|
||||
__text_start__ = .;
|
||||
*(EXCLUDE_FILE(*trampoline*) .text .text.*)
|
||||
*(EXCLUDE_FILE(*trampoline*) .iplt)
|
||||
*(.text .text.*)
|
||||
*(.iplt)
|
||||
__text_end__ = .;
|
||||
} > HIGH_KERNEL_V
|
||||
.rodata : AT(ADDR(.rodata) - high_base) {
|
||||
__rodata_start__ = .;
|
||||
*(EXCLUDE_FILE(*trampoline*) .rodata .rodata.*)
|
||||
*(.rodata .rodata.*)
|
||||
. = ALIGN(8);
|
||||
__reserved_ranges_start__ = .;
|
||||
KEEP(*(.reserved_ranges))
|
||||
|
|
@ -52,37 +52,37 @@ SECTIONS
|
|||
} > HIGH_KERNEL_V
|
||||
.data : AT(ADDR(.data) - high_base) {
|
||||
__data_start__ = .;
|
||||
*(EXCLUDE_FILE(*trampoline*) .data .data.*)
|
||||
*(EXCLUDE_FILE(*trampoline*) .got .got.plt .igot.plt .data.rel.ro .data.rel.ro.*)
|
||||
*(.data .data.*)
|
||||
*(.got .got.plt .igot.plt .data.rel.ro .data.rel.ro.*)
|
||||
__data_end__ = .;
|
||||
} > HIGH_KERNEL_V
|
||||
.bss (NOLOAD) : AT(ADDR(.bss) - high_base) {
|
||||
__bss_start__ = .;
|
||||
*(EXCLUDE_FILE(*trampoline*) .bss .bss.*)
|
||||
*(.bss .bss.*)
|
||||
__bss_end__ = .;
|
||||
} > HIGH_KERNEL_V
|
||||
|
||||
.trampoline_text : {
|
||||
__trampoline_text_start__ = .;
|
||||
*trampoline*(.text)
|
||||
*(.trampoline_text)
|
||||
__trampoline_text_end__ = .;
|
||||
} > TRAMPOLINE_PV
|
||||
|
||||
.trampoline_data : {
|
||||
__trampoline_data_start__ = .;
|
||||
*trampoline*(.data)
|
||||
*(.trampoline_data)
|
||||
__trampoline_data_end__ = .;
|
||||
} > TRAMPOLINE_PV
|
||||
|
||||
.trampoline_rodata : {
|
||||
__trampoline_rodata_start__ = .;
|
||||
*trampoline*(.rodata)
|
||||
*(.trampoline_rodata)
|
||||
__trampoline_rodata_end__ = .;
|
||||
} > TRAMPOLINE_PV
|
||||
|
||||
.trampoline_bss (NOLOAD) : {
|
||||
__trampoline_bss_start__ = .;
|
||||
*trampoline*(.bss)
|
||||
*(.trampoline_bss)
|
||||
__trampoline_bss_end__ = .;
|
||||
} > TRAMPOLINE_PV
|
||||
|
||||
|
|
|
|||
0
kernel/src/apic/core.cpp
Normal file
0
kernel/src/apic/core.cpp
Normal file
349
kernel/src/memory/pagetable.cpp
Normal file
349
kernel/src/memory/pagetable.cpp
Normal file
|
|
@ -0,0 +1,349 @@
|
|||
#include "memory/pagetable.h"
|
||||
#include "memory/allocator.h"
|
||||
#include "util/function.h"
|
||||
|
||||
template<typename EntryType>
|
||||
struct entry_table_t {
|
||||
EntryType entries[512];
|
||||
};
|
||||
|
||||
struct frame_entry_t {
|
||||
static constexpr size_t level = 1;
|
||||
|
||||
uint64_t present : 1;
|
||||
uint64_t writeable : 1;
|
||||
uint64_t user_accessible : 1;
|
||||
uint64_t write_through : 1;
|
||||
uint64_t cache_disabled : 1;
|
||||
uint64_t accessed : 1;
|
||||
uint64_t dirty : 1;
|
||||
uint64_t page_attribute_table : 1;
|
||||
uint64_t global : 1;
|
||||
uint64_t available_low : 3;
|
||||
uint64_t frame_address : 40;
|
||||
uint64_t available_high : 11;
|
||||
uint64_t execute_disabled : 1;
|
||||
};
|
||||
|
||||
template<typename NextEntryType>
|
||||
struct subtable_entry_t {
|
||||
using next_table_t = entry_table_t<NextEntryType>;
|
||||
static constexpr size_t level = NextEntryType::level + 1;
|
||||
|
||||
uint64_t present : 1;
|
||||
uint64_t writeable : 1;
|
||||
uint64_t user_accessible : 1;
|
||||
uint64_t write_through : 1;
|
||||
uint64_t cache_disabled : 1;
|
||||
uint64_t accessed : 1;
|
||||
uint64_t ignored_dirty : 1;
|
||||
uint64_t huge_page : 1;
|
||||
uint64_t ignored_global : 1;
|
||||
uint64_t available_low : 3;
|
||||
uint64_t table_address : 40;
|
||||
uint64_t available_high : 11;
|
||||
uint64_t execute_disabled : 1;
|
||||
};
|
||||
|
||||
template<size_t level_>
|
||||
struct huge_frame_entry_t {
|
||||
static constexpr size_t level = level_;
|
||||
|
||||
uint64_t present : 1;
|
||||
uint64_t writeable : 1;
|
||||
uint64_t user_accessible : 1;
|
||||
uint64_t write_through : 1;
|
||||
uint64_t cache_disabled : 1;
|
||||
uint64_t accessed : 1;
|
||||
uint64_t dirty : 1;
|
||||
uint64_t huge_page : 1;
|
||||
uint64_t global : 1;
|
||||
uint64_t available_low : 3;
|
||||
uint64_t page_attribute_table : 1;
|
||||
uint64_t frame_address : 39;
|
||||
uint64_t available_high : 11;
|
||||
uint64_t execute_disabled : 1;
|
||||
};
|
||||
|
||||
using frame_2MiB_entry_t = huge_frame_entry_t<2>;
|
||||
using frame_1GiB_entry_t = huge_frame_entry_t<3>;
|
||||
|
||||
template<typename NextEntryType>
|
||||
union table_or_huge_entry_t {
|
||||
static constexpr size_t level = NextEntryType::level + 1;
|
||||
|
||||
subtable_entry_t<NextEntryType> subtable;
|
||||
huge_frame_entry_t<NextEntryType::level + 1> huge;
|
||||
};
|
||||
|
||||
using level1_entry_t = frame_entry_t;
|
||||
using level2_entry_t = table_or_huge_entry_t<level1_entry_t>;
|
||||
using level3_entry_t = table_or_huge_entry_t<level2_entry_t>;
|
||||
using level4_entry_t = table_or_huge_entry_t<level3_entry_t>;
|
||||
|
||||
using level1_table_t = entry_table_t<level1_entry_t>;
|
||||
using level2_table_t = entry_table_t<level2_entry_t>;
|
||||
using level3_table_t = entry_table_t<level3_entry_t>;
|
||||
using level4_table_t = entry_table_t<level4_entry_t>;
|
||||
|
||||
static_assert(sizeof(frame_2MiB_entry_t) == sizeof(uint64_t));
|
||||
static_assert(sizeof(frame_1GiB_entry_t) == sizeof(uint64_t));
|
||||
static_assert(sizeof(level1_entry_t) == sizeof(uint64_t));
|
||||
static_assert(sizeof(level2_entry_t) == sizeof(uint64_t));
|
||||
static_assert(sizeof(level3_entry_t) == sizeof(uint64_t));
|
||||
static_assert(sizeof(level4_entry_t) == sizeof(uint64_t));
|
||||
static_assert(sizeof(level1_table_t) == page_size);
|
||||
static_assert(sizeof(level2_table_t) == page_size);
|
||||
static_assert(sizeof(level3_table_t) == page_size);
|
||||
static_assert(sizeof(level4_table_t) == page_size);
|
||||
|
||||
template<typename NextEntryType>
|
||||
static paddr_t address_of(subtable_entry_t<NextEntryType> entry) {
|
||||
return paddr_t{entry.table_address << 12};
|
||||
}
|
||||
|
||||
static paddr_t address_of(frame_entry_t entry) {
|
||||
return paddr_t{entry.frame_address << 12};
|
||||
}
|
||||
|
||||
template<size_t level_>
|
||||
static paddr_t address_of(huge_frame_entry_t<level_> entry) {
|
||||
return paddr_t{entry.frame_address << 13};
|
||||
}
|
||||
|
||||
template<size_t level>
|
||||
static size_t table_index(void* vaddress) {
|
||||
uint64_t address = reinterpret_cast<uint64_t>(vaddress);
|
||||
return (address >> (12 + 9 * (level - 1))) & 0x1FF;
|
||||
}
|
||||
|
||||
template<typename Fn>
|
||||
static optional<frame_entry_t*> walk(level1_table_t* table, void* vaddress, Fn&& fn) {
|
||||
frame_entry_t& entry = table->entries[table_index<frame_entry_t::level>(vaddress)];
|
||||
if constexpr (requires { fn(entry); }) {
|
||||
fn(entry);
|
||||
}
|
||||
return &entry;
|
||||
}
|
||||
|
||||
struct ascend_t {};
|
||||
|
||||
template<typename NextEntryType, typename Fn>
|
||||
static optional<frame_entry_t*> walk(entry_table_t<table_or_huge_entry_t<NextEntryType>>* table, void* vaddress, Fn&& fn) {
|
||||
using entry_t = table_or_huge_entry_t<NextEntryType>;
|
||||
entry_t& entry = table->entries[table_index<entry_t::level>(vaddress)];
|
||||
if constexpr (requires { fn(entry); }) {
|
||||
fn(entry);
|
||||
}
|
||||
optional<frame_entry_t*> leaf{};
|
||||
if (entry.subtable.present && entry.subtable.huge_page) {
|
||||
if constexpr (requires { fn(entry.huge); }) {
|
||||
fn(entry.huge);
|
||||
}
|
||||
} else if (entry.subtable.present) {
|
||||
leaf = walk(address_of(entry.subtable).template access<entry_table_t<NextEntryType>>(), vaddress, fn);
|
||||
}
|
||||
if constexpr (requires { fn(entry, ascend_t{}); }) {
|
||||
fn(entry, ascend_t{});
|
||||
}
|
||||
return leaf;
|
||||
}
|
||||
|
||||
static bool is_present(frame_entry_t entry) {
|
||||
return entry.present;
|
||||
}
|
||||
|
||||
template<typename NextEntryType>
|
||||
static bool is_present(table_or_huge_entry_t<NextEntryType> entry) {
|
||||
return entry.subtable.present;
|
||||
}
|
||||
|
||||
template<typename EntryType>
|
||||
static bool is_table_empty(entry_table_t<EntryType>* table) {
|
||||
for (EntryType& entry : table->entries) {
|
||||
if (is_present(entry)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename NextEntryType>
|
||||
static void reclaim_if_empty(table_or_huge_entry_t<NextEntryType>& entry) {
|
||||
if (!entry.subtable.present) {
|
||||
return;
|
||||
}
|
||||
if (entry.subtable.huge_page) {
|
||||
return;
|
||||
}
|
||||
entry_table_t<NextEntryType>* child_table = address_of(entry.subtable).template access<entry_table_t<NextEntryType>>();
|
||||
if (!is_table_empty(child_table)) {
|
||||
return;
|
||||
}
|
||||
PhysicalAllocator::getInstance().free({address_of(entry.subtable), 1});
|
||||
entry = table_or_huge_entry_t<NextEntryType>{};
|
||||
}
|
||||
|
||||
template<typename LeafEntryType>
|
||||
static PageTable::flags_t::granularity_t granularity_of() {
|
||||
using granularity_t = PageTable::flags_t::granularity_t;
|
||||
if constexpr (LeafEntryType::level == 1) {
|
||||
return granularity_t::page_4KiB;
|
||||
} else if constexpr (LeafEntryType::level == 2) {
|
||||
return granularity_t::page_2MiB;
|
||||
} else {
|
||||
return granularity_t::page_1GiB;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename LeafEntryType>
|
||||
static PageTable::info_t info_of(LeafEntryType entry, void* vaddress) {
|
||||
PageTable::info_t info{};
|
||||
info.flags.writeable = entry.writeable;
|
||||
info.flags.user_accessible = entry.user_accessible;
|
||||
info.flags.write_through = entry.write_through;
|
||||
info.flags.cache_disabled = entry.cache_disabled;
|
||||
info.flags.execute_disabled = entry.execute_disabled;
|
||||
info.flags.global = entry.global;
|
||||
info.flags.granularity = granularity_of<LeafEntryType>();
|
||||
uint64_t offset_mask = (uint64_t{1} << (12 + 9 * (LeafEntryType::level - 1))) - 1;
|
||||
info.address = paddr_t{address_of(entry).address + (reinterpret_cast<uint64_t>(vaddress) & offset_mask)};
|
||||
return info;
|
||||
}
|
||||
|
||||
static paddr_t current_l4() {
|
||||
uint64_t cr3;
|
||||
asm volatile("mov %%cr3, %0" : "=r"(cr3));
|
||||
return paddr_t{cr3 & ~uint64_t{0xFFF}};
|
||||
}
|
||||
|
||||
static bool is_active(paddr_t l4) {
|
||||
return current_l4().address == l4.address;
|
||||
}
|
||||
|
||||
template<typename LeafEntryType>
|
||||
static void apply_flags(LeafEntryType& entry, PageTable::flags_t flags) {
|
||||
entry.present = 1;
|
||||
entry.writeable = flags.writeable;
|
||||
entry.user_accessible = flags.user_accessible;
|
||||
entry.write_through = flags.write_through;
|
||||
entry.cache_disabled = flags.cache_disabled;
|
||||
entry.execute_disabled = flags.execute_disabled;
|
||||
entry.global = flags.global;
|
||||
}
|
||||
|
||||
static size_t target_level_of(PageTable::flags_t::granularity_t granularity) {
|
||||
if (granularity == PageTable::flags_t::granularity_t::page_1GiB) {
|
||||
return 3;
|
||||
}
|
||||
if (granularity == PageTable::flags_t::granularity_t::page_2MiB) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
template<typename NextEntryType>
|
||||
static void ensure_subtable(table_or_huge_entry_t<NextEntryType>& entry) {
|
||||
if (entry.subtable.present) {
|
||||
return;
|
||||
}
|
||||
optional<PhysicalAllocator::allocation_t> allocation = PhysicalAllocator::getInstance().allocPages(1);
|
||||
if (!allocation.has_value()) {
|
||||
return;
|
||||
}
|
||||
memset(allocation->ptr.access<uint8_t>(), 0, page_size);
|
||||
subtable_entry_t<NextEntryType> subtable{};
|
||||
subtable.present = 1;
|
||||
subtable.writeable = 1;
|
||||
subtable.user_accessible = 1;
|
||||
subtable.table_address = allocation->ptr.address >> 12;
|
||||
entry.subtable = subtable;
|
||||
}
|
||||
|
||||
void PageTable::activate() {
|
||||
asm volatile("mov %0, %%cr3" : : "r"(l4.address) : "memory");
|
||||
}
|
||||
PageTable PageTable::fromCurrent() {
|
||||
PageTable table;
|
||||
table.l4 = current_l4();
|
||||
return table;
|
||||
}
|
||||
|
||||
bool PageTable::map(void* vaddress, paddr_t paddress, flags_t flags) {
|
||||
size_t target_level = target_level_of(flags.granularity);
|
||||
bool mapped = false;
|
||||
walk(
|
||||
l4.access<level4_table_t>(), vaddress,
|
||||
overloaded{
|
||||
[&](frame_entry_t& entry) {
|
||||
frame_entry_t leaf{};
|
||||
apply_flags(leaf, flags);
|
||||
leaf.frame_address = paddress.address >> 12;
|
||||
entry = leaf;
|
||||
mapped = true;
|
||||
},
|
||||
[&]<typename NextEntryType>(table_or_huge_entry_t<NextEntryType>& entry) {
|
||||
constexpr size_t level = table_or_huge_entry_t<NextEntryType>::level;
|
||||
if (level == target_level) {
|
||||
if (entry.subtable.present && !entry.subtable.huge_page) {
|
||||
return;
|
||||
}
|
||||
huge_frame_entry_t<level> leaf{};
|
||||
apply_flags(leaf, flags);
|
||||
leaf.huge_page = 1;
|
||||
leaf.frame_address = paddress.address >> 13;
|
||||
entry.huge = leaf;
|
||||
mapped = true;
|
||||
} else {
|
||||
ensure_subtable(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
if (mapped && is_active(l4)) {
|
||||
asm volatile("invlpg (%0)" : : "r"(vaddress) : "memory");
|
||||
}
|
||||
return mapped;
|
||||
}
|
||||
void PageTable::unmap(void* vaddress) {
|
||||
walk(
|
||||
l4.access<level4_table_t>(), vaddress,
|
||||
overloaded{
|
||||
[](frame_entry_t& entry) {
|
||||
entry = frame_entry_t{};
|
||||
},
|
||||
[](frame_2MiB_entry_t& entry) {
|
||||
entry = frame_2MiB_entry_t{};
|
||||
},
|
||||
[](frame_1GiB_entry_t& entry) {
|
||||
entry = frame_1GiB_entry_t{};
|
||||
},
|
||||
[](auto& entry, ascend_t) {
|
||||
reclaim_if_empty(entry);
|
||||
}
|
||||
}
|
||||
);
|
||||
if (is_active(l4)) {
|
||||
asm volatile("invlpg (%0)" : : "r"(vaddress) : "memory");
|
||||
}
|
||||
}
|
||||
optional<PageTable::info_t> PageTable::get(void* vaddress) {
|
||||
optional<info_t> result{};
|
||||
walk(
|
||||
l4.access<level4_table_t>(), vaddress,
|
||||
overloaded{
|
||||
[&](frame_entry_t& entry) {
|
||||
if (entry.present) {
|
||||
result = info_of(entry, vaddress);
|
||||
}
|
||||
},
|
||||
[&](frame_2MiB_entry_t& entry) {
|
||||
result = info_of(entry, vaddress);
|
||||
},
|
||||
[&](frame_1GiB_entry_t& entry) {
|
||||
result = info_of(entry, vaddress);
|
||||
}
|
||||
}
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -48,6 +48,11 @@ __x64_not_supported:
|
|||
call __print
|
||||
jmp __stop32
|
||||
|
||||
__nx_not_supported:
|
||||
mov $__nx_not_supported_string, %esi
|
||||
call __print
|
||||
jmp __stop32
|
||||
|
||||
__check_if_x64:
|
||||
pushfl
|
||||
pop %eax
|
||||
|
|
@ -70,6 +75,8 @@ __check_if_x64:
|
|||
cpuid
|
||||
test $(1 << 29), %edx
|
||||
jz __x64_not_supported
|
||||
test $(1 << 20), %edx
|
||||
jz __nx_not_supported
|
||||
mov $__x64_supported_string, %esi
|
||||
call __print
|
||||
ret
|
||||
|
|
@ -85,7 +92,7 @@ __go_to_x64:
|
|||
|
||||
mov $0xC0000080, %ecx
|
||||
rdmsr
|
||||
or $(0x1 << 8), %eax
|
||||
or $((0x1 << 8) | (0x1 << 11)), %eax
|
||||
wrmsr
|
||||
|
||||
mov %cr0, %eax
|
||||
|
|
@ -135,6 +142,8 @@ __hello_string:
|
|||
.string "Starting PrOSess! 32bit start!\n"
|
||||
__x64_not_supported_string:
|
||||
.string "x64 is not supported!\n"
|
||||
__nx_not_supported_string:
|
||||
.string "CPU lacks the NX (no-execute) feature, refusing to boot!\n"
|
||||
__x64_supported_string:
|
||||
.string "x64 is supported!\n"
|
||||
__multiboot_info:
|
||||
|
|
@ -227,18 +236,28 @@ __page_level_4:
|
|||
.align 0x1000
|
||||
__page_level_3_low_1gb_identity_map:
|
||||
.set gib_index, 0
|
||||
.rept 512 # identity-map all 512 GiB the PDPT spans, one 1 GiB huge page each
|
||||
.rept 256 # identity-map the first 256 GiB, cached, one 1 GiB huge page each
|
||||
.quad (1 << 0) | (1 << 1) | (1 << 7) | (gib_index << 30)
|
||||
.set gib_index, gib_index + 1
|
||||
.endr
|
||||
.set gib_index, 0
|
||||
.rept 256 # alias the same 256 GiB uncached (PWT | PCD) for MMIO
|
||||
.quad (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 7) | (gib_index << 30)
|
||||
.set gib_index, gib_index + 1
|
||||
.endr
|
||||
|
||||
.align 0x1000
|
||||
__page_level_3_kernel_1gb_identity_map:
|
||||
.set gib_index, 0
|
||||
.rept 512 # identity-map all 512 GiB the PDPT spans, one 1 GiB huge page each
|
||||
.rept 256 # identity-map the first 256 GiB, cached, one 1 GiB huge page each
|
||||
.quad (1 << 0) | (1 << 1) | (1 << 7) | (gib_index << 30)
|
||||
.set gib_index, gib_index + 1
|
||||
.endr
|
||||
.set gib_index, 0
|
||||
.rept 256 # alias the same 256 GiB uncached (PWT | PCD) for MMIO
|
||||
.quad (1 << 0) | (1 << 1) | (1 << 3) | (1 << 4) | (1 << 7) | (gib_index << 30)
|
||||
.set gib_index, gib_index + 1
|
||||
.endr
|
||||
)");
|
||||
|
||||
// startup gdt
|
||||
|
|
|
|||
5
kernel/src/startup/secondaryStartup.cpp
Normal file
5
kernel/src/startup/secondaryStartup.cpp
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
asm(R"(
|
||||
.section .trampoline_text
|
||||
.align 0x1000
|
||||
.code16
|
||||
)");
|
||||
Loading…
Add table
Add a link
Reference in a new issue