/..

#CONTENT

#TOP

paging.zig
RS
const std = @import("std");
const mem = std.mem;
const arch = @import("arch.zig");
const term = @import("term.zig");

extern const mapped_memory: usize;
extern const page_table_unused: usize;
extern const __page_table_memory_end: usize;

fn get_frame() callconv(.C) ?[*]u8 {
    const page_table_memory_end = @ptrToInt(&__page_table_memory_end);
    if (page_table_unused != page_table_memory_end) {
        const frame = @intToPtr([*]u8, page_table_unused)[0..0x1000];
        mem.set(u8, frame, 0);
        page_table_unused += 0x1000;
        return frame;
    } else {
        @panic("unable to allocate page frame");
    }
    return null;
}

fn create_frame_if_not_present(descriptor: *PageMapDescriptor) callconv(.C) void {
    if (!descriptor.present) {
        var frame = @bitCast(PageMapDescriptor, @ptrToInt((get_frame() orelse @panic("cannot allocate frame"))));
        frame.present = true;
        frame.writeable = true;
        descriptor.* = frame;
    }
}

fn create_page_if_not_present(descriptor: *PageDescriptor4KiB, physaddr: u64) callconv(.C) void {
    if (!descriptor.present) {
        var page = @bitCast(PageDescriptor4KiB, physaddr);
        page.present = true;
        page.writeable = true;
        page.user_accessible = false;
        page.write_through = false;
        page.global = false;
        page.no_execute = false;
        descriptor.* = page;
    }
}

pub export fn identity_map(physaddr: u64) callconv(.C) void {
    const pml4 = @intToPtr(*[512]PageMapDescriptor, arch.read_cr3().pml4 << @bitOffsetOf(arch.Cr3, "pml4"));
    const mask = (1 << 9) - 1;
    const offset = @bitOffsetOf(PageMapDescriptor, "address");

    var pml4e = physaddr >> 39 & mask;
    var pdpe = physaddr >> 30 & mask;
    var pde = physaddr >> 21 & mask;
    var pte = physaddr >> 12 & mask;

    create_frame_if_not_present(&pml4[pml4e]);
    const pdp = @intToPtr(*[512]PageMapDescriptor, pml4[pml4e].address << offset);
    create_frame_if_not_present(&pdp[pdpe]);
    const pd = @intToPtr(*[512]PageMapDescriptor, pdp[pdpe].address << offset);
    create_frame_if_not_present(&pd[pde]);
    const pt = @intToPtr(*[512]PageDescriptor4KiB, pd[pde].address << offset);
    create_page_if_not_present(&pt[pte], physaddr);
}

pub const PageMapDescriptor = packed struct {
    present: bool,
    writeable: bool,
    user_accessible: bool,
    write_through: bool,
    uncacheable: bool,
    accessed: bool,
    mbz0: u1,
    huge_pages: bool,
    mbz1: u1,
    available_lo: u3,
    address: u40,
    available_hi: u11,
    no_execute: bool,
};

pub const PageDescriptor4KiB = packed struct {
    present: bool,
    writeable: bool,
    user_accessible: bool,
    write_through: bool,
    uncacheable: bool,
    accessed: bool,
    dirty: bool,
    page_attribute: u1,
    global: bool,
    available_lo: u3,
    address: u40,
    available_hi: u7,
    memory_protection_key: u4,
    no_execute: bool,
};

pub const HugePageDescriptor = packed struct {
    present: bool,
    writeable: bool,
    user_accessible: bool,
    write_through: bool,
    uncacheable: bool,
    accessed: bool,
    dirty: bool,
    must_be_one: u1,
    global: bool,
    available_lo: u3,
    page_attribute: u1,
    address: u39,
    available_hi: u7,
    memory_protection_key: u4,
    no_execute: bool,
};