···
1
-
const common = @import("common");
const arch = @import("../root.zig");
2
+
const common = @import("common");
const std = @import("std");
4
-
const physToVirt = common.mm.physToHHDM;
4
+
const Cr3 = arch.registers.ControlRegisters.Cr3;
5
+
const Cr4 = arch.registers.ControlRegisters.Cr4;
const Perms = common.mm.paging.Perms;
7
-
pub const page_sizes = [_]usize{
11
-
0x8000000000, // 512G
12
-
0x1000000000000, // 256T
pub const PageTable = extern struct {
···
46
-
fn extract_index_from_vaddr(vaddr: u64, level: u6) u9 {
47
-
const shamt = 12 + level * 9;
48
-
return @truncate(vaddr >> shamt);
39
+
pub const MemoryType = enum {
41
+
DeviceWriteCombining,
46
+
pub fn detect_5level() bool {
47
+
const bits: u64 = 1 << 12;
48
+
return Cr4.read() & bits != 0;
51
-
pub const TypedPTE = union(common.mm.paging.PTEType) {
52
-
Mapping: MappingHandle,
51
+
pub const Context = struct {
56
+
pub fn apply(self: *Self) void {
58
+
const IA32_EFER = arch.registers.MSR(u64, 0xC0000080);
59
+
const efer_val = IA32_EFER.read() | (0b1 << 11);
60
+
IA32_EFER.write(efer_val);
62
+
// Set the level 5 bit accordingly
63
+
const cr4 = Cr4.read();
64
+
const level5mask: u64 = 1 << 12;
65
+
Cr4.write(if (self.level5) cr4 | level5mask else cr4 & ~level5mask);
67
+
Cr3.write(self.cr3_val);
58
-
pub fn decode(pte: *PageTable.Entry, level: u3) Self {
70
+
pub fn get_current() Context {
72
+
.cr3_val = Cr3.read(),
73
+
.level5 = detect_5level(),
77
+
pub fn can_map_at(_: *const Self, level: u3) bool {
81
+
// We need the parameter because aarch64 has 2 root page tables
82
+
pub fn root_table(self: *Self, _: u64) TableHandle {
84
+
.paddr = self.cr3_val,
85
+
.level = if (self.level5) 5 else 4,
96
+
pub fn decode(self: *Self, pte: *PageTable.Entry, level: u3) SomePteHandle {
if (!pte.huge and level != 0) {
63
-
return .{ .Table = decode_table(pte, level) };
101
+
return .{ .Table = self.parse_table(pte, level) };
65
-
return .{ .Mapping = decode_mapping(pte, level) };
103
+
return .{ .Mapping = self.parse_mapping(pte, level) };
68
-
pub fn decode_table(pte: *PageTable.Entry, level: u3) TableHandle {
106
+
pub fn parse_mapping(self: *Self, pte: *PageTable.Entry, level: u3) MappingHandle {
107
+
const memory_type = self.decode_memory_type(pte, level);
70
-
.phys_addr = pte.getAddr(),
110
+
.paddr = pte.getAddr(),
112
+
.memory_type = memory_type,
74
-
.writable = pte.writable,
75
-
.executable = !pte.nx,
76
-
.userspace_accessible = pte.user_accessible,
117
+
.u = pte.user_accessible,
122
+
pub fn decode_memory_type(_: *Self, pte: *PageTable.Entry, _: u3) ?MemoryType {
123
+
return switch (pte.disable_cache) {
124
+
true => .DeviceUncacheable,
125
+
false => switch (pte.write_through) {
126
+
true => .MemoryWritethrough,
127
+
false => .MemoryWriteBack,
81
-
pub fn decode_mapping(pte: *PageTable.Entry, level: u3) MappingHandle {
132
+
pub fn encode_memory_type(_: *Self, pte: *PageTable.Entry, mapping_handle: MappingHandle) void {
133
+
switch (mapping_handle.memory_type.?) {
134
+
.MemoryWritethrough => pte.write_through = true,
135
+
.DeviceUncacheable => pte.disable_cache = true,
136
+
.MemoryWriteBack => {},
137
+
else => @panic("bad memory type"),
141
+
pub fn parse_table(self: *Self, pte: *PageTable.Entry, level: u3) TableHandle {
83
-
.phys_addr = pte.getAddr(),
144
+
.paddr = pte.getAddr(),
85
-
// TODO: memory types
86
-
.memory_type = null,
89
-
.writable = pte.writable,
90
-
.executable = !pte.nx,
91
-
.userspace_accessible = pte.user_accessible,
150
+
.u = pte.user_accessible,
155
+
pub fn encode_mapping(self: *Self, mapping_handle: MappingHandle) PageTable.Entry {
156
+
var pte = std.mem.zeroes(PageTable.Entry);
157
+
pte.setAddr(mapping_handle.paddr);
158
+
pte.present = true;
159
+
if (mapping_handle.level != 0) {
163
+
pte.writable = mapping_handle.perms.w;
164
+
pte.user_accessible = mapping_handle.perms.u;
165
+
pte.nx = !mapping_handle.perms.x;
167
+
self.encode_memory_type(&pte, mapping_handle);
171
+
pub fn encode_table(_: *Self, table_handle: TableHandle) PageTable.Entry {
172
+
var pte = std.mem.zeroes(PageTable.Entry);
173
+
pte.writable = table_handle.perms.w;
174
+
pte.user_accessible = table_handle.perms.u;
175
+
pte.nx = !table_handle.perms.x;
176
+
pte.setAddr(table_handle.paddr);
178
+
pte.present = true;
184
+
pub fn invalidate(_: *const Self, vaddr: u64) void {
186
+
\\ invlpg (%[vaddr])
188
+
: [vaddr] "r" (vaddr),
189
+
: .{ .memory = true });
192
+
pub fn domain(_: *const Self, level: u3, vaddr: u64) StupidSlice {
194
+
.ptr = vaddr & ~(page_sizes[level] - 1),
195
+
.len = page_sizes[level],
199
+
pub fn virt_to_phys(context: *Context, vaddr: usize) ?usize {
200
+
const root = context.root_table(0).get_children();
201
+
const indexes = [_]usize{
202
+
(vaddr >> 39) & 0x1FF,
203
+
(vaddr >> 30) & 0x1FF,
204
+
(vaddr >> 21) & 0x1FF,
205
+
(vaddr >> 12) & 0x1FF,
207
+
var pte_ptr = &root[indexes[0]];
208
+
std.log.warn("{*}: {any}, addr 0x{x}", .{ pte_ptr, pte_ptr, pte_ptr.getAddr() });
210
+
if (!pte_ptr.present) {
213
+
const next_page_table = common.mm.physToHHDM(*PageTable, pte_ptr.getAddr());
214
+
pte_ptr = &next_page_table.entries[indexes[i + 1]];
215
+
std.log.warn("{*}: {any}, addr 0x{x}", .{ pte_ptr, pte_ptr, pte_ptr.getAddr() });
217
+
return pte_ptr.getAddr() + (vaddr & 0xFFF);
97
-
pub const MappingHandle = struct {
221
+
fn idx_from_level(vaddr: u64, level: u6) u9 {
222
+
const shamt = 12 + level * 9;
223
+
return @truncate(vaddr >> shamt);
226
+
pub fn make_page_table() !usize {
227
+
const page_size = std.heap.pageSize();
228
+
const paddr = try common.init_data.bootmem.allocPhys(page_size);
229
+
const pt_ptr = common.mm.physToHHDM([*]u8, paddr);
230
+
@memset(pt_ptr[0..page_size], 0);
234
+
pub const page_sizes = [_]usize{
238
+
0x8000000000, // 512G
239
+
0x1000000000000, // 256T
242
+
const MappingHandle = struct {
memory_type: ?MemoryType,
underlying: *PageTable.Entry,
pub const TableHandle = struct {
underlying: ?*PageTable.Entry,
113
-
// Get the child entries of this page table
pub fn get_children(self: *const Self) []PageTable.Entry {
115
-
const page_table = physToVirt(*PageTable, self.phys_addr);
116
-
return page_table.entries[0..];
260
+
const pt = common.mm.physToHHDM(*PageTable, self.paddr);
261
+
return pt.entries[0..];
119
-
// Get children from the position holding the table and on
120
-
pub fn skip_to(self: *const Self, vaddr: usize) []PageTable.Entry {
121
-
return self.get_children()[extract_index_from_vaddr(vaddr, self.level - 1)..];
264
+
pub fn skip_to(self: *const Self, vaddr: u64) []PageTable.Entry {
265
+
return self.get_children()[idx_from_level(vaddr, self.level - 1)..];
124
-
// Decode child table given an entry
125
-
pub fn decode_child(self: *const Self, pte: *PageTable.Entry) TypedPTE {
126
-
return TypedPTE.decode(pte, self.level - 1);
268
+
pub fn decode_child(self: *const Self, pte: *PageTable.Entry) SomePteHandle {
269
+
return self.context.decode(pte, self.level - 1);
pub fn addPerms(self: *const Self, perms: Perms) void {
130
-
if (perms.executable) {
self.underlying.?.nx = false;
133
-
if (perms.writable) {
self.underlying.?.writable = true;
136
-
if (perms.userspace_accessible) {
self.underlying.?.user_accessible = true;
141
-
pub fn child_domain(self: *const Self, vaddr: usize) UntypedSlice {
142
-
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 = .{
289
+
.context = self.context,
154
-
pte.* = encode_table(result);
294
+
pte.* = self.context.encode_table(result);
159
-
pub fn make_child_mapping(
161
-
pte: *PageTable.Entry,
164
-
memory_type: MemoryType,
299
+
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,
306
+
.context = self.context,
177
-
pte.* = encode_mapping(result);
312
+
pte.* = self.context.encode_mapping(result);
183
-
pub fn root_table(vaddr: usize) TableHandle {
185
-
const cr3_val = arch.registers.ControlRegisters.Cr3.read() & 0xFFFF_FFFF_FFFF_F000;
187
-
.phys_addr = cr3_val,
188
-
// TODO: detect and support 5 level paging!
191
-
.executable = true,
194
-
.underlying = null,
198
-
fn encode_table(pte_handle: TableHandle) PageTable.Entry {
199
-
var pte = std.mem.zeroes(PageTable.Entry);
201
-
pte.setAddr(pte_handle.phys_addr);
202
-
pte.writable = pte_handle.perms.writable;
203
-
pte.user_accessible = pte_handle.perms.userspace_accessible;
204
-
pte.nx = !pte_handle.perms.executable;
205
-
pte.present = true;
211
-
fn encode_mapping(pte_handle: MappingHandle) PageTable.Entry {
212
-
var pte = std.mem.zeroes(PageTable.Entry);
214
-
pte.setAddr(pte_handle.phys_addr);
215
-
pte.present = true;
217
-
if (pte_handle.level != 0) {
317
+
pub fn child_domain(self: *const Self, vaddr: u64) StupidSlice {
318
+
return self.context.domain(self.level - 1, vaddr);
221
-
pte.writable = pte_handle.perms.writable;
222
-
pte.user_accessible = pte_handle.perms.userspace_accessible;
223
-
pte.nx = !pte_handle.perms.executable;
225
-
encode_memory_type(&pte, pte_handle);
230
-
fn encode_memory_type(pte: *PageTable.Entry, pte_handle: MappingHandle) void {
231
-
const mt = pte_handle.memory_type orelse @panic("Unknown memory type");
233
-
// TODO: Page Attribute Table
235
-
.MemoryWritethrough => pte.write_through = true,
236
-
.DeviceUncacheable => pte.disable_cache = true,
237
-
.MemoryWriteBack => {},
238
-
else => @panic("Cannot set memory type"),
242
-
/// Returns physical address
243
-
fn make_page_table() !usize {
244
-
const pt_phys = try common.init_data.bootmem.allocPhys(std.heap.pageSize());
245
-
const pt = physToVirt([*]u8, pt_phys);
246
-
@memset(pt[0..std.heap.pageSize()], 0x00);
322
+
pub const SomePteHandle = union(common.mm.paging.PTEType) {
323
+
Mapping: MappingHandle,
324
+
Table: TableHandle,
250
-
pub fn invalidate(vaddr: u64) void {
252
-
\\ invlpg (%[vaddr])
254
-
: [vaddr] "r" (vaddr),
255
-
: .{ .memory = true });
258
-
const UntypedSlice = struct {
328
+
pub const StupidSlice = struct {
263
-
pub fn domain(vaddr: usize, level: u3) UntypedSlice {
265
-
.len = page_sizes[level],
266
-
.ptr = vaddr & ~(page_sizes[level] - 1),
270
-
pub const MemoryType = enum {
272
-
DeviceWriteCombining,
273
-
MemoryWritethrough,
277
-
pub fn can_map_at(level: u3) bool {