diff options
| author | Bobby <[email protected]> | 2026-02-25 07:17:49 +0530 |
|---|---|---|
| committer | Bobby <[email protected]> | 2026-02-25 07:17:49 +0530 |
| commit | 15f9ee5984f97bdca1b75a4f732c4a503ee504dc (patch) | |
| tree | b1da26512642a740756f67497d4af4e9b22615ed | |
| parent | 50e29a219dc2e7de9f336e15fe0049b2e64ede0a (diff) | |
| download | akiba-15f9ee5984f97bdca1b75a4f732c4a503ee504dc.tar.xz akiba-15f9ee5984f97bdca1b75a4f732c4a503ee504dc.zip | |
feat: Implement Kagami page table abstraction with allocation, mapping, and protection functionalities
| -rw-r--r-- | mirai/kagami/allocate/allocate.zig | 35 | ||||
| -rw-r--r-- | mirai/kagami/constants/constants.zig | 4 | ||||
| -rw-r--r-- | mirai/kagami/constants/protection.zig | 19 | ||||
| -rw-r--r-- | mirai/kagami/constants/tables.zig | 12 | ||||
| -rw-r--r-- | mirai/kagami/create/create.zig | 71 | ||||
| -rw-r--r-- | mirai/kagami/destroy/destroy.zig | 78 | ||||
| -rw-r--r-- | mirai/kagami/enter/enter.zig | 87 | ||||
| -rw-r--r-- | mirai/kagami/extract/extract.zig | 35 | ||||
| -rw-r--r-- | mirai/kagami/kagami.zig | 51 | ||||
| -rw-r--r-- | mirai/kagami/protect/protect.zig | 41 | ||||
| -rw-r--r-- | mirai/kagami/remove/remove.zig | 40 | ||||
| -rw-r--r-- | mirai/kagami/state.zig | 41 | ||||
| -rw-r--r-- | mirai/kagami/tables/allocate.zig | 100 | ||||
| -rw-r--r-- | mirai/kagami/tables/tables.zig | 18 | ||||
| -rw-r--r-- | mirai/kagami/tables/walk.zig | 75 | ||||
| -rw-r--r-- | mirai/kagami/types/entry.zig | 56 | ||||
| -rw-r--r-- | mirai/kagami/types/kagami.zig | 56 | ||||
| -rw-r--r-- | mirai/kagami/types/table.zig | 38 | ||||
| -rw-r--r-- | mirai/kagami/types/types.zig | 9 |
19 files changed, 866 insertions, 0 deletions
diff --git a/mirai/kagami/allocate/allocate.zig b/mirai/kagami/allocate/allocate.zig new file mode 100644 index 0000000..d57f140 --- /dev/null +++ b/mirai/kagami/allocate/allocate.zig @@ -0,0 +1,35 @@ +//! Extract Physical Address + +const types = @import("../types/types.zig"); +const tables = @import("../tables/tables.zig"); + +const Entry = types.Entry; +const Kagami = types.Kagami; + +pub fn extract(kagami: *const Kagami, virtual_address: u64) ?u64 { + const entry = tables.walk_to_entry(kagami.pml4_physical, virtual_address) orelse return null; + + if (!entry.is_present()) { + return null; + } + + const physical_base = entry.get_physical_address(); + const offset = virtual_address & 0xFFF; + + return physical_base | offset; +} + +pub fn is_mapped(kagami: *const Kagami, virtual_address: u64) bool { + const entry = tables.walk_to_entry(kagami.pml4_physical, virtual_address) orelse return false; + return entry.is_present(); +} + +pub fn is_writable(kagami: *const Kagami, virtual_address: u64) bool { + const entry = tables.walk_to_entry(kagami.pml4_physical, virtual_address) orelse return false; + return entry.is_present() and entry.is_writable(); +} + +pub fn is_user_accessible(kagami: *const Kagami, virtual_address: u64) bool { + const entry = tables.walk_to_entry(kagami.pml4_physical, virtual_address) orelse return false; + return entry.is_present() and entry.is_user(); +} diff --git a/mirai/kagami/constants/constants.zig b/mirai/kagami/constants/constants.zig new file mode 100644 index 0000000..10e5379 --- /dev/null +++ b/mirai/kagami/constants/constants.zig @@ -0,0 +1,4 @@ +//! Kagami Constants + +pub const tables = @import("tables.zig"); +pub const protection = @import("protection.zig"); diff --git a/mirai/kagami/constants/protection.zig b/mirai/kagami/constants/protection.zig new file mode 100644 index 0000000..c1f0311 --- /dev/null +++ b/mirai/kagami/constants/protection.zig @@ -0,0 +1,19 @@ +//! Kagami Protection Constants + +pub const none: u8 = 0x00; +pub const read: u8 = 0x01; +pub const write: u8 = 0x02; +pub const execute: u8 = 0x04; +pub const user: u8 = 0x08; +pub const wired: u8 = 0x10; +pub const nocache: u8 = 0x20; + +pub const kernel_read: u8 = read; +pub const kernel_write: u8 = read | write; +pub const kernel_execute: u8 = read | execute; +pub const kernel_all: u8 = read | write | execute; + +pub const user_read: u8 = read | user; +pub const user_write: u8 = read | write | user; +pub const user_execute: u8 = read | execute | user; +pub const user_all: u8 = read | write | execute | user; diff --git a/mirai/kagami/constants/tables.zig b/mirai/kagami/constants/tables.zig new file mode 100644 index 0000000..0e83553 --- /dev/null +++ b/mirai/kagami/constants/tables.zig @@ -0,0 +1,12 @@ +//! Kagami Table Constants + +pub const pml4_entries: u64 = 512; +pub const pdpt_entries: u64 = 512; +pub const pd_entries: u64 = 512; +pub const pt_entries: u64 = 512; + +pub const kernel_pml4_start: u64 = 256; +pub const kernel_pml4_end: u64 = 512; + +pub const user_pml4_start: u64 = 0; +pub const user_pml4_end: u64 = 256; diff --git a/mirai/kagami/create/create.zig b/mirai/kagami/create/create.zig new file mode 100644 index 0000000..8e7bad3 --- /dev/null +++ b/mirai/kagami/create/create.zig @@ -0,0 +1,71 @@ +//! Create Kagami + +const common = @import("../../../common/common.zig"); +const pmm = @import("../../pmm/pmm.zig"); +const types = @import("../types/types.zig"); +const state = @import("../state.zig"); +const tables = @import("../tables/tables.zig"); + +const AllocationError = common.errors.memory.AllocationError; +const Kagami = types.Kagami; +const Table = types.Table; + +var kagami_pool: [256]Kagami = undefined; +var kagami_pool_bitmap: [32]u8 = [_]u8{0} ** 32; + +pub fn create() AllocationError!*Kagami { + const pml4_physical = try pmm.allocate_page_zeroed(); + + const kagami = allocate_kagami_struct() orelse { + pmm.free_page(pml4_physical); + return AllocationError.OutOfMemory; + }; + + kagami.* = Kagami{ + .pml4_physical = pml4_physical, + .reference_count = 1, + .resident_pages = 0, + .wired_pages = 0, + .table_pages = 1, + .lock = false, + }; + + const kernel_kagami = state.get_kernel_kagami(); + const new_pml4 = tables.get_pml4(pml4_physical); + const kernel_pml4 = tables.get_pml4(kernel_kagami.pml4_physical); + + new_pml4.copy_kernel_entries(kernel_pml4); + + return kagami; +} + +fn allocate_kagami_struct() ?*Kagami { + var index: usize = 0; + while (index < 256) : (index += 1) { + const byte_index = index / 8; + const bit_index: u3 = @truncate(index % 8); + + if ((kagami_pool_bitmap[byte_index] & (@as(u8, 1) << bit_index)) == 0) { + kagami_pool_bitmap[byte_index] |= (@as(u8, 1) << bit_index); + return &kagami_pool[index]; + } + } + return null; +} + +pub fn free_kagami_struct(kagami: *Kagami) void { + const base_ptr: usize = @intFromPtr(&kagami_pool[0]); + const kagami_ptr: usize = @intFromPtr(kagami); + + if (kagami_ptr < base_ptr) return; + + const offset = kagami_ptr - base_ptr; + const index = offset / @sizeOf(Kagami); + + if (index >= 256) return; + + const byte_index = index / 8; + const bit_index: u3 = @truncate(index % 8); + + kagami_pool_bitmap[byte_index] &= ~(@as(u8, 1) << bit_index); +} diff --git a/mirai/kagami/destroy/destroy.zig b/mirai/kagami/destroy/destroy.zig new file mode 100644 index 0000000..e8d9a5e --- /dev/null +++ b/mirai/kagami/destroy/destroy.zig @@ -0,0 +1,78 @@ +//! Destroy Kagami + +const pmm = @import("../../pmm/pmm.zig"); +const types = @import("../types/types.zig"); +const state = @import("../state.zig"); +const tables = @import("../tables/tables.zig"); +const create_module = @import("../create/create.zig"); + +const Kagami = types.Kagami; +const Table = types.Table; + +pub fn destroy(kagami: *Kagami) void { + if (kagami.is_kernel()) { + return; + } + + const remaining = kagami.decrement_reference(); + if (remaining > 0) { + return; + } + + free_user_tables(kagami); + + pmm.free_page(kagami.pml4_physical); + + create_module.free_kagami_struct(kagami); +} + +fn free_user_tables(kagami: *Kagami) void { + const pml4 = tables.get_pml4(kagami.pml4_physical); + + var pml4_index: u9 = 0; + while (pml4_index < 256) : (pml4_index += 1) { + const pml4_entry = pml4.get_entry(pml4_index); + if (!pml4_entry.is_present()) continue; + + const pdpt = tables.get_table_from_physical(pml4_entry.get_physical_address()); + free_pdpt(pdpt); + + pmm.free_page(pml4_entry.get_physical_address()); + pml4_entry.clear(); + } +} + +fn free_pdpt(pdpt: *Table) void { + var pdpt_index: u9 = 0; + while (pdpt_index < 512) : (pdpt_index += 1) { + const pdpt_entry = pdpt.get_entry(pdpt_index); + if (!pdpt_entry.is_present()) continue; + if (pdpt_entry.is_huge()) continue; + + const pd = tables.get_table_from_physical(pdpt_entry.get_physical_address()); + free_pd(pd); + + pmm.free_page(pdpt_entry.get_physical_address()); + pdpt_entry.clear(); + } +} + +fn free_pd(pd: *Table) void { + var pd_index: u9 = 0; + while (pd_index < 512) : (pd_index += 1) { + const pd_entry = pd.get_entry(pd_index); + if (!pd_entry.is_present()) continue; + if (pd_entry.is_huge()) continue; + + pmm.free_page(pd_entry.get_physical_address()); + pd_entry.clear(); + } +} + +pub fn reference(kagami: *Kagami) void { + kagami.increment_reference(); +} + +pub fn release(kagami: *Kagami) void { + destroy(kagami); +} diff --git a/mirai/kagami/enter/enter.zig b/mirai/kagami/enter/enter.zig new file mode 100644 index 0000000..e8e5441 --- /dev/null +++ b/mirai/kagami/enter/enter.zig @@ -0,0 +1,87 @@ +//! Enter Mapping (VA -> PA) + +const common = @import("../../../common/common.zig"); +const types = @import("../types/types.zig"); +const tables = @import("../tables/tables.zig"); +const constants = @import("../constants/constants.zig"); +const asm_cpu = @import("../../asm/cpu/cpu.zig"); + +const paging_flags = common.constants.paging.flags; +const MappingError = common.errors.memory.MappingError; +const AllocationError = common.errors.memory.AllocationError; + +const Entry = types.Entry; +const Kagami = types.Kagami; + +pub fn enter( + kagami: *Kagami, + virtual_address: u64, + physical_address: u64, + protection: u8, +) (MappingError || AllocationError)!void { + if ((virtual_address & 0xFFF) != 0) { + return MappingError.AddressNotAligned; + } + + if ((physical_address & 0xFFF) != 0) { + return MappingError.AddressNotAligned; + } + + const entry = try tables.ensure_tables(kagami, virtual_address); + + if (entry.is_present()) { + return MappingError.AlreadyMapped; + } + + entry.* = build_entry(physical_address, protection); + + kagami.add_resident(); + + if ((protection & constants.protection.wired) != 0) { + kagami.add_wired(); + } + + asm_cpu.invalidate_page(virtual_address); +} + +pub fn enter_replace( + kagami: *Kagami, + virtual_address: u64, + physical_address: u64, + protection: u8, +) (MappingError || AllocationError)!void { + if ((virtual_address & 0xFFF) != 0) { + return MappingError.AddressNotAligned; + } + + if ((physical_address & 0xFFF) != 0) { + return MappingError.AddressNotAligned; + } + + const entry = try tables.ensure_tables(kagami, virtual_address); + + const was_present = entry.is_present(); + + entry.* = build_entry(physical_address, protection); + + if (!was_present) { + kagami.add_resident(); + } + + asm_cpu.invalidate_page(virtual_address); +} + +fn build_entry(physical_address: u64, protection: u8) Entry { + var entry = Entry{ + .present = true, + .writable = (protection & constants.protection.write) != 0, + .user_accessible = (protection & constants.protection.user) != 0, + .cache_disabled = (protection & constants.protection.nocache) != 0, + .global = (protection & constants.protection.user) == 0, + .no_execute = (protection & constants.protection.execute) == 0, + }; + + entry.set_physical_address(physical_address); + + return entry; +} diff --git a/mirai/kagami/extract/extract.zig b/mirai/kagami/extract/extract.zig new file mode 100644 index 0000000..d57f140 --- /dev/null +++ b/mirai/kagami/extract/extract.zig @@ -0,0 +1,35 @@ +//! Extract Physical Address + +const types = @import("../types/types.zig"); +const tables = @import("../tables/tables.zig"); + +const Entry = types.Entry; +const Kagami = types.Kagami; + +pub fn extract(kagami: *const Kagami, virtual_address: u64) ?u64 { + const entry = tables.walk_to_entry(kagami.pml4_physical, virtual_address) orelse return null; + + if (!entry.is_present()) { + return null; + } + + const physical_base = entry.get_physical_address(); + const offset = virtual_address & 0xFFF; + + return physical_base | offset; +} + +pub fn is_mapped(kagami: *const Kagami, virtual_address: u64) bool { + const entry = tables.walk_to_entry(kagami.pml4_physical, virtual_address) orelse return false; + return entry.is_present(); +} + +pub fn is_writable(kagami: *const Kagami, virtual_address: u64) bool { + const entry = tables.walk_to_entry(kagami.pml4_physical, virtual_address) orelse return false; + return entry.is_present() and entry.is_writable(); +} + +pub fn is_user_accessible(kagami: *const Kagami, virtual_address: u64) bool { + const entry = tables.walk_to_entry(kagami.pml4_physical, virtual_address) orelse return false; + return entry.is_present() and entry.is_user(); +} diff --git a/mirai/kagami/kagami.zig b/mirai/kagami/kagami.zig new file mode 100644 index 0000000..23c129b --- /dev/null +++ b/mirai/kagami/kagami.zig @@ -0,0 +1,51 @@ +//! Kagami - Page Table Abstraction + +pub const constants = @import("constants/constants.zig"); +pub const types = @import("types/types.zig"); +pub const tables = @import("tables/tables.zig"); +pub const state = @import("state.zig"); + +pub const create_module = @import("create/create.zig"); +pub const destroy_module = @import("destroy/destroy.zig"); +pub const enter_module = @import("enter/enter.zig"); +pub const remove_module = @import("remove/remove.zig"); +pub const protect_module = @import("protect/protect.zig"); +pub const extract_module = @import("extract/extract.zig"); +pub const activate_module = @import("activate/activate.zig"); + +pub const Kagami = types.Kagami; +pub const Entry = types.Entry; +pub const Table = types.Table; + +pub const create = create_module.create; +pub const destroy = destroy_module.destroy; +pub const reference = destroy_module.reference; +pub const release = destroy_module.release; + +pub const enter = enter_module.enter; +pub const enter_replace = enter_module.enter_replace; + +pub const remove = remove_module.remove; +pub const remove_range = remove_module.remove_range; + +pub const protect = protect_module.protect; +pub const protect_range = protect_module.protect_range; + +pub const extract = extract_module.extract; +pub const is_mapped = extract_module.is_mapped; +pub const is_writable = extract_module.is_writable; +pub const is_user_accessible = extract_module.is_user_accessible; + +pub const activate = activate_module.activate; +pub const activate_kernel = activate_module.activate_kernel; +pub const get_active_pml4 = activate_module.get_active_pml4; +pub const is_active = activate_module.is_active; + +pub const kernel = state.get_kernel_kagami; +pub const current = state.get_current_kagami; +pub const is_initialized = state.is_initialized; + +pub fn initialize(pml4_physical: u64) void { + state.set_kernel_pml4(pml4_physical); + state.set_initialized(); +} diff --git a/mirai/kagami/protect/protect.zig b/mirai/kagami/protect/protect.zig new file mode 100644 index 0000000..fc08f18 --- /dev/null +++ b/mirai/kagami/protect/protect.zig @@ -0,0 +1,41 @@ +//! Change Protection + +const common = @import("../../../common/common.zig"); +const types = @import("../types/types.zig"); +const tables = @import("../tables/tables.zig"); +const constants = @import("../constants/constants.zig"); +const asm_cpu = @import("../../asm/cpu/cpu.zig"); + +const MappingError = common.errors.memory.MappingError; +const Entry = types.Entry; +const Kagami = types.Kagami; + +pub fn protect(kagami: *Kagami, virtual_address: u64, protection: u8) MappingError!void { + const entry = tables.walk_to_entry(kagami.pml4_physical, virtual_address) orelse { + return MappingError.NotMapped; + }; + + if (!entry.is_present()) { + return MappingError.NotMapped; + } + + entry.writable = (protection & constants.protection.write) != 0; + entry.user_accessible = (protection & constants.protection.user) != 0; + entry.cache_disabled = (protection & constants.protection.nocache) != 0; + entry.no_execute = (protection & constants.protection.execute) == 0; + + asm_cpu.invalidate_page(virtual_address); +} + +pub fn protect_range(kagami: *Kagami, start_address: u64, page_count: u64, protection: u8) u64 { + var protected_count: u64 = 0; + var offset: u64 = 0; + + while (offset < page_count) : (offset += 1) { + const virtual_address = start_address + (offset * 4096); + protect(kagami, virtual_address, protection) catch continue; + protected_count += 1; + } + + return protected_count; +} diff --git a/mirai/kagami/remove/remove.zig b/mirai/kagami/remove/remove.zig new file mode 100644 index 0000000..1133f09 --- /dev/null +++ b/mirai/kagami/remove/remove.zig @@ -0,0 +1,40 @@ +//! Remove Mapping + +const types = @import("../types/types.zig"); +const tables = @import("../tables/tables.zig"); +const asm_cpu = @import("../../asm/cpu/cpu.zig"); + +const Entry = types.Entry; +const Kagami = types.Kagami; + +pub fn remove(kagami: *Kagami, virtual_address: u64) ?u64 { + const entry = tables.walk_to_entry(kagami.pml4_physical, virtual_address) orelse return null; + + if (!entry.is_present()) { + return null; + } + + const physical_address = entry.get_physical_address(); + + entry.clear(); + + kagami.remove_resident(); + + asm_cpu.invalidate_page(virtual_address); + + return physical_address; +} + +pub fn remove_range(kagami: *Kagami, start_address: u64, page_count: u64) u64 { + var removed_count: u64 = 0; + var offset: u64 = 0; + + while (offset < page_count) : (offset += 1) { + const virtual_address = start_address + (offset * 4096); + if (remove(kagami, virtual_address) != null) { + removed_count += 1; + } + } + + return removed_count; +} diff --git a/mirai/kagami/state.zig b/mirai/kagami/state.zig new file mode 100644 index 0000000..86a77ed --- /dev/null +++ b/mirai/kagami/state.zig @@ -0,0 +1,41 @@ +//! Kagami State + +const types = @import("types/types.zig"); +const Kagami = types.Kagami; + +var kernel_kagami: Kagami = .{ + .pml4_physical = 0, + .reference_count = 1, + .resident_pages = 0, + .wired_pages = 0, + .table_pages = 0, + .lock = false, +}; + +var current_kagami: *Kagami = &kernel_kagami; + +var initialized: bool = false; + +pub fn get_kernel_kagami() *Kagami { + return &kernel_kagami; +} + +pub fn get_current_kagami() *Kagami { + return current_kagami; +} + +pub fn set_current_kagami(kagami: *Kagami) void { + current_kagami = kagami; +} + +pub fn set_kernel_pml4(pml4_physical: u64) void { + kernel_kagami.pml4_physical = pml4_physical; +} + +pub fn is_initialized() bool { + return initialized; +} + +pub fn set_initialized() void { + initialized = true; +} diff --git a/mirai/kagami/tables/allocate.zig b/mirai/kagami/tables/allocate.zig new file mode 100644 index 0000000..6526bae --- /dev/null +++ b/mirai/kagami/tables/allocate.zig @@ -0,0 +1,100 @@ +//! Page Table Allocation + +const common = @import("../../../common/common.zig"); +const pmm = @import("../../pmm/pmm.zig"); +const types = @import("../types/types.zig"); +const walk = @import("walk.zig"); + +const paging = common.constants.paging; +const memory = common.constants.memory; +const AllocationError = common.errors.memory.AllocationError; + +const Entry = types.Entry; +const Table = types.Table; +const Kagami = types.Kagami; + +pub fn allocate_table() AllocationError!u64 { + const physical_address = try pmm.allocate_page_zeroed(); + return physical_address; +} + +pub fn free_table(physical_address: u64) void { + pmm.free_page(physical_address); +} + +pub fn ensure_pdpt(kagami: *Kagami, virtual_address: u64) AllocationError!*Table { + const pml4 = walk.get_pml4(kagami.pml4_physical); + const pml4_index = paging.indices.extract_pml4_index(virtual_address); + const entry = pml4.get_entry(pml4_index); + + if (entry.is_present()) { + return walk.get_table_from_physical(entry.get_physical_address()); + } + + const new_table_physical = try allocate_table(); + kagami.add_table(); + + entry.* = Entry{ + .present = true, + .writable = true, + .user_accessible = (pml4_index < 256), + }; + entry.set_physical_address(new_table_physical); + + return walk.get_table_from_physical(new_table_physical); +} + +pub fn ensure_pd(kagami: *Kagami, pdpt: *Table, virtual_address: u64) AllocationError!*Table { + const pdpt_index = paging.indices.extract_pdpt_index(virtual_address); + const entry = pdpt.get_entry(pdpt_index); + + if (entry.is_present()) { + return walk.get_table_from_physical(entry.get_physical_address()); + } + + const new_table_physical = try allocate_table(); + kagami.add_table(); + + const pml4_index = paging.indices.extract_pml4_index(virtual_address); + + entry.* = Entry{ + .present = true, + .writable = true, + .user_accessible = (pml4_index < 256), + }; + entry.set_physical_address(new_table_physical); + + return walk.get_table_from_physical(new_table_physical); +} + +pub fn ensure_pt(kagami: *Kagami, pd: *Table, virtual_address: u64) AllocationError!*Table { + const pd_index = paging.indices.extract_pd_index(virtual_address); + const entry = pd.get_entry(pd_index); + + if (entry.is_present()) { + return walk.get_table_from_physical(entry.get_physical_address()); + } + + const new_table_physical = try allocate_table(); + kagami.add_table(); + + const pml4_index = paging.indices.extract_pml4_index(virtual_address); + + entry.* = Entry{ + .present = true, + .writable = true, + .user_accessible = (pml4_index < 256), + }; + entry.set_physical_address(new_table_physical); + + return walk.get_table_from_physical(new_table_physical); +} + +pub fn ensure_tables(kagami: *Kagami, virtual_address: u64) AllocationError!*Entry { + const pdpt = try ensure_pdpt(kagami, virtual_address); + const pd = try ensure_pd(kagami, pdpt, virtual_address); + const pt = try ensure_pt(kagami, pd, virtual_address); + + const pt_index = paging.indices.extract_pt_index(virtual_address); + return pt.get_entry(pt_index); +} diff --git a/mirai/kagami/tables/tables.zig b/mirai/kagami/tables/tables.zig new file mode 100644 index 0000000..2ee664a --- /dev/null +++ b/mirai/kagami/tables/tables.zig @@ -0,0 +1,18 @@ +//! Page Table Operations + +pub const walk = @import("walk.zig"); +pub const allocate = @import("allocate.zig"); + +pub const get_table_from_physical = walk.get_table_from_physical; +pub const get_pml4 = walk.get_pml4; +pub const get_pdpt = walk.get_pdpt; +pub const get_pd = walk.get_pd; +pub const get_pt = walk.get_pt; +pub const walk_to_entry = walk.walk_to_entry; + +pub const allocate_table = allocate.allocate_table; +pub const free_table = allocate.free_table; +pub const ensure_pdpt = allocate.ensure_pdpt; +pub const ensure_pd = allocate.ensure_pd; +pub const ensure_pt = allocate.ensure_pt; +pub const ensure_tables = allocate.ensure_tables; diff --git a/mirai/kagami/tables/walk.zig b/mirai/kagami/tables/walk.zig new file mode 100644 index 0000000..eeb37e7 --- /dev/null +++ b/mirai/kagami/tables/walk.zig @@ -0,0 +1,75 @@ +//! Page Table Walking + +const common = @import("../../../common/common.zig"); +const types = @import("../types/types.zig"); + +const paging = common.constants.paging; +const memory = common.constants.memory; + +const Entry = types.Entry; +const Table = types.Table; + +pub fn get_table_from_physical(physical_address: u64) *Table { + const virtual_address = physical_address + memory.layout.physmap_base; + return @ptrFromInt(virtual_address); +} + +pub fn get_pml4(pml4_physical: u64) *Table { + return get_table_from_physical(pml4_physical); +} + +pub fn get_pdpt(pml4: *Table, virtual_address: u64) ?*Table { + const pml4_index = paging.indices.extract_pml4_index(virtual_address); + const entry = pml4.get_entry(pml4_index); + + if (!entry.is_present()) { + return null; + } + + return get_table_from_physical(entry.get_physical_address()); +} + +pub fn get_pd(pdpt: *Table, virtual_address: u64) ?*Table { + const pdpt_index = paging.indices.extract_pdpt_index(virtual_address); + const entry = pdpt.get_entry(pdpt_index); + + if (!entry.is_present()) { + return null; + } + + if (entry.is_huge()) { + return null; + } + + return get_table_from_physical(entry.get_physical_address()); +} + +pub fn get_pt(pd: *Table, virtual_address: u64) ?*Table { + const pd_index = paging.indices.extract_pd_index(virtual_address); + const entry = pd.get_entry(pd_index); + + if (!entry.is_present()) { + return null; + } + + if (entry.is_huge()) { + return null; + } + + return get_table_from_physical(entry.get_physical_address()); +} + +pub fn get_page_entry(pt: *Table, virtual_address: u64) *Entry { + const pt_index = paging.indices.extract_pt_index(virtual_address); + return pt.get_entry(pt_index); +} + +pub fn walk_to_entry(pml4_physical: u64, virtual_address: u64) ?*Entry { + const pml4 = get_pml4(pml4_physical); + + const pdpt = get_pdpt(pml4, virtual_address) orelse return null; + const pd = get_pd(pdpt, virtual_address) orelse return null; + const pt = get_pt(pd, virtual_address) orelse return null; + + return get_page_entry(pt, virtual_address); +} diff --git a/mirai/kagami/types/entry.zig b/mirai/kagami/types/entry.zig new file mode 100644 index 0000000..5fc7a8d --- /dev/null +++ b/mirai/kagami/types/entry.zig @@ -0,0 +1,56 @@ +//! Page Table Entry Type + +const common = @import("../../../common/common.zig"); +const paging_flags = common.constants.paging.flags; + +pub const Entry = packed struct { + present: bool = false, + writable: bool = false, + user_accessible: bool = false, + write_through: bool = false, + cache_disabled: bool = false, + accessed: bool = false, + dirty: bool = false, + huge_page: bool = false, + global: bool = false, + available_low: u3 = 0, + physical_address: u40 = 0, + available_high: u11 = 0, + no_execute: bool = false, + + pub fn is_present(self: Entry) bool { + return self.present; + } + + pub fn is_writable(self: Entry) bool { + return self.writable; + } + + pub fn is_user(self: Entry) bool { + return self.user_accessible; + } + + pub fn is_huge(self: Entry) bool { + return self.huge_page; + } + + pub fn get_physical_address(self: Entry) u64 { + return @as(u64, self.physical_address) << 12; + } + + pub fn set_physical_address(self: *Entry, address: u64) void { + self.physical_address = @truncate(address >> 12); + } + + pub fn clear(self: *Entry) void { + self.* = Entry{}; + } + + pub fn from_raw(raw: u64) Entry { + return @bitCast(raw); + } + + pub fn to_raw(self: Entry) u64 { + return @bitCast(self); + } +}; diff --git a/mirai/kagami/types/kagami.zig b/mirai/kagami/types/kagami.zig new file mode 100644 index 0000000..f89863f --- /dev/null +++ b/mirai/kagami/types/kagami.zig @@ -0,0 +1,56 @@ +//! Kagami Structure + +pub const Kagami = struct { + pml4_physical: u64, + reference_count: u32, + resident_pages: u64, + wired_pages: u64, + table_pages: u64, + lock: bool, + + pub fn is_kernel(self: *const Kagami) bool { + const kernel_kagami = @import("../state.zig").get_kernel_kagami(); + return self.pml4_physical == kernel_kagami.pml4_physical; + } + + pub fn increment_reference(self: *Kagami) void { + self.reference_count += 1; + } + + pub fn decrement_reference(self: *Kagami) u32 { + if (self.reference_count > 0) { + self.reference_count -= 1; + } + return self.reference_count; + } + + pub fn add_resident(self: *Kagami) void { + self.resident_pages += 1; + } + + pub fn remove_resident(self: *Kagami) void { + if (self.resident_pages > 0) { + self.resident_pages -= 1; + } + } + + pub fn add_wired(self: *Kagami) void { + self.wired_pages += 1; + } + + pub fn remove_wired(self: *Kagami) void { + if (self.wired_pages > 0) { + self.wired_pages -= 1; + } + } + + pub fn add_table(self: *Kagami) void { + self.table_pages += 1; + } + + pub fn remove_table(self: *Kagami) void { + if (self.table_pages > 0) { + self.table_pages -= 1; + } + } +}; diff --git a/mirai/kagami/types/table.zig b/mirai/kagami/types/table.zig new file mode 100644 index 0000000..33a072c --- /dev/null +++ b/mirai/kagami/types/table.zig @@ -0,0 +1,38 @@ +//! Page Table Type + +const Entry = @import("entry.zig").Entry; + +pub const Table = struct { + entries: [512]Entry, + + pub fn get_entry(self: *Table, index: u9) *Entry { + return &self.entries[index]; + } + + pub fn get_entry_const(self: *const Table, index: u9) *const Entry { + return &self.entries[index]; + } + + pub fn clear_all(self: *Table) void { + for (&self.entries) |*entry| { + entry.clear(); + } + } + + pub fn copy_kernel_entries(self: *Table, source: *const Table) void { + var index: usize = 256; + while (index < 512) : (index += 1) { + self.entries[index] = source.entries[index]; + } + } + + pub fn count_present(self: *const Table) u32 { + var count: u32 = 0; + for (self.entries) |entry| { + if (entry.is_present()) { + count += 1; + } + } + return count; + } +}; diff --git a/mirai/kagami/types/types.zig b/mirai/kagami/types/types.zig new file mode 100644 index 0000000..a333b86 --- /dev/null +++ b/mirai/kagami/types/types.zig @@ -0,0 +1,9 @@ +//! Kagami Types + +pub const entry = @import("entry.zig"); +pub const table = @import("table.zig"); +pub const kagami = @import("kagami.zig"); + +pub const Entry = entry.Entry; +pub const Table = table.Table; +pub const Kagami = kagami.Kagami; |
