core: Fix a couple of bugs in VMM and add a few utility functions
This commit is contained in:
parent
f93158645b
commit
56f2c018a7
@ -2,9 +2,10 @@ const std = @import("std");
|
|||||||
const easyboot = @cImport(@cInclude("easyboot.h"));
|
const easyboot = @cImport(@cInclude("easyboot.h"));
|
||||||
const mmap = @import("../../mmap.zig");
|
const mmap = @import("../../mmap.zig");
|
||||||
const pmm = @import("../../pmm.zig");
|
const pmm = @import("../../pmm.zig");
|
||||||
|
const platform = @import("platform.zig");
|
||||||
|
|
||||||
const USER_ADDRESS_RANGE_END = 0x0000_7fff_ffff_ffff;
|
const USER_ADDRESS_RANGE_END = 0x0000_7fff_ffff_ffff;
|
||||||
const PHYSICAL_MAPPING_BASE = 0xffff_8000_0000_0000;
|
pub const PHYSICAL_MAPPING_BASE = 0xffff_8000_0000_0000;
|
||||||
const HUGE_PAGE_SIZE = 0x200000; // 2 MiB
|
const HUGE_PAGE_SIZE = 0x200000; // 2 MiB
|
||||||
|
|
||||||
pub const PageTableEntry = packed struct {
|
pub const PageTableEntry = packed struct {
|
||||||
@ -14,7 +15,7 @@ pub const PageTableEntry = packed struct {
|
|||||||
write_through: u1,
|
write_through: u1,
|
||||||
cache_disabled: u1,
|
cache_disabled: u1,
|
||||||
accessed: u1,
|
accessed: u1,
|
||||||
ignore0: u1,
|
reserved: u1,
|
||||||
larger_pages: u1,
|
larger_pages: u1,
|
||||||
global: u1,
|
global: u1,
|
||||||
available: u3,
|
available: u3,
|
||||||
@ -31,7 +32,7 @@ pub const PageTableEntry = packed struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(self: *PageTableEntry) void {
|
pub fn clear(self: *PageTableEntry) void {
|
||||||
self = std.mem.zeroes(@TypeOf(self));
|
self.* = std.mem.zeroes(PageTableEntry);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -39,7 +40,7 @@ pub const PageDirectory = struct {
|
|||||||
entries: [512]PageTableEntry,
|
entries: [512]PageTableEntry,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Flags = enum(u32) {
|
pub const Flags = enum(u32) {
|
||||||
None = 0,
|
None = 0,
|
||||||
ReadWrite = 1,
|
ReadWrite = 1,
|
||||||
User = 2,
|
User = 2,
|
||||||
@ -68,6 +69,7 @@ fn hasFlag(flags: u32, flag: Flags) u1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn updatePageTableEntry(entry: *PageTableEntry, phys: pmm.PhysFrame, flags: u32) void {
|
fn updatePageTableEntry(entry: *PageTableEntry, phys: pmm.PhysFrame, flags: u32) void {
|
||||||
|
entry.clear();
|
||||||
entry.present = 1;
|
entry.present = 1;
|
||||||
entry.read_write = hasFlag(flags, Flags.ReadWrite);
|
entry.read_write = hasFlag(flags, Flags.ReadWrite);
|
||||||
entry.user = hasFlag(flags, Flags.User);
|
entry.user = hasFlag(flags, Flags.User);
|
||||||
@ -80,6 +82,7 @@ fn updatePageTableEntry(entry: *PageTableEntry, phys: pmm.PhysFrame, flags: u32)
|
|||||||
|
|
||||||
fn setUpParentPageTableEntry(allocator: *pmm.FrameAllocator, pte: *PageTableEntry, flags: u32, base: usize) !void {
|
fn setUpParentPageTableEntry(allocator: *pmm.FrameAllocator, pte: *PageTableEntry, flags: u32, base: usize) !void {
|
||||||
if (pte.present == 0) {
|
if (pte.present == 0) {
|
||||||
|
pte.clear();
|
||||||
const frame = try pmm.allocFrame(allocator);
|
const frame = try pmm.allocFrame(allocator);
|
||||||
pte.present = 1;
|
pte.present = 1;
|
||||||
pte.set_address(frame.address);
|
pte.set_address(frame.address);
|
||||||
@ -107,8 +110,8 @@ pub fn map(allocator: *pmm.FrameAllocator, directory: *PageDirectory, base: usiz
|
|||||||
if (l2.larger_pages == 1) return error.MemoryAlreadyInUse;
|
if (l2.larger_pages == 1) return error.MemoryAlreadyInUse;
|
||||||
|
|
||||||
if (use_huge_pages) {
|
if (use_huge_pages) {
|
||||||
l2.larger_pages = 1;
|
|
||||||
updatePageTableEntry(l2, phys, flags);
|
updatePageTableEntry(l2, phys, flags);
|
||||||
|
l2.larger_pages = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +122,108 @@ pub fn map(allocator: *pmm.FrameAllocator, directory: *PageDirectory, base: usiz
|
|||||||
updatePageTableEntry(l1, phys, flags);
|
updatePageTableEntry(l1, phys, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getEntry(directory: *PageDirectory, base: usize, virt_address: u64) ?*PageTableEntry {
|
||||||
|
const indexes = calculatePageTableIndexes(virt_address);
|
||||||
|
const l4 = &directory.entries[indexes.level4];
|
||||||
|
if (l4.present == 0) return null;
|
||||||
|
|
||||||
|
const l3 = &getTable(l4, base).entries[indexes.level3];
|
||||||
|
if (l3.present == 0) return null;
|
||||||
|
if (l3.larger_pages == 1) return l3;
|
||||||
|
|
||||||
|
const l2 = &getTable(l3, base).entries[indexes.level2];
|
||||||
|
if (l2.present == 0) return null;
|
||||||
|
if (l2.larger_pages == 1) return l2;
|
||||||
|
|
||||||
|
const l1 = &getTable(l2, base).entries[indexes.level1];
|
||||||
|
if (l1.present == 0) return null;
|
||||||
|
|
||||||
|
return l1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copyToUser(directory: *PageDirectory, base: usize, user: usize, kernel: [*]const u8, size: usize) !void {
|
||||||
|
const remainder: usize = @rem(user, platform.PAGE_SIZE);
|
||||||
|
const user_page = user - remainder;
|
||||||
|
|
||||||
|
var user_address = user;
|
||||||
|
var kernel_ptr = kernel;
|
||||||
|
var count = size;
|
||||||
|
|
||||||
|
if (user_address != user_page) {
|
||||||
|
const pte = getEntry(directory, base, user_page) orelse return error.MemoryNotInUse;
|
||||||
|
const frame = pmm.PhysFrame{ .address = pte.get_address() };
|
||||||
|
const amount: usize = @min((platform.PAGE_SIZE - remainder), count);
|
||||||
|
const virt = frame.virtualAddress(base) + remainder;
|
||||||
|
|
||||||
|
@memcpy(@as([*]u8, @ptrFromInt(virt))[0..amount], kernel_ptr[0..amount]);
|
||||||
|
|
||||||
|
kernel_ptr += amount;
|
||||||
|
user_address += amount;
|
||||||
|
count -= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (count > 0) {
|
||||||
|
const pte = getEntry(directory, base, user_address) orelse return error.MemoryNotInUse;
|
||||||
|
const frame = pmm.PhysFrame{ .address = pte.get_address() };
|
||||||
|
const amount: usize = @min(platform.PAGE_SIZE, count);
|
||||||
|
const virt = frame.virtualAddress(base);
|
||||||
|
|
||||||
|
@memcpy(@as([*]u8, @ptrFromInt(virt))[0..amount], kernel_ptr[0..amount]);
|
||||||
|
|
||||||
|
kernel_ptr += amount;
|
||||||
|
user_address += amount;
|
||||||
|
count -= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memsetUser(directory: *PageDirectory, base: usize, user: usize, elem: u8, size: usize) !void {
|
||||||
|
const remainder: usize = @rem(user, platform.PAGE_SIZE);
|
||||||
|
const user_page = user - remainder;
|
||||||
|
|
||||||
|
var user_address = user;
|
||||||
|
var count = size;
|
||||||
|
|
||||||
|
if (user_address != user_page) {
|
||||||
|
const pte = getEntry(directory, base, user_page) orelse return error.MemoryNotInUse;
|
||||||
|
const frame = pmm.PhysFrame{ .address = pte.get_address() };
|
||||||
|
const amount: usize = @min((platform.PAGE_SIZE - remainder), count);
|
||||||
|
const virt = frame.virtualAddress(base) + remainder;
|
||||||
|
|
||||||
|
@memset(@as([*]u8, @ptrFromInt(virt))[0..amount], elem);
|
||||||
|
|
||||||
|
user_address += amount;
|
||||||
|
count -= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (count > 0) {
|
||||||
|
const pte = getEntry(directory, base, user_address) orelse return error.MemoryNotInUse;
|
||||||
|
const frame = pmm.PhysFrame{ .address = pte.get_address() };
|
||||||
|
const amount: usize = @min(platform.PAGE_SIZE, count);
|
||||||
|
const virt = frame.virtualAddress(base);
|
||||||
|
|
||||||
|
@memset(@as([*]u8, @ptrFromInt(virt))[0..amount], elem);
|
||||||
|
|
||||||
|
user_address += amount;
|
||||||
|
count -= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocAndMap(allocator: *pmm.FrameAllocator, directory: *PageDirectory, base: u64, pages: usize, flags: u32) !void {
|
||||||
|
var virt = base;
|
||||||
|
var i: usize = 0;
|
||||||
|
|
||||||
|
while (i < pages) {
|
||||||
|
const frame = try pmm.allocFrame(allocator);
|
||||||
|
try map(allocator, directory, PHYSICAL_MAPPING_BASE, virt, frame, flags, false);
|
||||||
|
virt += platform.PAGE_SIZE;
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn mapPhysicalMemory(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t, directory: *PageDirectory, base: usize, flags: u32) !void {
|
fn mapPhysicalMemory(allocator: *pmm.FrameAllocator, tag: *easyboot.multiboot_tag_mmap_t, directory: *PageDirectory, base: usize, flags: u32) !void {
|
||||||
const address_space_size = mmap.getAddressSpaceSize(tag) orelse return error.InvalidMemoryMap;
|
const address_space_size = mmap.getAddressSpaceSize(tag) orelse return error.InvalidMemoryMap;
|
||||||
const address_space_pages = address_space_size / HUGE_PAGE_SIZE;
|
const address_space_pages = address_space_size / HUGE_PAGE_SIZE;
|
||||||
@ -195,6 +300,10 @@ pub fn readPageDirectory() *PageDirectory {
|
|||||||
return directory;
|
return directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn getPhysicalPageDirectory(directory: *PageDirectory) *PageDirectory {
|
||||||
|
return @ptrFromInt(@intFromPtr(directory) - @as(usize, PHYSICAL_MAPPING_BASE));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn setPageDirectory(directory: *PageDirectory) void {
|
pub fn setPageDirectory(directory: *PageDirectory) void {
|
||||||
asm volatile ("mov %[dir], %%cr3"
|
asm volatile ("mov %[dir], %%cr3"
|
||||||
:
|
:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user