···
-
const common = @import("common");
const arch = @import("../root.zig");
const std = @import("std");
-
const physToVirt = common.mm.physToHHDM;
const Perms = common.mm.paging.Perms;
-
pub const page_sizes = [_]usize{
-
0x1000000000000, // 256T
pub const PageTable = extern struct {
···
-
fn extract_index_from_vaddr(vaddr: u64, level: u6) u9 {
-
const shamt = 12 + level * 9;
-
return @truncate(vaddr >> shamt);
-
pub const TypedPTE = union(common.mm.paging.PTEType) {
-
Mapping: MappingHandle,
-
pub fn decode(pte: *PageTable.Entry, level: u3) Self {
if (!pte.huge and level != 0) {
-
return .{ .Table = decode_table(pte, level) };
-
return .{ .Mapping = decode_mapping(pte, level) };
-
pub fn decode_table(pte: *PageTable.Entry, level: u3) TableHandle {
-
.phys_addr = pte.getAddr(),
-
.writable = pte.writable,
-
.userspace_accessible = pte.user_accessible,
-
pub fn decode_mapping(pte: *PageTable.Entry, level: u3) MappingHandle {
-
.phys_addr = pte.getAddr(),
-
.writable = pte.writable,
-
.userspace_accessible = pte.user_accessible,
-
pub const MappingHandle = struct {
memory_type: ?MemoryType,
underlying: *PageTable.Entry,
pub const TableHandle = struct {
underlying: ?*PageTable.Entry,
-
// Get the child entries of this page table
pub fn get_children(self: *const Self) []PageTable.Entry {
-
const page_table = physToVirt(*PageTable, self.phys_addr);
-
return page_table.entries[0..];
-
// Get children from the position holding the table and on
-
pub fn skip_to(self: *const Self, vaddr: usize) []PageTable.Entry {
-
return self.get_children()[extract_index_from_vaddr(vaddr, self.level - 1)..];
-
// Decode child table given an entry
-
pub fn decode_child(self: *const Self, pte: *PageTable.Entry) TypedPTE {
-
return TypedPTE.decode(pte, self.level - 1);
pub fn addPerms(self: *const Self, perms: Perms) void {
-
if (perms.executable) {
self.underlying.?.nx = false;
self.underlying.?.writable = true;
-
if (perms.userspace_accessible) {
self.underlying.?.user_accessible = true;
-
pub fn child_domain(self: *const Self, vaddr: usize) UntypedSlice {
-
return domain(vaddr, self.level - 1);
pub fn make_child_table(self: *const Self, pte: *PageTable.Entry, perms: Perms) !TableHandle {
const pmem = try make_page_table();
const result: TableHandle = .{
-
pte.* = encode_table(result);
-
pub fn make_child_mapping(
-
memory_type: MemoryType,
const page_size = page_sizes[self.level - 1];
const pmem = paddr orelse try common.init_data.bootmem.allocPhys(page_size);
const result: MappingHandle = .{
.memory_type = memory_type,
-
pte.* = encode_mapping(result);
-
pub fn root_table(vaddr: usize) TableHandle {
-
const cr3_val = arch.registers.ControlRegisters.Cr3.read() & 0xFFFF_FFFF_FFFF_F000;
-
// TODO: detect and support 5 level paging!
-
fn encode_table(pte_handle: TableHandle) PageTable.Entry {
-
var pte = std.mem.zeroes(PageTable.Entry);
-
pte.setAddr(pte_handle.phys_addr);
-
pte.writable = pte_handle.perms.writable;
-
pte.user_accessible = pte_handle.perms.userspace_accessible;
-
pte.nx = !pte_handle.perms.executable;
-
fn encode_mapping(pte_handle: MappingHandle) PageTable.Entry {
-
var pte = std.mem.zeroes(PageTable.Entry);
-
pte.setAddr(pte_handle.phys_addr);
-
if (pte_handle.level != 0) {
-
pte.writable = pte_handle.perms.writable;
-
pte.user_accessible = pte_handle.perms.userspace_accessible;
-
pte.nx = !pte_handle.perms.executable;
-
encode_memory_type(&pte, pte_handle);
-
fn encode_memory_type(pte: *PageTable.Entry, pte_handle: MappingHandle) void {
-
const mt = pte_handle.memory_type orelse @panic("Unknown memory type");
-
// TODO: Page Attribute Table
-
.MemoryWritethrough => pte.write_through = true,
-
.DeviceUncacheable => pte.disable_cache = true,
-
.MemoryWriteBack => {},
-
else => @panic("Cannot set memory type"),
-
/// Returns physical address
-
fn make_page_table() !usize {
-
const pt_phys = try common.init_data.bootmem.allocPhys(std.heap.pageSize());
-
const pt = physToVirt([*]u8, pt_phys);
-
@memset(pt[0..std.heap.pageSize()], 0x00);
-
pub fn invalidate(vaddr: u64) void {
-
: .{ .memory = true });
-
const UntypedSlice = struct {
-
pub fn domain(vaddr: usize, level: u3) UntypedSlice {
-
.len = page_sizes[level],
-
.ptr = vaddr & ~(page_sizes[level] - 1),
-
pub const MemoryType = enum {
-
pub fn can_map_at(level: u3) bool {
···
const arch = @import("../root.zig");
+
const common = @import("common");
const std = @import("std");
+
const Cr3 = arch.registers.ControlRegisters.Cr3;
+
const Cr4 = arch.registers.ControlRegisters.Cr4;
const Perms = common.mm.paging.Perms;
pub const PageTable = extern struct {
···
+
pub const MemoryType = enum {
+
pub fn detect_5level() bool {
+
const bits: u64 = 1 << 12;
+
return Cr4.read() & bits != 0;
+
pub const Context = struct {
+
pub fn apply(self: *Self) void {
+
const IA32_EFER = arch.registers.MSR(u64, 0xC0000080);
+
const efer_val = IA32_EFER.read() | (0b1 << 11);
+
IA32_EFER.write(efer_val);
+
// Set the level 5 bit accordingly
+
const cr4 = Cr4.read();
+
const level5mask: u64 = 1 << 12;
+
Cr4.write(if (self.level5) cr4 | level5mask else cr4 & ~level5mask);
+
Cr3.write(self.cr3_val);
+
pub fn get_current() Context {
+
.level5 = detect_5level(),
+
pub fn can_map_at(_: *const Self, level: u3) bool {
+
// We need the parameter because aarch64 has 2 root page tables
+
pub fn root_table(self: *Self, _: u64) TableHandle {
+
.level = if (self.level5) 5 else 4,
+
pub fn decode(self: *Self, pte: *PageTable.Entry, level: u3) SomePteHandle {
if (!pte.huge and level != 0) {
+
return .{ .Table = self.parse_table(pte, level) };
+
return .{ .Mapping = self.parse_mapping(pte, level) };
+
pub fn parse_mapping(self: *Self, pte: *PageTable.Entry, level: u3) MappingHandle {
+
const memory_type = self.decode_memory_type(pte, level);
+
.paddr = pte.getAddr(),
+
.memory_type = memory_type,
+
.u = pte.user_accessible,
+
pub fn decode_memory_type(_: *Self, pte: *PageTable.Entry, _: u3) ?MemoryType {
+
return switch (pte.disable_cache) {
+
true => .DeviceUncacheable,
+
false => switch (pte.write_through) {
+
true => .MemoryWritethrough,
+
false => .MemoryWriteBack,
+
pub fn encode_memory_type(_: *Self, pte: *PageTable.Entry, mapping_handle: MappingHandle) void {
+
switch (mapping_handle.memory_type.?) {
+
.MemoryWritethrough => pte.write_through = true,
+
.DeviceUncacheable => pte.disable_cache = true,
+
.MemoryWriteBack => {},
+
else => @panic("bad memory type"),
+
pub fn parse_table(self: *Self, pte: *PageTable.Entry, level: u3) TableHandle {
+
.paddr = pte.getAddr(),
+
.u = pte.user_accessible,
+
pub fn encode_mapping(self: *Self, mapping_handle: MappingHandle) PageTable.Entry {
+
var pte = std.mem.zeroes(PageTable.Entry);
+
pte.setAddr(mapping_handle.paddr);
+
if (mapping_handle.level != 0) {
+
pte.writable = mapping_handle.perms.w;
+
pte.user_accessible = mapping_handle.perms.u;
+
pte.nx = !mapping_handle.perms.x;
+
self.encode_memory_type(&pte, mapping_handle);
+
pub fn encode_table(_: *Self, table_handle: TableHandle) PageTable.Entry {
+
var pte = std.mem.zeroes(PageTable.Entry);
+
pte.writable = table_handle.perms.w;
+
pte.user_accessible = table_handle.perms.u;
+
pte.nx = !table_handle.perms.x;
+
pte.setAddr(table_handle.paddr);
+
pub fn invalidate(_: *const Self, vaddr: u64) void {
+
: .{ .memory = true });
+
pub fn domain(_: *const Self, level: u3, vaddr: u64) StupidSlice {
+
.ptr = vaddr & ~(page_sizes[level] - 1),
+
.len = page_sizes[level],
+
pub fn virt_to_phys(context: *Context, vaddr: usize) ?usize {
+
const root = context.root_table(0).get_children();
+
const indexes = [_]usize{
+
var pte_ptr = &root[indexes[0]];
+
std.log.warn("{*}: {any}, addr 0x{x}", .{ pte_ptr, pte_ptr, pte_ptr.getAddr() });
+
if (!pte_ptr.present) {
+
const next_page_table = common.mm.physToHHDM(*PageTable, pte_ptr.getAddr());
+
pte_ptr = &next_page_table.entries[indexes[i + 1]];
+
std.log.warn("{*}: {any}, addr 0x{x}", .{ pte_ptr, pte_ptr, pte_ptr.getAddr() });
+
return pte_ptr.getAddr() + (vaddr & 0xFFF);
+
fn idx_from_level(vaddr: u64, level: u6) u9 {
+
const shamt = 12 + level * 9;
+
return @truncate(vaddr >> shamt);
+
pub fn make_page_table() !usize {
+
const page_size = std.heap.pageSize();
+
const paddr = try common.init_data.bootmem.allocPhys(page_size);
+
const pt_ptr = common.mm.physToHHDM([*]u8, paddr);
+
@memset(pt_ptr[0..page_size], 0);
+
pub const page_sizes = [_]usize{
+
0x1000000000000, // 256T
+
const MappingHandle = struct {
memory_type: ?MemoryType,
underlying: *PageTable.Entry,
pub const TableHandle = struct {
underlying: ?*PageTable.Entry,
pub fn get_children(self: *const Self) []PageTable.Entry {
+
const pt = common.mm.physToHHDM(*PageTable, self.paddr);
+
return pt.entries[0..];
+
pub fn skip_to(self: *const Self, vaddr: u64) []PageTable.Entry {
+
return self.get_children()[idx_from_level(vaddr, self.level - 1)..];
+
pub fn decode_child(self: *const Self, pte: *PageTable.Entry) SomePteHandle {
+
return self.context.decode(pte, self.level - 1);
pub fn addPerms(self: *const Self, perms: Perms) void {
self.underlying.?.nx = false;
self.underlying.?.writable = true;
self.underlying.?.user_accessible = true;
pub fn make_child_table(self: *const Self, pte: *PageTable.Entry, perms: Perms) !TableHandle {
const pmem = try make_page_table();
const result: TableHandle = .{
+
.context = self.context,
+
pte.* = self.context.encode_table(result);
+
pub fn make_child_mapping(self: *const Self, pte: *PageTable.Entry, paddr: ?u64, perms: Perms, memory_type: MemoryType) !MappingHandle {
const page_size = page_sizes[self.level - 1];
const pmem = paddr orelse try common.init_data.bootmem.allocPhys(page_size);
const result: MappingHandle = .{
.memory_type = memory_type,
+
.context = self.context,
+
pte.* = self.context.encode_mapping(result);
+
pub fn child_domain(self: *const Self, vaddr: u64) StupidSlice {
+
return self.context.domain(self.level - 1, vaddr);
+
pub const SomePteHandle = union(common.mm.paging.PTEType) {
+
Mapping: MappingHandle,
+
pub const StupidSlice = struct {