mirror of
https://github.com/rdmsr/zag.git
synced 2026-10-27 13:58:20 +00:00
feat: amd64 interrupts
This commit is contained in:
@@ -236,6 +236,13 @@ fn addKernel(b: *std.Build, plat: config.Platform, optimize: std.builtin.Optimiz
|
|||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (plat.arch) {
|
||||||
|
.x86_64 => {
|
||||||
|
kernel.root_module.addAssemblyFile(b.path("src/kern/amd64/locore.s"));
|
||||||
|
},
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
|
||||||
kernel.linker_script = b.path(b.fmt("build/linker-scripts/{s}.lds", .{@tagName(plat.arch)}));
|
kernel.linker_script = b.path(b.fmt("build/linker-scripts/{s}.lds", .{@tagName(plat.arch)}));
|
||||||
} else {
|
} else {
|
||||||
kernel.linker_script = b.path("build/linker-scripts/uml.lds");
|
kernel.linker_script = b.path("build/linker-scripts/uml.lds");
|
||||||
|
|||||||
@@ -1,447 +0,0 @@
|
|||||||
//! Wrappers over amd64 CPU instructions and CPUID feature detection.
|
|
||||||
const std = @import("std");
|
|
||||||
|
|
||||||
pub const Msr = enum(u32) {
|
|
||||||
/// IA32_APIC_BASE
|
|
||||||
LapicBase = 0x1B,
|
|
||||||
/// IA32_FS_BASE
|
|
||||||
FsBase = 0xC000_0100,
|
|
||||||
/// IA32_GS_BASE
|
|
||||||
GsBase = 0xC000_0101,
|
|
||||||
/// IA32_KERNEL_GS_BASE
|
|
||||||
KernelGsBase = 0xC000_0102,
|
|
||||||
/// IA32_EFER
|
|
||||||
Efer = 0xC000_0080,
|
|
||||||
/// IA32_STAR
|
|
||||||
Star = 0xC000_0081,
|
|
||||||
/// IA32_LSTAR
|
|
||||||
LStar = 0xC000_0082,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const InterruptFrame = packed struct {
|
|
||||||
r15: u64,
|
|
||||||
r14: u64,
|
|
||||||
r13: u64,
|
|
||||||
r12: u64,
|
|
||||||
r11: u64,
|
|
||||||
r10: u64,
|
|
||||||
r9: u64,
|
|
||||||
r8: u64,
|
|
||||||
rsi: u64,
|
|
||||||
rdi: u64,
|
|
||||||
rbp: u64,
|
|
||||||
rdx: u64,
|
|
||||||
rcx: u64,
|
|
||||||
rbx: u64,
|
|
||||||
rax: u64,
|
|
||||||
intno: u64,
|
|
||||||
errcode: u64,
|
|
||||||
rip: u64,
|
|
||||||
cs: u64,
|
|
||||||
rflags: u64,
|
|
||||||
rsp: u64,
|
|
||||||
ss: u64,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub inline fn outb(port: u16, value: u8) void {
|
|
||||||
asm volatile ("outb %[value], %[port]"
|
|
||||||
:
|
|
||||||
: [value] "{al}" (value),
|
|
||||||
[port] "{dx}" (port),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn outw(port: u16, value: u16) void {
|
|
||||||
asm volatile ("outw %[value], %[port]"
|
|
||||||
:
|
|
||||||
: [value] "{ax}" (value),
|
|
||||||
[port] "{dx}" (port),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn outl(port: u16, value: u32) void {
|
|
||||||
asm volatile ("outl %[value], %[port]"
|
|
||||||
:
|
|
||||||
: [value] "{eax}" (value),
|
|
||||||
[port] "{dx}" (port),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn inb(port: u16) u8 {
|
|
||||||
return asm volatile ("inb %[port], %[ret]"
|
|
||||||
: [ret] "={al}" (-> u8),
|
|
||||||
: [port] "{dx}" (port),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn inw(port: u16) u16 {
|
|
||||||
return asm volatile ("inw %[port], %[ret]"
|
|
||||||
: [ret] "={ax}" (-> u16),
|
|
||||||
: [port] "{dx}" (port),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn inl(port: u16) u32 {
|
|
||||||
return asm volatile ("inl %[port], %[ret]"
|
|
||||||
: [ret] "={eax}" (-> u32),
|
|
||||||
: [port] "{dx}" (port),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn rdmsr(msr: Msr) u64 {
|
|
||||||
var low: u32 = undefined;
|
|
||||||
var high: u32 = undefined;
|
|
||||||
asm volatile ("rdmsr"
|
|
||||||
: [low] "={eax}" (low),
|
|
||||||
[high] "={edx}" (high),
|
|
||||||
: [msr] "{ecx}" (@intFromEnum(msr)),
|
|
||||||
);
|
|
||||||
return @as(u64, high) << 32 | low;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn wrmsr(msr: Msr, value: u64) void {
|
|
||||||
asm volatile ("wrmsr"
|
|
||||||
:
|
|
||||||
: [low] "{eax}" (@as(u32, @truncate(value))),
|
|
||||||
[high] "{edx}" (@as(u32, @truncate(value >> 32))),
|
|
||||||
[msr] "{ecx}" (@intFromEnum(msr)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn invlpg(addr: u64) void {
|
|
||||||
asm volatile ("invlpg (%[addr])"
|
|
||||||
:
|
|
||||||
: [addr] "r" (addr),
|
|
||||||
: .{ .memory = true });
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn sti() void {
|
|
||||||
asm volatile ("sti");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn cli() void {
|
|
||||||
asm volatile ("cli");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn hlt() void {
|
|
||||||
asm volatile ("hlt");
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn rflags() u64 {
|
|
||||||
var flags: u64 = undefined;
|
|
||||||
asm volatile ("pushfq; pop %[flags]"
|
|
||||||
: [flags] "=r" (flags),
|
|
||||||
);
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn rdtsc() u64 {
|
|
||||||
var low: u32 = undefined;
|
|
||||||
var high: u32 = undefined;
|
|
||||||
asm volatile ("rdtsc"
|
|
||||||
: [low] "={eax}" (low),
|
|
||||||
[high] "={edx}" (high),
|
|
||||||
);
|
|
||||||
return @as(u64, high) << 32 | low;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn read_cr(comptime n: u2) u64 {
|
|
||||||
comptime std.debug.assert(n != 1);
|
|
||||||
return asm volatile (std.fmt.comptimePrint("mov %%cr{}, %[ret]", .{n})
|
|
||||||
: [ret] "=r" (-> u64),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn write_cr(comptime n: u2, value: u64) void {
|
|
||||||
comptime std.debug.assert(n != 1);
|
|
||||||
asm volatile (std.fmt.comptimePrint("mov %[value], %%cr{}", .{n})
|
|
||||||
:
|
|
||||||
: [value] "r" (value),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const CpuidResult = struct { eax: u32, ebx: u32, ecx: u32, edx: u32 };
|
|
||||||
|
|
||||||
pub inline fn cpuid(leaf: u32, subleaf: u32) CpuidResult {
|
|
||||||
var eax: u32 = undefined;
|
|
||||||
var ebx: u32 = undefined;
|
|
||||||
var ecx: u32 = undefined;
|
|
||||||
var edx: u32 = undefined;
|
|
||||||
asm volatile ("cpuid"
|
|
||||||
: [eax] "={eax}" (eax),
|
|
||||||
[ebx] "={ebx}" (ebx),
|
|
||||||
[ecx] "={ecx}" (ecx),
|
|
||||||
[edx] "={edx}" (edx),
|
|
||||||
: [leaf] "{eax}" (leaf),
|
|
||||||
[subleaf] "{ecx}" (subleaf),
|
|
||||||
);
|
|
||||||
return .{ .eax = eax, .ebx = ebx, .ecx = ecx, .edx = edx };
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const CpuidRequest = union(enum) {
|
|
||||||
vendor_info,
|
|
||||||
feature_info,
|
|
||||||
extended_info,
|
|
||||||
highest_extended_function,
|
|
||||||
extended_features: ExtendedFeaturesSubLeaf,
|
|
||||||
brand_string: BrandStringPart,
|
|
||||||
power_management_info,
|
|
||||||
|
|
||||||
pub const ExtendedFeaturesSubLeaf = enum(u32) {
|
|
||||||
first = 0,
|
|
||||||
second = 1,
|
|
||||||
third = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const BrandStringPart = enum(u32) {
|
|
||||||
part0 = 0x80000002,
|
|
||||||
part1 = 0x80000003,
|
|
||||||
part2 = 0x80000004,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn execute(self: CpuidRequest) CpuidResult {
|
|
||||||
const leaf, const subleaf = switch (self) {
|
|
||||||
.vendor_info => .{ 0x0, 0 },
|
|
||||||
.feature_info => .{ 0x1, 0 },
|
|
||||||
.highest_extended_function => .{ 0x80000000, 0 },
|
|
||||||
.extended_info => .{ 0x80000001, 0 },
|
|
||||||
.power_management_info => .{ 0x80000007, 0 },
|
|
||||||
.extended_features => |s| .{ 0x7, @intFromEnum(s) },
|
|
||||||
.brand_string => |p| .{ @intFromEnum(p), 0 },
|
|
||||||
};
|
|
||||||
return cpuid(leaf, subleaf);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const FeatureInfoEcx = packed struct(u32) {
|
|
||||||
sse3: bool,
|
|
||||||
pclmul: bool,
|
|
||||||
dtes64: bool,
|
|
||||||
monitor: bool,
|
|
||||||
ds_cpl: bool,
|
|
||||||
vmx: bool,
|
|
||||||
smx: bool,
|
|
||||||
est: bool,
|
|
||||||
tm2: bool,
|
|
||||||
ssse3: bool,
|
|
||||||
cnxt_id: bool,
|
|
||||||
sdbg: bool,
|
|
||||||
fma: bool,
|
|
||||||
cx16: bool,
|
|
||||||
xtpr: bool,
|
|
||||||
pdcm: bool,
|
|
||||||
_reserved: u1,
|
|
||||||
pcid: bool,
|
|
||||||
dca: bool,
|
|
||||||
sse4_1: bool,
|
|
||||||
sse4_2: bool,
|
|
||||||
x2apic: bool,
|
|
||||||
movbe: bool,
|
|
||||||
popcnt: bool,
|
|
||||||
tsc_deadline: bool,
|
|
||||||
aes: bool,
|
|
||||||
xsave: bool,
|
|
||||||
osxsave: bool,
|
|
||||||
avx: bool,
|
|
||||||
f16c: bool,
|
|
||||||
rdrand: bool,
|
|
||||||
hypervisor: bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
const FeatureInfoEdx = packed struct(u32) {
|
|
||||||
fpu: bool,
|
|
||||||
vme: bool,
|
|
||||||
de: bool,
|
|
||||||
pse: bool,
|
|
||||||
tsc: bool,
|
|
||||||
msr: bool,
|
|
||||||
pae: bool,
|
|
||||||
mce: bool,
|
|
||||||
cx8: bool,
|
|
||||||
apic: bool,
|
|
||||||
_reserved0: u1,
|
|
||||||
sep: bool,
|
|
||||||
mtrr: bool,
|
|
||||||
pge: bool,
|
|
||||||
mca: bool,
|
|
||||||
cmov: bool,
|
|
||||||
pat: bool,
|
|
||||||
pse36: bool,
|
|
||||||
psn: bool,
|
|
||||||
clfsh: bool,
|
|
||||||
_reserved1: u1,
|
|
||||||
ds: bool,
|
|
||||||
acpi: bool,
|
|
||||||
mmx: bool,
|
|
||||||
fxsave: bool,
|
|
||||||
sse: bool,
|
|
||||||
sse2: bool,
|
|
||||||
ignore: u5,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ExtendedFeaturesEcx = packed struct(u32) {
|
|
||||||
_reserved0: u16,
|
|
||||||
la57: bool,
|
|
||||||
_reserved1: u5,
|
|
||||||
rdpid: bool,
|
|
||||||
_reserved2: u9,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ExtendedFeaturesEbx = packed struct(u32) {
|
|
||||||
ignore: u7,
|
|
||||||
smep: bool,
|
|
||||||
ignore2: u12,
|
|
||||||
smap: bool,
|
|
||||||
ignore3: u11,
|
|
||||||
};
|
|
||||||
|
|
||||||
const ExtendedProcessorInfoEdx = packed struct(u32) {
|
|
||||||
ignore: u20,
|
|
||||||
nx: bool,
|
|
||||||
ignore2: u5,
|
|
||||||
pdpe1gb: bool,
|
|
||||||
ignore3: u5,
|
|
||||||
};
|
|
||||||
|
|
||||||
const PowerManagementInfoEdx = packed struct(u32) {
|
|
||||||
ignore: u8,
|
|
||||||
invtsc: bool,
|
|
||||||
ignore2: u23,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn assert_bit(comptime T: type, comptime field_name: []const u8, comptime expected_bit: u5) void {
|
|
||||||
var v: T = @bitCast(@as(u32, 0));
|
|
||||||
@field(v, field_name) = true;
|
|
||||||
const raw: u32 = @bitCast(v);
|
|
||||||
const want = (@as(u32, 1) << expected_bit);
|
|
||||||
if (raw != want) @compileError("bit mismatch for field " ++ field_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
comptime {
|
|
||||||
assert_bit(FeatureInfoEcx, "pcid", 17);
|
|
||||||
assert_bit(FeatureInfoEcx, "x2apic", 21);
|
|
||||||
assert_bit(FeatureInfoEcx, "tsc_deadline", 24);
|
|
||||||
assert_bit(FeatureInfoEcx, "xsave", 26);
|
|
||||||
assert_bit(ExtendedFeaturesEcx, "la57", 16);
|
|
||||||
assert_bit(ExtendedProcessorInfoEdx, "nx", 20);
|
|
||||||
assert_bit(ExtendedProcessorInfoEdx, "pdpe1gb", 26);
|
|
||||||
assert_bit(PowerManagementInfoEdx, "invtsc", 8);
|
|
||||||
assert_bit(FeatureInfoEdx, "fxsave", 24);
|
|
||||||
assert_bit(ExtendedFeaturesEbx, "smap", 20);
|
|
||||||
assert_bit(ExtendedFeaturesEbx, "smep", 7);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const CpuFeatures = struct {
|
|
||||||
x2apic: bool,
|
|
||||||
five_level_paging: bool,
|
|
||||||
gib_pages: bool,
|
|
||||||
tsc_deadline: bool,
|
|
||||||
fxsave: bool,
|
|
||||||
xsave: bool,
|
|
||||||
invariant_tsc: bool,
|
|
||||||
nx: bool,
|
|
||||||
pcid: bool,
|
|
||||||
smap: bool,
|
|
||||||
smep: bool,
|
|
||||||
pge: bool,
|
|
||||||
vendor_string: [12]u8,
|
|
||||||
brand_string: [48]u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub var cpu_features: CpuFeatures = undefined;
|
|
||||||
|
|
||||||
pub fn detect_cpu_features() void {
|
|
||||||
const vendor_info = CpuidRequest.execute(.vendor_info);
|
|
||||||
const max_ext = CpuidRequest.execute(.highest_extended_function).eax;
|
|
||||||
|
|
||||||
const max_basic = vendor_info.eax;
|
|
||||||
|
|
||||||
var x2apic = false;
|
|
||||||
var five_level_paging = false;
|
|
||||||
var gib_pages = false;
|
|
||||||
var tsc_deadline = false;
|
|
||||||
var xsave = false;
|
|
||||||
var fxsave = false;
|
|
||||||
var invtsc = false;
|
|
||||||
var nx = false;
|
|
||||||
var pcid = false;
|
|
||||||
var smap = false;
|
|
||||||
var smep = false;
|
|
||||||
var pge = false;
|
|
||||||
|
|
||||||
var vendor_string: [12]u8 = undefined;
|
|
||||||
var brand_string: [48]u8 = undefined;
|
|
||||||
|
|
||||||
std.mem.writeInt(u32, vendor_string[0..4], vendor_info.ebx, .little);
|
|
||||||
std.mem.writeInt(u32, vendor_string[4..8], vendor_info.edx, .little);
|
|
||||||
std.mem.writeInt(u32, vendor_string[8..12], vendor_info.ecx, .little);
|
|
||||||
|
|
||||||
if (max_basic >= 0x1) {
|
|
||||||
const r = CpuidRequest.execute(.feature_info);
|
|
||||||
const ecx: FeatureInfoEcx = @bitCast(r.ecx);
|
|
||||||
const edx: FeatureInfoEdx = @bitCast(r.edx);
|
|
||||||
|
|
||||||
x2apic = ecx.x2apic;
|
|
||||||
tsc_deadline = ecx.tsc_deadline;
|
|
||||||
xsave = ecx.xsave;
|
|
||||||
pcid = ecx.pcid;
|
|
||||||
fxsave = edx.fxsave;
|
|
||||||
pge = edx.pge;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_basic >= 0x7) {
|
|
||||||
const r = CpuidRequest.execute(.{ .extended_features = .first });
|
|
||||||
const ecx: ExtendedFeaturesEcx = @bitCast(r.ecx);
|
|
||||||
const ebx: ExtendedFeaturesEbx = @bitCast(r.ebx);
|
|
||||||
smap = ebx.smap;
|
|
||||||
smep = ebx.smep;
|
|
||||||
five_level_paging = ecx.la57;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_ext >= 0x80000001) {
|
|
||||||
const r = CpuidRequest.execute(.extended_info);
|
|
||||||
const edx: ExtendedProcessorInfoEdx = @bitCast(r.edx);
|
|
||||||
gib_pages = edx.pdpe1gb;
|
|
||||||
nx = edx.nx;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_ext >= 0x80000004) {
|
|
||||||
const parts = [_]CpuidResult{
|
|
||||||
CpuidRequest.execute(.{ .brand_string = .part0 }),
|
|
||||||
CpuidRequest.execute(.{ .brand_string = .part1 }),
|
|
||||||
CpuidRequest.execute(.{ .brand_string = .part2 }),
|
|
||||||
};
|
|
||||||
|
|
||||||
var off: usize = 0;
|
|
||||||
for (parts) |p| {
|
|
||||||
for ([_]u32{ p.eax, p.ebx, p.ecx, p.edx }) |reg| {
|
|
||||||
const dst: *[4]u8 = @ptrCast(brand_string[off..].ptr);
|
|
||||||
std.mem.writeInt(u32, dst, reg, .little);
|
|
||||||
off += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_ext >= 0x80000007) {
|
|
||||||
const r = CpuidRequest.execute(.power_management_info);
|
|
||||||
const edx: PowerManagementInfoEdx = @bitCast(r.edx);
|
|
||||||
invtsc = edx.invtsc;
|
|
||||||
}
|
|
||||||
|
|
||||||
cpu_features = .{
|
|
||||||
.x2apic = x2apic,
|
|
||||||
.five_level_paging = five_level_paging,
|
|
||||||
.gib_pages = gib_pages,
|
|
||||||
.tsc_deadline = tsc_deadline,
|
|
||||||
.fxsave = fxsave,
|
|
||||||
.xsave = xsave,
|
|
||||||
.invariant_tsc = invtsc,
|
|
||||||
.nx = nx,
|
|
||||||
.pcid = pcid,
|
|
||||||
.smap = smap,
|
|
||||||
.smep = smep,
|
|
||||||
.vendor_string = vendor_string,
|
|
||||||
.brand_string = brand_string,
|
|
||||||
.pge = pge,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
+574
-1
@@ -1,2 +1,575 @@
|
|||||||
pub const cpu = @import("cpu.zig");
|
//! Wrappers over amd64 CPU definitions and CPUID.
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
pub const name = "amd64";
|
pub const name = "amd64";
|
||||||
|
|
||||||
|
pub const Msr = enum(u32) {
|
||||||
|
/// IA32_APIC_BASE
|
||||||
|
LapicBase = 0x1B,
|
||||||
|
/// IA32_FS_BASE
|
||||||
|
FsBase = 0xC000_0100,
|
||||||
|
/// IA32_GS_BASE
|
||||||
|
GsBase = 0xC000_0101,
|
||||||
|
/// IA32_KERNEL_GS_BASE
|
||||||
|
KernelGsBase = 0xC000_0102,
|
||||||
|
/// IA32_EFER
|
||||||
|
Efer = 0xC000_0080,
|
||||||
|
/// IA32_STAR
|
||||||
|
Star = 0xC000_0081,
|
||||||
|
/// IA32_LSTAR
|
||||||
|
LStar = 0xC000_0082,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const IrqFrame = extern struct {
|
||||||
|
r15: u64,
|
||||||
|
r14: u64,
|
||||||
|
r13: u64,
|
||||||
|
r12: u64,
|
||||||
|
r11: u64,
|
||||||
|
r10: u64,
|
||||||
|
r9: u64,
|
||||||
|
r8: u64,
|
||||||
|
rsi: u64,
|
||||||
|
rdi: u64,
|
||||||
|
rbp: u64,
|
||||||
|
rdx: u64,
|
||||||
|
rcx: u64,
|
||||||
|
rbx: u64,
|
||||||
|
rax: u64,
|
||||||
|
intno: u64,
|
||||||
|
errcode: u64,
|
||||||
|
rip: u64,
|
||||||
|
cs: u64,
|
||||||
|
rflags: u64,
|
||||||
|
rsp: u64,
|
||||||
|
ss: u64,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub inline fn outb(port: u16, value: u8) void {
|
||||||
|
asm volatile ("outb %[value], %[port]"
|
||||||
|
:
|
||||||
|
: [value] "{al}" (value),
|
||||||
|
[port] "{dx}" (port),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn outw(port: u16, value: u16) void {
|
||||||
|
asm volatile ("outw %[value], %[port]"
|
||||||
|
:
|
||||||
|
: [value] "{ax}" (value),
|
||||||
|
[port] "{dx}" (port),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn outl(port: u16, value: u32) void {
|
||||||
|
asm volatile ("outl %[value], %[port]"
|
||||||
|
:
|
||||||
|
: [value] "{eax}" (value),
|
||||||
|
[port] "{dx}" (port),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn inb(port: u16) u8 {
|
||||||
|
return asm volatile ("inb %[port], %[ret]"
|
||||||
|
: [ret] "={al}" (-> u8),
|
||||||
|
: [port] "{dx}" (port),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn inw(port: u16) u16 {
|
||||||
|
return asm volatile ("inw %[port], %[ret]"
|
||||||
|
: [ret] "={ax}" (-> u16),
|
||||||
|
: [port] "{dx}" (port),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn inl(port: u16) u32 {
|
||||||
|
return asm volatile ("inl %[port], %[ret]"
|
||||||
|
: [ret] "={eax}" (-> u32),
|
||||||
|
: [port] "{dx}" (port),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn rdmsr(msr: Msr) u64 {
|
||||||
|
var low: u32 = undefined;
|
||||||
|
var high: u32 = undefined;
|
||||||
|
asm volatile ("rdmsr"
|
||||||
|
: [low] "={eax}" (low),
|
||||||
|
[high] "={edx}" (high),
|
||||||
|
: [msr] "{ecx}" (@intFromEnum(msr)),
|
||||||
|
);
|
||||||
|
return @as(u64, high) << 32 | low;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn wrmsr(msr: Msr, value: u64) void {
|
||||||
|
asm volatile ("wrmsr"
|
||||||
|
:
|
||||||
|
: [low] "{eax}" (@as(u32, @truncate(value))),
|
||||||
|
[high] "{edx}" (@as(u32, @truncate(value >> 32))),
|
||||||
|
[msr] "{ecx}" (@intFromEnum(msr)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn invlpg(addr: u64) void {
|
||||||
|
asm volatile ("invlpg (%[addr])"
|
||||||
|
:
|
||||||
|
: [addr] "r" (addr),
|
||||||
|
: .{ .memory = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn sti() void {
|
||||||
|
asm volatile ("sti");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn cli() void {
|
||||||
|
asm volatile ("cli");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn hlt() void {
|
||||||
|
asm volatile ("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const RFlags = packed struct(u64) {
|
||||||
|
carry: bool,
|
||||||
|
_reserved0: u1,
|
||||||
|
parity: bool,
|
||||||
|
_reserved1: u1,
|
||||||
|
auxiliary: bool,
|
||||||
|
_reserved2: u1,
|
||||||
|
zero: bool,
|
||||||
|
sign: bool,
|
||||||
|
trap: bool,
|
||||||
|
interrupt_enable: bool,
|
||||||
|
direction: bool,
|
||||||
|
overflow: bool,
|
||||||
|
iopl: u2,
|
||||||
|
nested_task: bool,
|
||||||
|
_reserved3: u1,
|
||||||
|
resume_: bool,
|
||||||
|
virtual_8086_mode: bool,
|
||||||
|
alignment_check: bool,
|
||||||
|
virtual_interrupt: bool,
|
||||||
|
virtual_interrupt_pending: bool,
|
||||||
|
id: bool,
|
||||||
|
_reserved4: u42,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub inline fn rflags() RFlags {
|
||||||
|
var flags: u64 = undefined;
|
||||||
|
asm volatile ("pushfq; pop %[flags]"
|
||||||
|
: [flags] "=r" (flags),
|
||||||
|
);
|
||||||
|
return @bitCast(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn rdtsc() u64 {
|
||||||
|
var low: u32 = undefined;
|
||||||
|
var high: u32 = undefined;
|
||||||
|
asm volatile ("rdtsc"
|
||||||
|
: [low] "={eax}" (low),
|
||||||
|
[high] "={edx}" (high),
|
||||||
|
);
|
||||||
|
return @as(u64, high) << 32 | low;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const Cr0 = packed struct(u64) {
|
||||||
|
pe: bool,
|
||||||
|
mp: bool,
|
||||||
|
em: bool,
|
||||||
|
ts: bool,
|
||||||
|
et: bool,
|
||||||
|
ne: bool,
|
||||||
|
reserved: u11,
|
||||||
|
wp: bool,
|
||||||
|
reserved2: u1,
|
||||||
|
am: bool,
|
||||||
|
reserved3: u10,
|
||||||
|
nw: bool,
|
||||||
|
cd: bool,
|
||||||
|
pg: bool,
|
||||||
|
reserved4: u32,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Cr4 = packed struct(u64) {
|
||||||
|
vme: bool,
|
||||||
|
pvi: bool,
|
||||||
|
tsd: bool,
|
||||||
|
de: bool,
|
||||||
|
pse: bool,
|
||||||
|
pae: bool,
|
||||||
|
mce: bool,
|
||||||
|
pge: bool,
|
||||||
|
pce: bool,
|
||||||
|
osfxr: bool,
|
||||||
|
osxmmEex: bool,
|
||||||
|
umip: bool,
|
||||||
|
la57: bool,
|
||||||
|
reserved: u4,
|
||||||
|
fsgsbase: bool,
|
||||||
|
pcide: bool,
|
||||||
|
osxsave: bool,
|
||||||
|
reserve2: u1,
|
||||||
|
smep: bool,
|
||||||
|
smap: bool,
|
||||||
|
pke: bool,
|
||||||
|
cet: bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub inline fn read_cr(comptime n: u2) u64 {
|
||||||
|
comptime std.debug.assert(n != 1);
|
||||||
|
return asm volatile (std.fmt.comptimePrint("mov %%cr{}, %[ret]", .{n})
|
||||||
|
: [ret] "=r" (-> u64),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn write_cr(comptime n: u2, value: u64) void {
|
||||||
|
comptime std.debug.assert(n != 1);
|
||||||
|
asm volatile (std.fmt.comptimePrint("mov %[value], %%cr{}", .{n})
|
||||||
|
:
|
||||||
|
: [value] "r" (value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const CpuidResult = struct { eax: u32, ebx: u32, ecx: u32, edx: u32 };
|
||||||
|
|
||||||
|
pub inline fn cpuid(leaf: u32, subleaf: u32) CpuidResult {
|
||||||
|
var eax: u32 = undefined;
|
||||||
|
var ebx: u32 = undefined;
|
||||||
|
var ecx: u32 = undefined;
|
||||||
|
var edx: u32 = undefined;
|
||||||
|
asm volatile ("cpuid"
|
||||||
|
: [eax] "={eax}" (eax),
|
||||||
|
[ebx] "={ebx}" (ebx),
|
||||||
|
[ecx] "={ecx}" (ecx),
|
||||||
|
[edx] "={edx}" (edx),
|
||||||
|
: [leaf] "{eax}" (leaf),
|
||||||
|
[subleaf] "{ecx}" (subleaf),
|
||||||
|
);
|
||||||
|
return .{ .eax = eax, .ebx = ebx, .ecx = ecx, .edx = edx };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const CpuidRequest = union(enum) {
|
||||||
|
vendor_info,
|
||||||
|
feature_info,
|
||||||
|
extended_info,
|
||||||
|
highest_extended_function,
|
||||||
|
extended_features: ExtendedFeaturesSubLeaf,
|
||||||
|
brand_string: BrandStringPart,
|
||||||
|
power_management_info,
|
||||||
|
|
||||||
|
pub const ExtendedFeaturesSubLeaf = enum(u32) {
|
||||||
|
first = 0,
|
||||||
|
second = 1,
|
||||||
|
third = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const BrandStringPart = enum(u32) {
|
||||||
|
part0 = 0x80000002,
|
||||||
|
part1 = 0x80000003,
|
||||||
|
part2 = 0x80000004,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn execute(self: CpuidRequest) CpuidResult {
|
||||||
|
const leaf, const subleaf = switch (self) {
|
||||||
|
.vendor_info => .{ 0x0, 0 },
|
||||||
|
.feature_info => .{ 0x1, 0 },
|
||||||
|
.highest_extended_function => .{ 0x80000000, 0 },
|
||||||
|
.extended_info => .{ 0x80000001, 0 },
|
||||||
|
.power_management_info => .{ 0x80000007, 0 },
|
||||||
|
.extended_features => |s| .{ 0x7, @intFromEnum(s) },
|
||||||
|
.brand_string => |p| .{ @intFromEnum(p), 0 },
|
||||||
|
};
|
||||||
|
return cpuid(leaf, subleaf);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const FeatureInfoEcx = packed struct(u32) {
|
||||||
|
sse3: bool,
|
||||||
|
pclmul: bool,
|
||||||
|
dtes64: bool,
|
||||||
|
monitor: bool,
|
||||||
|
ds_cpl: bool,
|
||||||
|
vmx: bool,
|
||||||
|
smx: bool,
|
||||||
|
est: bool,
|
||||||
|
tm2: bool,
|
||||||
|
ssse3: bool,
|
||||||
|
cnxt_id: bool,
|
||||||
|
sdbg: bool,
|
||||||
|
fma: bool,
|
||||||
|
cx16: bool,
|
||||||
|
xtpr: bool,
|
||||||
|
pdcm: bool,
|
||||||
|
_reserved: u1,
|
||||||
|
pcid: bool,
|
||||||
|
dca: bool,
|
||||||
|
sse4_1: bool,
|
||||||
|
sse4_2: bool,
|
||||||
|
x2apic: bool,
|
||||||
|
movbe: bool,
|
||||||
|
popcnt: bool,
|
||||||
|
tsc_deadline: bool,
|
||||||
|
aes: bool,
|
||||||
|
xsave: bool,
|
||||||
|
osxsave: bool,
|
||||||
|
avx: bool,
|
||||||
|
f16c: bool,
|
||||||
|
rdrand: bool,
|
||||||
|
hypervisor: bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
const FeatureInfoEdx = packed struct(u32) {
|
||||||
|
fpu: bool,
|
||||||
|
vme: bool,
|
||||||
|
de: bool,
|
||||||
|
pse: bool,
|
||||||
|
tsc: bool,
|
||||||
|
msr: bool,
|
||||||
|
pae: bool,
|
||||||
|
mce: bool,
|
||||||
|
cx8: bool,
|
||||||
|
apic: bool,
|
||||||
|
_reserved0: u1,
|
||||||
|
sep: bool,
|
||||||
|
mtrr: bool,
|
||||||
|
pge: bool,
|
||||||
|
mca: bool,
|
||||||
|
cmov: bool,
|
||||||
|
pat: bool,
|
||||||
|
pse36: bool,
|
||||||
|
psn: bool,
|
||||||
|
clfsh: bool,
|
||||||
|
_reserved1: u1,
|
||||||
|
ds: bool,
|
||||||
|
acpi: bool,
|
||||||
|
mmx: bool,
|
||||||
|
fxsave: bool,
|
||||||
|
sse: bool,
|
||||||
|
sse2: bool,
|
||||||
|
ignore: u5,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ExtendedFeaturesEcx = packed struct(u32) {
|
||||||
|
_reserved0: u16,
|
||||||
|
la57: bool,
|
||||||
|
_reserved1: u5,
|
||||||
|
rdpid: bool,
|
||||||
|
_reserved2: u9,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ExtendedFeaturesEbx = packed struct(u32) {
|
||||||
|
ignore: u7,
|
||||||
|
smep: bool,
|
||||||
|
ignore2: u12,
|
||||||
|
smap: bool,
|
||||||
|
ignore3: u11,
|
||||||
|
};
|
||||||
|
|
||||||
|
const ExtendedProcessorInfoEdx = packed struct(u32) {
|
||||||
|
ignore: u20,
|
||||||
|
nx: bool,
|
||||||
|
ignore2: u5,
|
||||||
|
pdpe1gb: bool,
|
||||||
|
ignore3: u5,
|
||||||
|
};
|
||||||
|
|
||||||
|
const PowerManagementInfoEdx = packed struct(u32) {
|
||||||
|
ignore: u8,
|
||||||
|
invtsc: bool,
|
||||||
|
ignore2: u23,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn assert_bit(comptime T: type, comptime field_name: []const u8, comptime expected_bit: u5) void {
|
||||||
|
var v: T = @bitCast(@as(u32, 0));
|
||||||
|
@field(v, field_name) = true;
|
||||||
|
const raw: u32 = @bitCast(v);
|
||||||
|
const want = (@as(u32, 1) << expected_bit);
|
||||||
|
if (raw != want) @compileError("bit mismatch for field " ++ field_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
assert_bit(FeatureInfoEcx, "pcid", 17);
|
||||||
|
assert_bit(FeatureInfoEcx, "x2apic", 21);
|
||||||
|
assert_bit(FeatureInfoEcx, "tsc_deadline", 24);
|
||||||
|
assert_bit(FeatureInfoEcx, "xsave", 26);
|
||||||
|
assert_bit(ExtendedFeaturesEcx, "la57", 16);
|
||||||
|
assert_bit(ExtendedProcessorInfoEdx, "nx", 20);
|
||||||
|
assert_bit(ExtendedProcessorInfoEdx, "pdpe1gb", 26);
|
||||||
|
assert_bit(PowerManagementInfoEdx, "invtsc", 8);
|
||||||
|
assert_bit(FeatureInfoEdx, "fxsave", 24);
|
||||||
|
assert_bit(ExtendedFeaturesEbx, "smap", 20);
|
||||||
|
assert_bit(ExtendedFeaturesEbx, "smep", 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const CpuFeatures = struct {
|
||||||
|
x2apic: bool,
|
||||||
|
five_level_paging: bool,
|
||||||
|
gib_pages: bool,
|
||||||
|
tsc_deadline: bool,
|
||||||
|
fxsave: bool,
|
||||||
|
xsave: bool,
|
||||||
|
invariant_tsc: bool,
|
||||||
|
nx: bool,
|
||||||
|
pcid: bool,
|
||||||
|
smap: bool,
|
||||||
|
smep: bool,
|
||||||
|
pge: bool,
|
||||||
|
vendor_string: [12]u8,
|
||||||
|
brand_string: [48]u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub var cpu_features: CpuFeatures = undefined;
|
||||||
|
|
||||||
|
pub fn detect_cpu_features() void {
|
||||||
|
const vendor_info = CpuidRequest.execute(.vendor_info);
|
||||||
|
const max_ext = CpuidRequest.execute(.highest_extended_function).eax;
|
||||||
|
|
||||||
|
const max_basic = vendor_info.eax;
|
||||||
|
|
||||||
|
var x2apic = false;
|
||||||
|
var five_level_paging = false;
|
||||||
|
var gib_pages = false;
|
||||||
|
var tsc_deadline = false;
|
||||||
|
var xsave = false;
|
||||||
|
var fxsave = false;
|
||||||
|
var invtsc = false;
|
||||||
|
var nx = false;
|
||||||
|
var pcid = false;
|
||||||
|
var smap = false;
|
||||||
|
var smep = false;
|
||||||
|
var pge = false;
|
||||||
|
|
||||||
|
var vendor_string: [12]u8 = undefined;
|
||||||
|
var brand_string: [48]u8 = undefined;
|
||||||
|
|
||||||
|
std.mem.writeInt(u32, vendor_string[0..4], vendor_info.ebx, .little);
|
||||||
|
std.mem.writeInt(u32, vendor_string[4..8], vendor_info.edx, .little);
|
||||||
|
std.mem.writeInt(u32, vendor_string[8..12], vendor_info.ecx, .little);
|
||||||
|
|
||||||
|
if (max_basic >= 0x1) {
|
||||||
|
const r = CpuidRequest.execute(.feature_info);
|
||||||
|
const ecx: FeatureInfoEcx = @bitCast(r.ecx);
|
||||||
|
const edx: FeatureInfoEdx = @bitCast(r.edx);
|
||||||
|
|
||||||
|
x2apic = ecx.x2apic;
|
||||||
|
tsc_deadline = ecx.tsc_deadline;
|
||||||
|
xsave = ecx.xsave;
|
||||||
|
pcid = ecx.pcid;
|
||||||
|
fxsave = edx.fxsave;
|
||||||
|
pge = edx.pge;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_basic >= 0x7) {
|
||||||
|
const r = CpuidRequest.execute(.{ .extended_features = .first });
|
||||||
|
const ecx: ExtendedFeaturesEcx = @bitCast(r.ecx);
|
||||||
|
const ebx: ExtendedFeaturesEbx = @bitCast(r.ebx);
|
||||||
|
smap = ebx.smap;
|
||||||
|
smep = ebx.smep;
|
||||||
|
five_level_paging = ecx.la57;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_ext >= 0x80000001) {
|
||||||
|
const r = CpuidRequest.execute(.extended_info);
|
||||||
|
const edx: ExtendedProcessorInfoEdx = @bitCast(r.edx);
|
||||||
|
gib_pages = edx.pdpe1gb;
|
||||||
|
nx = edx.nx;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_ext >= 0x80000004) {
|
||||||
|
const parts = [_]CpuidResult{
|
||||||
|
CpuidRequest.execute(.{ .brand_string = .part0 }),
|
||||||
|
CpuidRequest.execute(.{ .brand_string = .part1 }),
|
||||||
|
CpuidRequest.execute(.{ .brand_string = .part2 }),
|
||||||
|
};
|
||||||
|
|
||||||
|
var off: usize = 0;
|
||||||
|
for (parts) |p| {
|
||||||
|
for ([_]u32{ p.eax, p.ebx, p.ecx, p.edx }) |reg| {
|
||||||
|
const dst: *[4]u8 = @ptrCast(brand_string[off..].ptr);
|
||||||
|
std.mem.writeInt(u32, dst, reg, .little);
|
||||||
|
off += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_ext >= 0x80000007) {
|
||||||
|
const r = CpuidRequest.execute(.power_management_info);
|
||||||
|
const edx: PowerManagementInfoEdx = @bitCast(r.edx);
|
||||||
|
invtsc = edx.invtsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu_features = .{
|
||||||
|
.x2apic = x2apic,
|
||||||
|
.five_level_paging = five_level_paging,
|
||||||
|
.gib_pages = gib_pages,
|
||||||
|
.tsc_deadline = tsc_deadline,
|
||||||
|
.fxsave = fxsave,
|
||||||
|
.xsave = xsave,
|
||||||
|
.invariant_tsc = invtsc,
|
||||||
|
.nx = nx,
|
||||||
|
.pcid = pcid,
|
||||||
|
.smap = smap,
|
||||||
|
.smep = smep,
|
||||||
|
.vendor_string = vendor_string,
|
||||||
|
.brand_string = brand_string,
|
||||||
|
.pge = pge,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const TssDescriptor = extern struct {
|
||||||
|
length: u16 align(1),
|
||||||
|
base_low: u16 align(1),
|
||||||
|
base_mid: u8 align(1),
|
||||||
|
access: u8 align(1),
|
||||||
|
flags_limit_high: u8 align(1),
|
||||||
|
base_high: u8 align(1),
|
||||||
|
base_upper: u32 align(1),
|
||||||
|
reserved: u32 align(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Tss = extern struct {
|
||||||
|
reserved1: u32 align(1),
|
||||||
|
rsp: [3]usize align(1),
|
||||||
|
reserved2: u64 align(1),
|
||||||
|
ist: [7]usize align(1),
|
||||||
|
reserved3: u64 align(1),
|
||||||
|
reserved4: u16 align(1),
|
||||||
|
iopb: u16 align(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Gdtr = extern struct {
|
||||||
|
limit: u16 align(1),
|
||||||
|
base: usize align(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Idtr = extern struct {
|
||||||
|
limit: u16 align(1),
|
||||||
|
base: usize align(1),
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const IdtEntry = extern struct {
|
||||||
|
offset_low: u16 align(1),
|
||||||
|
selector: u16 align(1),
|
||||||
|
ist: u8 align(1),
|
||||||
|
type_attr: u8 align(1),
|
||||||
|
offset_mid: u16 align(1),
|
||||||
|
offset_high: u32 align(1),
|
||||||
|
reserved: u32 align(1),
|
||||||
|
|
||||||
|
pub const Attr = enum(u8) {
|
||||||
|
InterruptGate = 0x8E,
|
||||||
|
TrapGate = 0x8F,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn init(cs: u16, ist: u8, attr: Attr, offset: usize) @This() {
|
||||||
|
return .{
|
||||||
|
.offset_low = @truncate(offset),
|
||||||
|
.selector = cs,
|
||||||
|
.ist = ist,
|
||||||
|
.type_attr = @intFromEnum(attr),
|
||||||
|
.offset_mid = @truncate(offset >> 16),
|
||||||
|
.offset_high = @truncate(offset >> 32),
|
||||||
|
.reserved = 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ const amd64 = b.arch;
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const early_init = @import("init.zig").early_init;
|
||||||
|
|
||||||
pub const Cpu = struct {
|
pub const Cpu = struct {
|
||||||
self_ptr: *Cpu,
|
self_ptr: *Cpu,
|
||||||
percpu_offset: usize,
|
percpu_offset: usize,
|
||||||
@@ -122,15 +124,15 @@ pub inline fn set_hardware_ipl(ipl: ke.Ipl) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn enable_interrupts() void {
|
pub inline fn enable_interrupts() void {
|
||||||
amd64.cpu.sti();
|
amd64.sti();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn disable_interrupts() bool {
|
pub inline fn disable_interrupts() bool {
|
||||||
const rflags = amd64.cpu.rflags();
|
const ie = amd64.rflags().interrupt_enable;
|
||||||
|
|
||||||
amd64.cpu.cli();
|
amd64.cli();
|
||||||
|
|
||||||
return rflags & (1 << 9) != 0;
|
return ie;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn restore_interrupts(state: bool) void {
|
pub inline fn restore_interrupts(state: bool) void {
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
const amd64 = @import("arch");
|
||||||
|
const int = @import("int.zig");
|
||||||
|
const b = @import("base");
|
||||||
|
|
||||||
|
var gdt = extern struct {
|
||||||
|
entries: [9]u64 align(1),
|
||||||
|
tss: amd64.TssDescriptor align(1),
|
||||||
|
}{
|
||||||
|
.entries = .{
|
||||||
|
0, // null
|
||||||
|
0x00009a000000ffff, // code16
|
||||||
|
0x000093000000ffff, // data16
|
||||||
|
0x00cf9a000000ffff, // code32
|
||||||
|
0x00cf93000000ffff, // data32
|
||||||
|
0x00af9b000000ffff, // kernel code64
|
||||||
|
0x00af93000000ffff, // kernel data64
|
||||||
|
0x00aff3000000ffff, // user code64
|
||||||
|
0x00affb000000ffff, // user data64
|
||||||
|
},
|
||||||
|
|
||||||
|
.tss = undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern fn gdt_load(gdtr: *const amd64.Gdtr) callconv(.{ .x86_64_sysv = .{} }) void;
|
||||||
|
|
||||||
|
pub fn early_init() linksection(b.init) void {
|
||||||
|
const gdtr: amd64.Gdtr = .{
|
||||||
|
.limit = @sizeOf(@TypeOf(gdt)) - 1,
|
||||||
|
.base = @intFromPtr(&gdt),
|
||||||
|
};
|
||||||
|
|
||||||
|
gdt_load(&gdtr);
|
||||||
|
|
||||||
|
int.init();
|
||||||
|
|
||||||
|
asm volatile ("int3");
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
const amd64 = @import("arch");
|
||||||
|
const std = @import("std");
|
||||||
|
const b = @import("base");
|
||||||
|
|
||||||
|
extern const __interrupt_vectors: [256]usize;
|
||||||
|
|
||||||
|
var idt: [256]amd64.IdtEntry align(16) = undefined;
|
||||||
|
|
||||||
|
const exception_msg = [32][]const u8{
|
||||||
|
"Divide Error",
|
||||||
|
"Debug",
|
||||||
|
"Non-Maskable Interrupt",
|
||||||
|
"Breakpoint",
|
||||||
|
"Overflow",
|
||||||
|
"Bound Range Exceeded",
|
||||||
|
"Invalid Opcode",
|
||||||
|
"Device Not Available",
|
||||||
|
"Double Fault",
|
||||||
|
"Coprocessor Segment Overrun",
|
||||||
|
"Invalid TSS",
|
||||||
|
"Segment Not Present",
|
||||||
|
"Stack-Segment Fault",
|
||||||
|
"General Protection Fault",
|
||||||
|
"Page Fault",
|
||||||
|
"???",
|
||||||
|
"x87 Floating-Point Exception",
|
||||||
|
"Alignment Check",
|
||||||
|
"Machine Check",
|
||||||
|
"SIMD Floating-Point Exception",
|
||||||
|
"Virtualization Exception",
|
||||||
|
"Control Protection Exception",
|
||||||
|
"???",
|
||||||
|
"???",
|
||||||
|
"???",
|
||||||
|
"???",
|
||||||
|
"???",
|
||||||
|
"???",
|
||||||
|
"???",
|
||||||
|
"???",
|
||||||
|
"???",
|
||||||
|
"Security Exception",
|
||||||
|
};
|
||||||
|
|
||||||
|
export fn isr_handler_main(frame: *const amd64.IrqFrame) callconv(.{ .x86_64_sysv = .{} }) void {
|
||||||
|
if (frame.intno < 32) {
|
||||||
|
std.log.info("Unhandled exception: 0x{x} ({s}), err=0x{x}, pc=0x{x}", .{ frame.intno, exception_msg[frame.intno], frame.errcode, frame.rip });
|
||||||
|
std.log.info("RAX=0x{x:0>16} RBX=0x{x:0>16} RCX=0x{x:0>16} RDX=0x{x:0>16}", .{ frame.rax, frame.rbx, frame.rcx, frame.rdx });
|
||||||
|
std.log.info("RSI=0x{x:0>16} RDI=0x{x:0>16} RBP=0x{x:0>16} RSP=0x{x:0>16}", .{ frame.rsi, frame.rdi, frame.rbp, frame.rsp });
|
||||||
|
std.log.info("R8= 0x{x:0>16} R9=0x{x:0>16} R10=0x{x:0>16} R11=0x{x:0>16}", .{ frame.r8, frame.r9, frame.r10, frame.r11 });
|
||||||
|
std.log.info("R12=0x{x:0>16} R13=0x{x:0>16} R14=0x{x:0>16} R15=0x{x:0>16}", .{ frame.r12, frame.r13, frame.r14, frame.r15 });
|
||||||
|
const cr2 = amd64.read_cr(2);
|
||||||
|
const cr3 = amd64.read_cr(3);
|
||||||
|
const rflags = amd64.rflags();
|
||||||
|
std.log.info("CR2=0x{x:0>16} CR3=0x{x:0>16} RFLAGS={x}", .{ cr2, cr3, @as(u64, @bitCast(rflags)) });
|
||||||
|
|
||||||
|
@panic("Unhandled exception");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn idt_load(idt_ptr: *const amd64.Idtr) callconv(.{ .x86_64_sysv = .{} }) void;
|
||||||
|
|
||||||
|
pub fn init() linksection(b.init) void {
|
||||||
|
const idtr: amd64.Idtr = .{
|
||||||
|
.limit = @sizeOf(@TypeOf(idt)) - 1,
|
||||||
|
.base = @intFromPtr(&idt),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (&idt, 0..256) |*entry, i| {
|
||||||
|
entry.* = .init(0x28, 0, .InterruptGate, __interrupt_vectors[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
idt_load(&idtr);
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
.altmacro
|
||||||
|
.code64
|
||||||
|
|
||||||
|
.section .text
|
||||||
|
.globl gdt_load
|
||||||
|
gdt_load:
|
||||||
|
lgdt (%rdi)
|
||||||
|
|
||||||
|
/* Set ss, ds and es to data segment */
|
||||||
|
mov $0x30, %ax
|
||||||
|
mov %ax, %ds
|
||||||
|
mov %ax, %es
|
||||||
|
mov %ax, %ss
|
||||||
|
|
||||||
|
/* Save return address */
|
||||||
|
pop %rdi
|
||||||
|
|
||||||
|
/* Push CS so the CPU will pop it off with retfq */
|
||||||
|
mov $0x28, %rax
|
||||||
|
push %rax
|
||||||
|
push %rdi
|
||||||
|
lretq
|
||||||
|
|
||||||
|
|
||||||
|
.globl idt_load
|
||||||
|
idt_load:
|
||||||
|
lidt (%rdi)
|
||||||
|
ret
|
||||||
|
|
||||||
|
.macro pushall
|
||||||
|
push %rax
|
||||||
|
push %rbx
|
||||||
|
push %rcx
|
||||||
|
push %rdx
|
||||||
|
push %rbp
|
||||||
|
push %rdi
|
||||||
|
push %rsi
|
||||||
|
push %r8
|
||||||
|
push %r9
|
||||||
|
push %r10
|
||||||
|
push %r11
|
||||||
|
push %r12
|
||||||
|
push %r13
|
||||||
|
push %r14
|
||||||
|
push %r15
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro popall
|
||||||
|
pop %r15
|
||||||
|
pop %r14
|
||||||
|
pop %r13
|
||||||
|
pop %r12
|
||||||
|
pop %r11
|
||||||
|
pop %r10
|
||||||
|
pop %r9
|
||||||
|
pop %r8
|
||||||
|
pop %rsi
|
||||||
|
pop %rdi
|
||||||
|
pop %rbp
|
||||||
|
pop %rdx
|
||||||
|
pop %rcx
|
||||||
|
pop %rbx
|
||||||
|
pop %rax
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.extern isr_handler_main
|
||||||
|
isr_handler:
|
||||||
|
cld
|
||||||
|
pushall
|
||||||
|
mov %rsp, %rdi
|
||||||
|
call isr_handler_main
|
||||||
|
popall
|
||||||
|
cli
|
||||||
|
add $16, %rsp
|
||||||
|
iretq
|
||||||
|
|
||||||
|
.macro INTERRUPT_NOERR num
|
||||||
|
.globl isr\num
|
||||||
|
isr\num :
|
||||||
|
pushq $0
|
||||||
|
pushq $\num
|
||||||
|
jmp isr_handler
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro INTERRUPT_ERR num
|
||||||
|
.globl isr\num
|
||||||
|
isr\num :
|
||||||
|
pushq $\num
|
||||||
|
jmp isr_handler
|
||||||
|
.endm
|
||||||
|
|
||||||
|
INTERRUPT_NOERR 0
|
||||||
|
INTERRUPT_NOERR 1
|
||||||
|
INTERRUPT_NOERR 2
|
||||||
|
INTERRUPT_NOERR 3
|
||||||
|
INTERRUPT_NOERR 4
|
||||||
|
INTERRUPT_NOERR 5
|
||||||
|
INTERRUPT_NOERR 6
|
||||||
|
INTERRUPT_NOERR 7
|
||||||
|
INTERRUPT_ERR 8
|
||||||
|
INTERRUPT_NOERR 9
|
||||||
|
INTERRUPT_ERR 10
|
||||||
|
INTERRUPT_ERR 11
|
||||||
|
INTERRUPT_ERR 12
|
||||||
|
INTERRUPT_ERR 13
|
||||||
|
INTERRUPT_ERR 14
|
||||||
|
INTERRUPT_NOERR 15
|
||||||
|
INTERRUPT_NOERR 16
|
||||||
|
INTERRUPT_ERR 17
|
||||||
|
INTERRUPT_NOERR 18
|
||||||
|
INTERRUPT_NOERR 19
|
||||||
|
INTERRUPT_NOERR 20
|
||||||
|
INTERRUPT_NOERR 21
|
||||||
|
INTERRUPT_NOERR 22
|
||||||
|
INTERRUPT_NOERR 23
|
||||||
|
INTERRUPT_NOERR 24
|
||||||
|
INTERRUPT_NOERR 25
|
||||||
|
INTERRUPT_NOERR 26
|
||||||
|
INTERRUPT_NOERR 27
|
||||||
|
INTERRUPT_NOERR 28
|
||||||
|
INTERRUPT_NOERR 29
|
||||||
|
INTERRUPT_ERR 30
|
||||||
|
INTERRUPT_NOERR 31
|
||||||
|
|
||||||
|
.rept 224
|
||||||
|
INTERRUPT_NOERR %32+\+
|
||||||
|
.endr
|
||||||
|
|
||||||
|
.global __interrupt_vectors
|
||||||
|
__interrupt_vectors:
|
||||||
|
.rept 256
|
||||||
|
.quad isr\()\+
|
||||||
|
.endr
|
||||||
@@ -11,6 +11,7 @@ var stack: [8192]u8 align(16) = undefined;
|
|||||||
|
|
||||||
pub fn init(boot_info: *pl.BootInfo) linksection(b.init) void {
|
pub fn init(boot_info: *pl.BootInfo) linksection(b.init) void {
|
||||||
std.log.info("hello, world", .{});
|
std.log.info("hello, world", .{});
|
||||||
|
ki.impl.early_init();
|
||||||
pl.early_init();
|
pl.early_init();
|
||||||
ki.cpu.init_cpu();
|
ki.cpu.init_cpu();
|
||||||
|
|
||||||
|
|||||||
+11
-12
@@ -3,35 +3,34 @@ const amd64 = b.arch;
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
const ki = b.ke.private;
|
const ki = b.ke.private;
|
||||||
const cpu = amd64.cpu;
|
|
||||||
|
|
||||||
pub const name = "PC";
|
pub const name = "PC";
|
||||||
|
|
||||||
const com1 = 0x3F8;
|
const com1 = 0x3F8;
|
||||||
|
|
||||||
fn com1_init() linksection(b.init) void {
|
fn com1_init() linksection(b.init) void {
|
||||||
cpu.outb(com1 + 0x3, 0x80);
|
amd64.outb(com1 + 0x3, 0x80);
|
||||||
cpu.outb(com1 + 0x0, 0x0c);
|
amd64.outb(com1 + 0x0, 0x0c);
|
||||||
cpu.outb(com1 + 0x1, 0x00);
|
amd64.outb(com1 + 0x1, 0x00);
|
||||||
cpu.outb(com1 + 0x3, 0x03);
|
amd64.outb(com1 + 0x3, 0x03);
|
||||||
cpu.outb(com1 + 0x2, 0xc7);
|
amd64.outb(com1 + 0x2, 0xc7);
|
||||||
cpu.outb(com1 + 0x4, 0x00);
|
amd64.outb(com1 + 0x4, 0x00);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn com1_write(c: u8) void {
|
fn com1_write(c: u8) void {
|
||||||
while ((cpu.inb(com1 + 0x5) & 0x20) == 0) {}
|
while ((amd64.inb(com1 + 0x5) & 0x20) == 0) {}
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
cpu.outb(com1, '\r');
|
amd64.outb(com1, '\r');
|
||||||
}
|
}
|
||||||
cpu.outb(com1, c);
|
amd64.outb(com1, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn early_init() linksection(b.init) void {
|
pub fn early_init() linksection(b.init) void {
|
||||||
com1_init();
|
com1_init();
|
||||||
|
|
||||||
cpu.detect_cpu_features();
|
amd64.detect_cpu_features();
|
||||||
|
|
||||||
const f = cpu.cpu_features;
|
const f = amd64.cpu_features;
|
||||||
|
|
||||||
std.log.info("amd64/cpu: {s}", .{&f.brand_string});
|
std.log.info("amd64/cpu: {s}", .{&f.brand_string});
|
||||||
std.log.info("amd64/cpu: vendor={s} x2apic={} la57={} nx={} pcid={} pge={} smap={} smep={} pdpe1g={} invtsc={} xsave={} fxsave={} tsc-deadline={}", .{
|
std.log.info("amd64/cpu: vendor={s} x2apic={} la57={} nx={} pcid={} pge={} smap={} smep={} pdpe1g={} invtsc={} xsave={} fxsave={} tsc-deadline={}", .{
|
||||||
|
|||||||
Reference in New Issue
Block a user