Xenon/src/cpu.zig

284 lines
7.7 KiB
Zig

const std = @import("std");
const msr = @import("msr.zig");
inline fn bit(value: var, comptime pos: @IntType(false, std.math.log2_int(u16, @typeInfo(@TypeOf(value)).Int.bits))) bool {
return (value & (1 << pos)) != 0;
}
pub const CpuId = struct {
const Self = @This();
a: u32,
b: u32,
c: u32,
d: u32,
pub fn instructionSupport() InstructionSupport {
const standard = cpuid(0x00000001);
const extended = cpuid(0x80000001);
const structured = cpuid(0x00000007);
return InstructionSupport{
// TODO All flags
.sse = bit(standard.d, 25),
.sse2 = bit(standard.d, 26),
.sse3 = bit(standard.c, 0),
.avx = bit(standard.c, 28),
.aes = bit(standard.c, 25),
.sha = bit(structured.b, 29),
};
}
pub fn signature() Signature {
const sign = cpuid(1);
return Signature{
.value = sign.a,
};
}
pub fn vendor() [12]u8 {
var result = [_]u8{0} ** 12;
const name = cpuid(0);
// bitCast crashes the compiler
comptime var i = 0;
comptime const shifts = [_]u5{ 0, 8, 16, 24 };
inline for (shifts) |s| {
result[i] = @intCast(u8, name.b >> s & 255);
i += 1;
}
inline for (shifts) |s| {
result[i] = @intCast(u8, name.d >> s & 255);
i += 1;
}
inline for (shifts) |s| {
result[i] = @intCast(u8, name.c >> s & 255);
i += 1;
}
return result;
}
pub const InstructionSupport = packed struct {
clfsh: bool = false,
cmpxchg8b: bool = false,
cmpxchg16b: bool = false,
cmov: bool = false,
msr: bool = false,
tsc: bool = false,
rdtscp: bool = false,
syscallsysret: bool = false,
sysentersysexit: bool = false,
fpu: bool = false,
x87_and_cmov: bool = false,
mmx: bool = false,
_3dnow: bool = false,
mmxext: bool = false,
_3dnowext: bool = false,
_3dnowprefetch: bool = false,
sse: bool = false,
sse2: bool = false,
sse3: bool = false,
ssse3: bool = false,
sse4a: bool = false,
sse41: bool = false,
sse42: bool = false,
lm: bool = false,
svm: bool = false,
avx: bool = false,
avx2: bool = false,
xop: bool = false,
aes: bool = false,
fma: bool = false,
fma4: bool = false,
f16c: bool = false,
rdrand: bool = false,
abm: bool = false,
bmi1: bool = false,
bmi2: bool = false,
popcnt: bool = false,
tbm: bool = false,
movbe: bool = false,
monitor: bool = false,
monitorx: bool = false,
pclmulqdq: bool = false,
fxsr: bool = false,
skinit: bool = false,
lahfsahf: bool = false,
fsgsbase: bool = false,
sha: bool = false,
clflopt: bool = false,
smap: bool = false,
adx: bool = false,
rdseed: bool = false,
sme: bool = false,
sev: bool = false,
pageflushmsr: bool = false,
es: bool = false,
clzero: bool = false,
instruction_retired_counter: bool = false,
error_pointer_zero_restore: bool = false,
xsaveopt: bool = false,
xsavec_with_ecx1: bool = false,
xgetbv: bool = false,
xsaves_xrstors: bool = false,
xsave: bool = false,
};
pub const Signature = struct {
value: u32,
pub inline fn stepping(self: Signature) u4 {
return @intCast(u4, self.value & 0xf);
}
pub inline fn baseModel(self: Signature) u4 {
return @intCast(u4, (self.value & 0xf << 4) >> 4);
}
pub inline fn baseFamily(self: Signature) u4 {
return @intCast(u4, (self.value & 0xf << 8) >> 8);
}
pub inline fn extModel(self: Signature) u4 {
return @intCast(u4, (self.value & 0xf << 16) >> 16);
}
pub inline fn extFamily(self: Signature) u8 {
return @intCast(u4, (self.value & 0xf << 20) >> 20);
}
pub fn model(self: Signature) u8 {
const base = @intCast(u8, self.baseModel());
return base + if (base == 0xf) (@intCast(u8, self.extModel()) << 4) else 0;
}
pub fn family(self: Signature) u8 {
const base = @intCast(u8, self.baseFamily());
return base + if (base == 0xf) self.extFamily() else 0;
}
pub fn format(self: *const @This(), comptime fmt: []const u8, options: std.fmt.FormatOptions, context: var, comptime Errors: type, output: fn (@TypeOf(context), []const u8) Errors!void) Errors!void {
try std.fmt.format(context, Errors, output, "Family {x}h model {} stepping {} - {x}", .{ self.family(), self.model(), self.stepping(), self.value });
}
};
};
pub fn cpuid(function: u32) CpuId {
var a: u32 = undefined;
var b: u32 = undefined;
var c: u32 = undefined;
var d: u32 = undefined;
asm volatile ("cpuid"
: [a] "={eax}" (a),
[b] "={ebx}" (b),
[c] "={ecx}" (c),
[d] "={edx}" (d)
: [function] "{eax}" (function)
);
return CpuId{
.a = a,
.b = b,
.c = c,
.d = d,
};
}
pub const Capabilities = struct {
physical_address_width: u8 = 32,
virtual_address_width: u8 = 32,
gigabyte_pages: bool = false,
no_execute: bool = false,
pub fn initialize(self: *@This()) void {
const addr_width = cpuid(0x80000008);
self.physical_address_width = @intCast(u8, addr_width.a & 255);
self.virtual_address_width = @intCast(u8, addr_width.a >> 8 & 255);
const caps = cpuid(0x80000001);
if (bit(caps.d, 20) or bit(caps.d, 29)) { // EFER available
var extended_features_enables = rdmsr(msr.ia32_efer);
extended_features_enables |= 1 << 11; // Set no execute
wrmsr(msr.ia32_efer, extended_features_enables);
extended_features_enables = rdmsr(msr.ia32_efer);
if (bit(extended_features_enables, 11))
self.no_execute = true;
}
if (bit(caps.d, 26)) {
self.gigabyte_pages = true;
}
}
};
pub inline fn hlt() void {
asm volatile ("hlt");
}
pub inline fn lgdt(addr: u64) void {
asm volatile ("lgdt %[addr]"
: [addr] "r" (addr)
);
}
pub inline fn lidt(addr: u64) void {
asm volatile ("lidt %[addr]"
: [addr] "r" (addr)
);
}
pub inline fn outb(port: u16, data: u8) void {
asm volatile ("out %[data], %[port]"
:
: [port] "{dx}" (port),
[data] "{al}" (data)
);
}
pub inline fn rdmsr(reg: u32) u64 {
var value_low: u32 = undefined;
var value_high: u32 = undefined;
asm volatile ("rdmsr"
: [ret_low] "={eax}" (value_low),
[ret_high] "={edx}" (value_high)
: [reg] "{ecx}" (reg)
);
return @intCast(u64, value_high) << 32 | value_low;
}
pub inline fn wrmsr(reg: u32, value: u64) void {
asm volatile ("wrmsr"
:
: [reg] "{ecx}" (reg),
[value_low] "{eax}" (@intCast(u32, value & 0xffff)),
[value_high] "{edx}" (@intCast(u32, (value & 0xffff0000) >> 32))
);
}
pub const register = struct {
pub inline fn cr3() u64 {
return asm volatile ("movq %%cr3, %%rax"
: [ret] "={rax}" (-> u64)
);
}
pub inline fn cr3Set(addr: u64) void {
return asm volatile ("movq %[addr], %%cr3"
:
: [addr] "r" (addr)
: "memory"
);
}
pub inline fn sp() u64 {
return asm volatile (""
: [ret] "={rsp}" (-> u64)
);
}
};