birth/src/cpu/arch/x86_64.zig
David Gonzalez Martin 0709f980af first commit
2023-07-09 11:24:30 -06:00

266 lines
7.8 KiB
Zig

const lib = @import("lib");
const Allocator = lib.Allocator;
const assert = lib.assert;
const ELF = lib.ELF(64);
const log = lib.log;
const Spinlock = lib.Spinlock;
const bootloader = @import("bootloader");
const privileged = @import("privileged");
const panic = cpu.panic;
const PageAllocator = cpu.PageAllocator;
const x86_64 = privileged.arch.x86_64;
const APIC = x86_64.APIC;
const paging = x86_64.paging;
const cr0 = x86_64.registers.cr0;
const cr3 = x86_64.registers.cr3;
const cr4 = x86_64.registers.cr4;
const PhysicalAddress = lib.PhysicalAddress;
const PhysicalMemoryRegion = lib.PhysicalMemoryRegion;
const VirtualAddress = lib.VirtualAddress;
const VirtualMemoryRegion = lib.VirtualMemoryRegion;
const cpu = @import("cpu");
const Heap = cpu.Heap;
const init = @import("./x86/64/init.zig");
pub const syscall = @import("./x86/64/syscall.zig");
pub const entryPoint = init.entryPoint;
const rise = @import("rise");
var writer_lock: Spinlock = .released;
pub const Registers = extern struct {
r15: u64,
r14: u64,
r13: u64,
r12: u64,
rbp: u64,
rbx: u64,
r11: u64,
r10: u64,
r9: u64,
r8: u64,
rax: u64,
rcx: u64,
rdx: u64,
rsi: u64,
rdi: u64,
syscall_number_or_error_code: u64,
rip: u64,
cs: u64,
rflags: lib.arch.x86_64.registers.RFLAGS,
rsp: u64,
ss: u64,
};
const interrupt_kind: u32 = 0;
export fn interruptHandler(regs: *const InterruptRegisters, interrupt_number: u8) void {
switch (interrupt_number) {
local_timer_vector => {
APIC.write(.eoi, 0);
nextTimer(10);
},
else => cpu.panicFromInstructionPointerAndFramePointer(regs.rip, regs.rbp, "Exception: 0x{x}", .{interrupt_number}),
}
}
const InterruptRegisters = extern struct {
r15: u64,
r14: u64,
r13: u64,
r12: u64,
rbp: u64,
rbx: u64,
r11: u64,
r10: u64,
r9: u64,
r8: u64,
rax: u64,
rcx: u64,
rdx: u64,
rsi: u64,
rdi: u64,
error_code: u64,
rip: u64,
cs: u64,
rflags: u64,
rsp: u64,
ss: u64,
};
const local_timer_vector = 0xef;
pub export var ticks_per_ms: privileged.arch.x86_64.TicksPerMS = undefined;
pub inline fn nextTimer(ms: u32) void {
APIC.write(.lvt_timer, local_timer_vector | (1 << 17));
APIC.write(.timer_initcnt, ticks_per_ms.lapic * ms);
}
pub const kpti = true;
pub const pcid = false;
pub const smap = false;
pub const invariant_tsc = false;
pub const capability_address_space_size = 1 * lib.gb;
pub const capability_address_space_start = capability_address_space_stack_top - capability_address_space_size;
pub const capability_address_space_stack_top = 0xffff_ffff_8000_0000;
pub const capability_address_space_stack_size = privileged.default_stack_size;
pub const capability_address_space_stack_alignment = lib.arch.valid_page_sizes[0];
pub const capability_address_space_stack_address = VirtualAddress.new(capability_address_space_stack_top - capability_address_space_stack_size);
pub const code_64 = @offsetOf(GDT, "code_64");
pub const data_64 = @offsetOf(GDT, "data_64");
pub const user_code_64 = @offsetOf(GDT, "user_code_64");
pub const user_data_64 = @offsetOf(GDT, "user_data_64");
pub const tss_selector = @offsetOf(GDT, "tss_descriptor");
pub const user_code_selector = user_code_64 | user_dpl;
pub const user_data_selector = user_data_64 | user_dpl;
pub const user_dpl = 3;
pub const GDT = extern struct {
null: Entry = GDT.Entry.null_entry, // 0x00
code_16: Entry = GDT.Entry.code_16, // 0x08
data_16: Entry = GDT.Entry.data_16, // 0x10
code_32: Entry = GDT.Entry.code_32, // 0x18
data_32: Entry = GDT.Entry.data_32, // 0x20
code_64: u64 = 0x00A09A0000000000, // 0x28
data_64: u64 = 0x0000920000000000, // 0x30
user_data_64: u64 = @as(u64, 0x0000920000000000) | (3 << 45), //GDT.Entry.user_data_64, // 0x38
user_code_64: u64 = @as(u64, 0x00A09A0000000000) | (3 << 45), //GDT.Entry.user_code_64, // 0x40
tss_descriptor: TSS.Descriptor = undefined, // 0x48
const Entry = privileged.arch.x86_64.GDT.Entry;
pub const Descriptor = privileged.arch.x86_64.GDT.Descriptor;
comptime {
const entry_count = 9;
const target_size = entry_count * @sizeOf(Entry) + @sizeOf(TSS.Descriptor);
assert(@sizeOf(GDT) == target_size);
assert(@offsetOf(GDT, "code_64") == 0x28);
assert(@offsetOf(GDT, "data_64") == 0x30);
assert(@offsetOf(GDT, "user_data_64") == 0x38);
assert(@offsetOf(GDT, "user_code_64") == 0x40);
assert(@offsetOf(GDT, "tss_descriptor") == entry_count * @sizeOf(Entry));
}
pub fn getDescriptor(global_descriptor_table: *const GDT) GDT.Descriptor {
return .{
.limit = @sizeOf(GDT) - 1,
.address = @intFromPtr(global_descriptor_table),
};
}
};
pub const SystemSegmentDescriptor = extern struct {
const Type = enum(u4) {
ldt = 0b0010,
tss_available = 0b1001,
tss_busy = 0b1011,
call_gate = 0b1100,
interrupt_gate = 0b1110,
trap_gate = 0b1111,
};
};
pub const TSS = extern struct {
reserved0: u32 = 0,
rsp: [3]u64 align(4) = [3]u64{ 0, 0, 0 },
reserved1: u64 align(4) = 0,
IST: [7]u64 align(4) = [7]u64{ 0, 0, 0, 0, 0, 0, 0 },
reserved3: u64 align(4) = 0,
reserved4: u16 = 0,
IO_map_base_address: u16 = 104,
comptime {
assert(@sizeOf(TSS) == 104);
}
pub const Descriptor = extern struct {
limit_low: u16,
base_low: u16,
base_mid_low: u8,
access: Access,
attributes: Attributes,
base_mid_high: u8,
base_high: u32,
reserved: u32 = 0,
pub const Access = packed struct(u8) {
type: SystemSegmentDescriptor.Type,
reserved: u1 = 0,
dpl: u2,
present: bool,
};
pub const Attributes = packed struct(u8) {
limit: u4,
available_for_system_software: bool,
reserved: u2 = 0,
granularity: bool,
};
comptime {
assert(@sizeOf(TSS.Descriptor) == 0x10);
}
};
pub fn getDescriptor(tss_struct: *const TSS, offset: u64) Descriptor {
const address = @intFromPtr(tss_struct) + offset;
return Descriptor{
.low = .{
.limit_low = @as(u16, @truncate(@sizeOf(TSS) - 1)),
.base_low = @as(u16, @truncate(address)),
.base_low_mid = @as(u8, @truncate(address >> 16)),
.type = 0b1001,
.descriptor_privilege_level = 0,
.present = 1,
.limit_high = 0,
.available_for_system_software = 0,
.granularity = 0,
.base_mid = @as(u8, @truncate(address >> 24)),
},
.base_high = @as(u32, @truncate(address >> 32)),
};
}
};
pub const IDT = extern struct {
descriptors: [entry_count]GateDescriptor = undefined,
pub const Descriptor = privileged.arch.x86_64.SegmentDescriptor;
pub const GateDescriptor = extern struct {
offset_low: u16,
segment_selector: u16,
flags: packed struct(u16) {
ist: u3,
reserved: u5 = 0,
type: SystemSegmentDescriptor.Type,
reserved1: u1 = 0,
dpl: u2,
present: bool,
},
offset_mid: u16,
offset_high: u32,
reserved: u32 = 0,
comptime {
assert(@sizeOf(@This()) == 0x10);
}
};
pub const entry_count = 256;
};
pub inline fn writerStart() void {
writer_lock.acquire();
}
pub inline fn writerEnd() void {
writer_lock.release();
}
pub const PageTableEntry = paging.Level;
pub const root_page_table_entry = @as(cpu.arch.PageTableEntry, @enumFromInt(0));
pub const IOMap = extern struct {
debug: bool,
};