Microkernel thing OS experiment (Zig ⚡)
at dev 4.9 kB view raw
1//! The Global Descriptor Table (GDT) structure for AMD64 2const std = @import("std"); 3const arch = @import("../root.zig"); 4 5pub const Descriptor = packed struct(u64) { 6 limit_low: u16 = 0, 7 base_low: u16 = 0, 8 base_mid: u8 = 0, 9 access: Access, 10 limit_high: u4 = 0, 11 flags: Flags = .{}, 12 base_high: u8 = 0, 13 14 const Self = @This(); 15 16 pub const Access = packed struct(u8) { 17 // Accessed 18 accessed: bool = true, 19 // Readable/Writable 20 rw: bool = false, 21 // Direction bit or Conforming bit 22 dc: bool = false, 23 // Executable 24 executable: bool, 25 // Descriptor Type bit 26 descriptor_type: DescriptorType = .code_or_data, 27 // Descriptor Privilege Level 28 dpl: u2, 29 // Present bit 30 p: bool = true, 31 32 pub const DescriptorType = enum(u1) { 33 tss = 0, 34 code_or_data = 1, 35 }; 36 }; 37 38 pub const Flags = packed struct(u4) { 39 // Reserved 40 _reserved: u1 = 0, 41 // Long Mode code flag 42 long_mode: bool = true, 43 // Size flag (16 vs 32) 44 db: DB = .protected_16, 45 // Granularity flag 46 granularity: Granularity = .byte, 47 48 pub const Granularity = enum(u1) { 49 byte = 0, 50 page = 1, 51 }; 52 53 pub const DB = enum(u1) { 54 protected_16 = 0, 55 protected_32 = 1, 56 }; 57 }; 58 59 pub const null_desc = std.mem.zeroes(Descriptor); 60 pub const kernel_code: Self = .{ .access = .{ .dpl = 0, .executable = true } }; 61 pub const kernel_data: Self = .{ .access = .{ .dpl = 0, .executable = false, .rw = true } }; 62 pub const user_code: Self = .{ .access = .{ .dpl = 3, .executable = true } }; 63 pub const user_data: Self = .{ .access = .{ .dpl = 3, .executable = false, .rw = true } }; 64}; 65 66pub const StandardGdt = extern struct { 67 null_desc: Descriptor = .null_desc, 68 kernel_code: Descriptor = .kernel_code, 69 kernel_data: Descriptor = .kernel_data, 70 tss_desc: TssDescriptor align(@alignOf(Descriptor)) = .{}, 71 user_data: Descriptor = .user_data, 72 user_code: Descriptor = .user_code, 73 74 pub const selectors = struct { 75 pub const null_desc = @offsetOf(StandardGdt, "null_desc"); 76 pub const kernel_code = @offsetOf(StandardGdt, "kernel_code"); 77 pub const kernel_data = @offsetOf(StandardGdt, "kernel_data"); 78 pub const tss_desc = @offsetOf(StandardGdt, "tss_desc"); 79 pub const user_data = @offsetOf(StandardGdt, "user_data") | 0b11; 80 pub const user_code = @offsetOf(StandardGdt, "user_code") | 0b11; 81 }; 82 83 const Self = @This(); 84 85 pub fn load(self: *Self) void { 86 // 1. Load the GDTR 87 const gdtr: Gdtr = .{ 88 .limit = @truncate(@sizeOf(StandardGdt) - 1), 89 .base = @intFromPtr(self), 90 }; 91 gdtr.load(); 92 93 // 2. Set the kernel data segments 94 asm volatile ( 95 \\ mov %[sel], %%ds 96 \\ mov %[sel], %%es 97 \\ mov %[sel], %%fs 98 \\ mov %[sel], %%gs 99 \\ mov %[sel], %%ss 100 : 101 : [sel] "rm" (@as(u16, selectors.kernel_data)), 102 ); 103 104 // 3. Reload kernel code segments (far return) 105 asm volatile ( 106 \\ push %[sel] 107 \\ lea 1f(%%rip), %%rax 108 \\ push %%rax 109 \\ .byte 0x48, 0xcb // retfq 110 \\ 1: 111 : 112 : [sel] "i" (@as(u16, selectors.kernel_code)), 113 : .{ .rax = true }); 114 115 // 4. Set the TSS descriptor 116 asm volatile ( 117 \\ ltr %[sel] 118 : 119 : [sel] "r" (@as(u16, selectors.tss_desc)), 120 ); 121 } 122}; 123 124pub const Gdtr = packed struct(u80) { 125 limit: u16, 126 base: u64, 127 128 pub fn load(self: *const Gdtr) void { 129 asm volatile ("lgdt %[gdtr_ptr]" 130 : 131 : [gdtr_ptr] "*p" (self), 132 ); 133 } 134}; 135 136const TssDescriptor = extern struct { 137 const Low = packed struct(u64) { 138 limit_low: u16 = 0, 139 base_low: u16 = 0, 140 base_mid: u8 = 0, 141 seg_type: u4 = 0b1001, 142 _reserved0: u1 = 0b0, 143 dpl: u2 = 0, 144 p: bool = true, 145 limit_high: u4 = 0, 146 unused: u1 = 0, 147 _reserved1: u2 = 0b00, 148 granularity: u1 = 0, 149 base_high: u8 = 0, 150 }; 151 descriptor: Low = .{}, 152 base_top: u32 = 0, 153 _reserved: u32 = 0, 154 155 const Self = @This(); 156 157 pub fn set_tss_addr(self: *Self, tss: *const arch.structures.tss.Tss) void { 158 const tss_ptr: usize = @intFromPtr(tss); 159 // Set the base 160 self.descriptor.base_low = @truncate(tss_ptr); 161 self.descriptor.base_mid = @truncate(tss_ptr >> 16); 162 self.descriptor.base_high = @truncate(tss_ptr >> 24); 163 self.base_top = @truncate(tss_ptr >> 32); 164 // Set the limit 165 self.descriptor.limit_low = @sizeOf(arch.structures.tss.Tss); 166 } 167};