mirror of
https://github.com/rdmsr/zag.git
synced 2026-10-31 15:28:21 +00:00
feat(amd64): add a bunch of stuff
This commit is contained in:
@@ -0,0 +1,102 @@
|
|||||||
|
//! KVM paravirtualization support.
|
||||||
|
const std = @import("std");
|
||||||
|
const amd64 = @import("../root.zig");
|
||||||
|
|
||||||
|
pub const Features = packed struct(u32) {
|
||||||
|
clocksource: bool,
|
||||||
|
nop_io_delay: bool,
|
||||||
|
mmu_op: bool,
|
||||||
|
clocksource2: bool,
|
||||||
|
async_pf: bool,
|
||||||
|
steal_time: bool,
|
||||||
|
pv_eoi: bool,
|
||||||
|
pv_unhalt: bool,
|
||||||
|
_reserved0: u1,
|
||||||
|
pv_tlb_flush: bool,
|
||||||
|
async_pf_vmexit: bool,
|
||||||
|
pv_send_ipi: bool,
|
||||||
|
pv_poll_control: bool,
|
||||||
|
pv_sched_yield: bool,
|
||||||
|
async_pf_int: bool,
|
||||||
|
msi_ext_dest_id: bool,
|
||||||
|
hc_map_gpa_range: bool,
|
||||||
|
migration_control: bool,
|
||||||
|
_reserved1: u14,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Info = struct {
|
||||||
|
features: Features,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Msr = enum(u32) {
|
||||||
|
SystemTime = 0x4B564D01,
|
||||||
|
WallClock = 0x4B564D00,
|
||||||
|
AsyncPf = 0x4B564D02,
|
||||||
|
AsyncPfEn = 0x4B564D03,
|
||||||
|
StealTime = 0x4B564D04,
|
||||||
|
PvEoi = 0x4B564D05,
|
||||||
|
AsyncPfInt = 0x4B564D06,
|
||||||
|
_,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn read_msr(msr: Msr) u64 {
|
||||||
|
return amd64.rdmsr(@intFromEnum(msr));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_msr(msr: Msr, value: u64) void {
|
||||||
|
amd64.wrmsr(@intFromEnum(msr), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const PVClock = extern struct {
|
||||||
|
version: u32,
|
||||||
|
pad0: u32,
|
||||||
|
tsc_timestamp: u64,
|
||||||
|
system_time: u64,
|
||||||
|
tsc_to_system_mul: u32,
|
||||||
|
tsc_shift: i8,
|
||||||
|
flags: u8,
|
||||||
|
pad1: [2]u8,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const PVClockSource = struct {
|
||||||
|
page: *volatile PVClock,
|
||||||
|
time_at_boot: u64,
|
||||||
|
|
||||||
|
pub fn read(self: *PVClockSource) u64 {
|
||||||
|
while (true) {
|
||||||
|
const ver = @atomicLoad(u32, &self.page.version, .acquire);
|
||||||
|
if (ver & 1 != 0) continue;
|
||||||
|
|
||||||
|
const tsc_shift = self.page.tsc_shift;
|
||||||
|
const tsc_delta = amd64.rdtsc() - self.page.tsc_timestamp;
|
||||||
|
const shifted = if (tsc_shift >= 0)
|
||||||
|
tsc_delta << @intCast(tsc_shift)
|
||||||
|
else
|
||||||
|
tsc_delta >> @intCast(-tsc_shift);
|
||||||
|
const ns = self.page.system_time +
|
||||||
|
(shifted * @as(u128, self.page.tsc_to_system_mul) >> 32);
|
||||||
|
|
||||||
|
if (@atomicLoad(u32, &self.page.version, .acquire) == ver)
|
||||||
|
return @as(u64, @truncate(ns)) - self.time_at_boot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(phys_page: usize, virt_page: usize) PVClockSource {
|
||||||
|
const page: *volatile PVClock = @ptrFromInt(virt_page);
|
||||||
|
write_msr(.SystemTime, phys_page | 1);
|
||||||
|
var src = PVClockSource{ .page = page, .time_at_boot = 0 };
|
||||||
|
src.time_at_boot = src.read();
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn detect(highest_function: u32) Info {
|
||||||
|
if (highest_function < 0x40000001) {
|
||||||
|
return .{ .features = @bitCast(@as(u32, 0)) };
|
||||||
|
}
|
||||||
|
|
||||||
|
const r = amd64.cpuid(0x40000001, 0);
|
||||||
|
return Info{
|
||||||
|
.features = @bitCast(r.eax),
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
//! Hypervisor detection and identification.
|
||||||
|
const std = @import("std");
|
||||||
|
const amd64 = @import("root.zig");
|
||||||
|
pub const kvm = @import("hv/kvm.zig");
|
||||||
|
|
||||||
|
pub const Vendor = enum(u32) {
|
||||||
|
Unknown,
|
||||||
|
KVM,
|
||||||
|
TCG,
|
||||||
|
VMWare,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const VendorData = union(Vendor) {
|
||||||
|
Unknown: void,
|
||||||
|
KVM: kvm.Info,
|
||||||
|
TCG: void,
|
||||||
|
VMWare: void,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Info = struct {
|
||||||
|
vendor: Vendor,
|
||||||
|
data: VendorData,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub var info: ?Info = null;
|
||||||
|
|
||||||
|
const known_vendors = [_]struct {
|
||||||
|
string: *const [12:0]u8,
|
||||||
|
vendor: Vendor,
|
||||||
|
}{
|
||||||
|
.{ .string = "KVMKVMKVM\x00\x00\x00", .vendor = .KVM },
|
||||||
|
.{ .string = "TCGTCGTCG\x00\x00\x00", .vendor = .TCG },
|
||||||
|
.{ .string = "VMwareVMware", .vendor = .VMWare },
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn detect() void {
|
||||||
|
const r = amd64.CpuidRequest.execute(.HypervisorId);
|
||||||
|
var hypervisor_brand: [12]u8 = undefined;
|
||||||
|
std.mem.writeInt(u32, hypervisor_brand[0..4], r.ebx, .little);
|
||||||
|
std.mem.writeInt(u32, hypervisor_brand[4..8], r.ecx, .little);
|
||||||
|
std.mem.writeInt(u32, hypervisor_brand[8..12], r.edx, .little);
|
||||||
|
|
||||||
|
var vendor = Vendor.Unknown;
|
||||||
|
|
||||||
|
for (known_vendors) |h| {
|
||||||
|
if (std.mem.eql(u8, hypervisor_brand[0..], h.string[0..])) {
|
||||||
|
vendor = h.vendor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const data: VendorData = switch (vendor) {
|
||||||
|
.KVM => .{ .KVM = kvm.detect(r.eax) },
|
||||||
|
.Unknown, .TCG, .VMWare => .{ .Unknown = {} },
|
||||||
|
};
|
||||||
|
|
||||||
|
info = Info{
|
||||||
|
.vendor = vendor,
|
||||||
|
.data = data,
|
||||||
|
};
|
||||||
|
}
|
||||||
+155
-92
@@ -1,6 +1,8 @@
|
|||||||
//! Wrappers over amd64 CPU definitions and CPUID.
|
//! Wrappers over amd64 CPU definitions and CPUID.
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const hypervisor = @import("hypervisor.zig");
|
||||||
|
|
||||||
pub const name = "amd64";
|
pub const name = "amd64";
|
||||||
|
|
||||||
pub const Msr = enum(u32) {
|
pub const Msr = enum(u32) {
|
||||||
@@ -24,6 +26,24 @@ pub const Msr = enum(u32) {
|
|||||||
_,
|
_,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const Efer = packed struct(u64) {
|
||||||
|
sce: bool,
|
||||||
|
reserved0: u7,
|
||||||
|
lme: bool,
|
||||||
|
reserved1: u1,
|
||||||
|
lma: bool,
|
||||||
|
nxe: bool,
|
||||||
|
svme: bool,
|
||||||
|
lmsle: bool,
|
||||||
|
ffxsr: bool,
|
||||||
|
tce: bool,
|
||||||
|
reserved2: u1,
|
||||||
|
mcommit: bool,
|
||||||
|
interruptible_wb: bool,
|
||||||
|
uaie: bool,
|
||||||
|
reserved3: u44,
|
||||||
|
};
|
||||||
|
|
||||||
pub const IrqFrame = extern struct {
|
pub const IrqFrame = extern struct {
|
||||||
r15: u64,
|
r15: u64,
|
||||||
r14: u64,
|
r14: u64,
|
||||||
@@ -173,11 +193,11 @@ pub fn pio_write(comptime T: type, port: u16, value: T) void {
|
|||||||
|
|
||||||
pub const RFlags = packed struct(u64) {
|
pub const RFlags = packed struct(u64) {
|
||||||
carry: bool,
|
carry: bool,
|
||||||
_reserved0: u1,
|
reserved0: u1,
|
||||||
parity: bool,
|
parity: bool,
|
||||||
_reserved1: u1,
|
reserved1: u1,
|
||||||
auxiliary: bool,
|
auxiliary: bool,
|
||||||
_reserved2: u1,
|
reserved2: u1,
|
||||||
zero: bool,
|
zero: bool,
|
||||||
sign: bool,
|
sign: bool,
|
||||||
trap: bool,
|
trap: bool,
|
||||||
@@ -186,14 +206,14 @@ pub const RFlags = packed struct(u64) {
|
|||||||
overflow: bool,
|
overflow: bool,
|
||||||
iopl: u2,
|
iopl: u2,
|
||||||
nested_task: bool,
|
nested_task: bool,
|
||||||
_reserved3: u1,
|
reserved3: u1,
|
||||||
resume_: bool,
|
resume_: bool,
|
||||||
virtual_8086_mode: bool,
|
virtual_8086_mode: bool,
|
||||||
alignment_check: bool,
|
alignment_check: bool,
|
||||||
virtual_interrupt: bool,
|
virtual_interrupt: bool,
|
||||||
virtual_interrupt_pending: bool,
|
virtual_interrupt_pending: bool,
|
||||||
id: bool,
|
id: bool,
|
||||||
_reserved4: u42,
|
reserved4: u42,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub inline fn rflags() RFlags {
|
pub inline fn rflags() RFlags {
|
||||||
@@ -221,17 +241,22 @@ pub const Cr0 = packed struct(u64) {
|
|||||||
ts: bool,
|
ts: bool,
|
||||||
et: bool,
|
et: bool,
|
||||||
ne: bool,
|
ne: bool,
|
||||||
reserved: u11,
|
reserved0: u11,
|
||||||
wp: bool,
|
wp: bool,
|
||||||
reserved2: u1,
|
reserved1: u1,
|
||||||
am: bool,
|
am: bool,
|
||||||
reserved3: u10,
|
reserved2: u10,
|
||||||
nw: bool,
|
nw: bool,
|
||||||
cd: bool,
|
cd: bool,
|
||||||
pg: bool,
|
pg: bool,
|
||||||
reserved4: u32,
|
reserved3: u31,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
comptime {
|
||||||
|
_ = Cr0;
|
||||||
|
_ = Cr4;
|
||||||
|
}
|
||||||
|
|
||||||
pub const Cr4 = packed struct(u64) {
|
pub const Cr4 = packed struct(u64) {
|
||||||
vme: bool,
|
vme: bool,
|
||||||
pvi: bool,
|
pvi: bool,
|
||||||
@@ -242,15 +267,15 @@ pub const Cr4 = packed struct(u64) {
|
|||||||
mce: bool,
|
mce: bool,
|
||||||
pge: bool,
|
pge: bool,
|
||||||
pce: bool,
|
pce: bool,
|
||||||
osfxr: bool,
|
osfxsr: bool,
|
||||||
osxmmEex: bool,
|
osxmmexcpt: bool,
|
||||||
umip: bool,
|
umip: bool,
|
||||||
la57: bool,
|
la57: bool,
|
||||||
reserved: u3,
|
reserved0: u3,
|
||||||
fsgsbase: bool,
|
fsgsbase: bool,
|
||||||
pcide: bool,
|
pcide: bool,
|
||||||
osxsave: bool,
|
osxsave: bool,
|
||||||
reserve2: u1,
|
reserved1: u1,
|
||||||
smep: bool,
|
smep: bool,
|
||||||
smap: bool,
|
smap: bool,
|
||||||
pke: bool,
|
pke: bool,
|
||||||
@@ -292,37 +317,37 @@ pub inline fn cpuid(leaf: u32, subleaf: u32) CpuidResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const CpuidRequest = union(enum) {
|
pub const CpuidRequest = union(enum) {
|
||||||
vendor_info,
|
VendorInfo,
|
||||||
feature_info,
|
FeatureInfo,
|
||||||
extended_info,
|
ExtendedInfo,
|
||||||
highest_extended_function,
|
HighestExtendedFunction,
|
||||||
extended_features: ExtendedFeaturesSubLeaf,
|
ExtendedFeatures: ExtendedFeaturesSubLeaf,
|
||||||
brand_string: BrandStringPart,
|
BrandString: BrandStringPart,
|
||||||
power_management_info,
|
PowerManagementInfo,
|
||||||
hypervisor_id,
|
HypervisorId,
|
||||||
|
|
||||||
pub const ExtendedFeaturesSubLeaf = enum(u32) {
|
pub const ExtendedFeaturesSubLeaf = enum(u32) {
|
||||||
first = 0,
|
First = 0,
|
||||||
second = 1,
|
Second = 1,
|
||||||
third = 3,
|
Third = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const BrandStringPart = enum(u32) {
|
pub const BrandStringPart = enum(u32) {
|
||||||
part0 = 0x80000002,
|
Part0 = 0x80000002,
|
||||||
part1 = 0x80000003,
|
Part1 = 0x80000003,
|
||||||
part2 = 0x80000004,
|
Part2 = 0x80000004,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn execute(self: CpuidRequest) CpuidResult {
|
pub fn execute(self: CpuidRequest) CpuidResult {
|
||||||
const leaf, const subleaf = switch (self) {
|
const leaf, const subleaf = switch (self) {
|
||||||
.vendor_info => .{ 0x0, 0 },
|
.VendorInfo => .{ 0x0, 0 },
|
||||||
.feature_info => .{ 0x1, 0 },
|
.FeatureInfo => .{ 0x1, 0 },
|
||||||
.highest_extended_function => .{ 0x80000000, 0 },
|
.HighestExtendedFunction => .{ 0x80000000, 0 },
|
||||||
.extended_info => .{ 0x80000001, 0 },
|
.ExtendedInfo => .{ 0x80000001, 0 },
|
||||||
.power_management_info => .{ 0x80000007, 0 },
|
.PowerManagementInfo => .{ 0x80000007, 0 },
|
||||||
.extended_features => |s| .{ 0x7, @intFromEnum(s) },
|
.ExtendedFeatures => |s| .{ 0x7, @intFromEnum(s) },
|
||||||
.brand_string => |p| .{ @intFromEnum(p), 0 },
|
.BrandString => |p| .{ @intFromEnum(p), 0 },
|
||||||
.hypervisor_id => .{ 0x40000000, 0 },
|
.HypervisorId => .{ 0x40000000, 0 },
|
||||||
};
|
};
|
||||||
return cpuid(leaf, subleaf);
|
return cpuid(leaf, subleaf);
|
||||||
}
|
}
|
||||||
@@ -345,7 +370,7 @@ const FeatureInfoEcx = packed struct(u32) {
|
|||||||
cx16: bool,
|
cx16: bool,
|
||||||
xtpr: bool,
|
xtpr: bool,
|
||||||
pdcm: bool,
|
pdcm: bool,
|
||||||
_reserved: u1,
|
reserved0: u1,
|
||||||
pcid: bool,
|
pcid: bool,
|
||||||
dca: bool,
|
dca: bool,
|
||||||
sse4_1: bool,
|
sse4_1: bool,
|
||||||
@@ -374,7 +399,7 @@ const FeatureInfoEdx = packed struct(u32) {
|
|||||||
mce: bool,
|
mce: bool,
|
||||||
cx8: bool,
|
cx8: bool,
|
||||||
apic: bool,
|
apic: bool,
|
||||||
_reserved0: u1,
|
reserved0: u1,
|
||||||
sep: bool,
|
sep: bool,
|
||||||
mtrr: bool,
|
mtrr: bool,
|
||||||
pge: bool,
|
pge: bool,
|
||||||
@@ -384,44 +409,69 @@ const FeatureInfoEdx = packed struct(u32) {
|
|||||||
pse36: bool,
|
pse36: bool,
|
||||||
psn: bool,
|
psn: bool,
|
||||||
clfsh: bool,
|
clfsh: bool,
|
||||||
_reserved1: u1,
|
reserved1: u1,
|
||||||
ds: bool,
|
ds: bool,
|
||||||
acpi: bool,
|
acpi: bool,
|
||||||
mmx: bool,
|
mmx: bool,
|
||||||
fxsave: bool,
|
fxsave: bool,
|
||||||
sse: bool,
|
sse: bool,
|
||||||
sse2: bool,
|
sse2: bool,
|
||||||
ignore: u5,
|
reserved2: u5,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ExtendedFeaturesEcx = packed struct(u32) {
|
const ExtendedFeaturesEcx = packed struct(u32) {
|
||||||
_reserved0: u16,
|
reserved0: u2,
|
||||||
|
umip: bool,
|
||||||
|
reserved1: u13,
|
||||||
la57: bool,
|
la57: bool,
|
||||||
_reserved1: u5,
|
reserved2: u5,
|
||||||
rdpid: bool,
|
rdpid: bool,
|
||||||
_reserved2: u9,
|
reserved3: u9,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ExtendedFeaturesEbx = packed struct(u32) {
|
const ExtendedFeaturesEbx = packed struct(u32) {
|
||||||
ignore: u7,
|
reserved0: u7,
|
||||||
smep: bool,
|
smep: bool,
|
||||||
ignore2: u12,
|
reserved1: u12,
|
||||||
smap: bool,
|
smap: bool,
|
||||||
ignore3: u11,
|
reserved2: u11,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ExtendedProcessorInfoEdx = packed struct(u32) {
|
const ExtendedProcessorInfoEdx = packed struct(u32) {
|
||||||
ignore: u20,
|
fpu: bool,
|
||||||
|
vme: bool,
|
||||||
|
de: bool,
|
||||||
|
pse: bool,
|
||||||
|
tsc: bool,
|
||||||
|
msr: bool,
|
||||||
|
pae: bool,
|
||||||
|
mce: bool,
|
||||||
|
cx8: bool,
|
||||||
|
apic: bool,
|
||||||
|
reserved0: u1,
|
||||||
|
syscall_sysret: bool,
|
||||||
|
mtrr: bool,
|
||||||
|
pge: bool,
|
||||||
|
mca: bool,
|
||||||
|
cmov: bool,
|
||||||
|
pat: bool,
|
||||||
|
pse36: bool,
|
||||||
|
reserved1: u1,
|
||||||
|
mp: bool,
|
||||||
nx: bool,
|
nx: bool,
|
||||||
ignore2: u5,
|
reserved2: u5,
|
||||||
pdpe1gb: bool,
|
pdpe1gb: bool,
|
||||||
ignore3: u5,
|
rdtscp: bool,
|
||||||
|
reserved3: u1,
|
||||||
|
lm: bool,
|
||||||
|
_3dnowext: bool,
|
||||||
|
_3dnow: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
const PowerManagementInfoEdx = packed struct(u32) {
|
const PowerManagementInfoEdx = packed struct(u32) {
|
||||||
ignore: u8,
|
reserved0: u8,
|
||||||
invtsc: bool,
|
invtsc: bool,
|
||||||
ignore2: u23,
|
reserved1: u23,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn assert_bit(comptime T: type, comptime field_name: []const u8, comptime expected_bit: u5) void {
|
fn assert_bit(comptime T: type, comptime field_name: []const u8, comptime expected_bit: u5) void {
|
||||||
@@ -446,6 +496,22 @@ comptime {
|
|||||||
assert_bit(ExtendedFeaturesEbx, "smep", 7);
|
assert_bit(ExtendedFeaturesEbx, "smep", 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const CpuVendor = enum {
|
||||||
|
Intel,
|
||||||
|
Amd,
|
||||||
|
Hygon,
|
||||||
|
Unknown,
|
||||||
|
};
|
||||||
|
|
||||||
|
const known_vendors = [_]struct {
|
||||||
|
string: *const [12:0]u8,
|
||||||
|
vendor: CpuVendor,
|
||||||
|
}{
|
||||||
|
.{ .string = "GenuineIntel", .vendor = .Intel },
|
||||||
|
.{ .string = "AuthenticAMD", .vendor = .Amd },
|
||||||
|
.{ .string = "HygonGenuine", .vendor = .Hygon },
|
||||||
|
};
|
||||||
|
|
||||||
pub const CpuFeatures = struct {
|
pub const CpuFeatures = struct {
|
||||||
x2apic: bool,
|
x2apic: bool,
|
||||||
five_level_paging: bool,
|
five_level_paging: bool,
|
||||||
@@ -459,7 +525,10 @@ pub const CpuFeatures = struct {
|
|||||||
smap: bool,
|
smap: bool,
|
||||||
smep: bool,
|
smep: bool,
|
||||||
pge: bool,
|
pge: bool,
|
||||||
vendor_string: [12]u8,
|
syscall: bool,
|
||||||
|
umip: bool,
|
||||||
|
vendor: CpuVendor,
|
||||||
|
family: u8,
|
||||||
brand_string: [48]u8,
|
brand_string: [48]u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -474,42 +543,20 @@ pub const HypervisorInfo = struct {
|
|||||||
highest_function: u32,
|
highest_function: u32,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub var hypervisor_info: ?HypervisorInfo = null;
|
|
||||||
pub var cpu_features: CpuFeatures = undefined;
|
pub var cpu_features: CpuFeatures = undefined;
|
||||||
|
|
||||||
const known_hypervisors = [_]struct {
|
fn detect_vendor(string: [12]u8) CpuVendor {
|
||||||
vendor_string: *const [12:0]u8,
|
for (known_vendors) |v| {
|
||||||
vendor: HypervisorVendor,
|
if (std.mem.eql(u8, string[0..], v.string[0..])) {
|
||||||
}{
|
return v.vendor;
|
||||||
.{ .vendor_string = "KVMKVMKVM\x00\x00\x00", .vendor = HypervisorVendor.KVM },
|
|
||||||
};
|
|
||||||
|
|
||||||
fn detect_hypervisor() void {
|
|
||||||
const r = CpuidRequest.execute(.hypervisor_id);
|
|
||||||
var hypervisor_brand: [12]u8 = undefined;
|
|
||||||
std.mem.writeInt(u32, hypervisor_brand[0..4], r.ebx, .little);
|
|
||||||
std.mem.writeInt(u32, hypervisor_brand[4..8], r.ecx, .little);
|
|
||||||
std.mem.writeInt(u32, hypervisor_brand[8..12], r.edx, .little);
|
|
||||||
|
|
||||||
var vendor = HypervisorVendor.Unknown;
|
|
||||||
|
|
||||||
for (known_hypervisors) |h| {
|
|
||||||
if (std.mem.eql(u8, hypervisor_brand[0..], h.vendor_string[0..])) {
|
|
||||||
vendor = h.vendor;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return .Unknown;
|
||||||
hypervisor_info = HypervisorInfo{
|
|
||||||
.brand_string = hypervisor_brand,
|
|
||||||
.vendor = vendor,
|
|
||||||
.highest_function = r.eax,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn detect_cpu_features() void {
|
pub fn detect_cpu_features() void {
|
||||||
const vendor_info = CpuidRequest.execute(.vendor_info);
|
const vendor_info = CpuidRequest.execute(.VendorInfo);
|
||||||
const max_ext = CpuidRequest.execute(.highest_extended_function).eax;
|
const max_ext = CpuidRequest.execute(.HighestExtendedFunction).eax;
|
||||||
|
|
||||||
const max_basic = vendor_info.eax;
|
const max_basic = vendor_info.eax;
|
||||||
|
|
||||||
@@ -525,7 +572,10 @@ pub fn detect_cpu_features() void {
|
|||||||
var smap = false;
|
var smap = false;
|
||||||
var smep = false;
|
var smep = false;
|
||||||
var pge = false;
|
var pge = false;
|
||||||
var hypervisor = false;
|
var hypervisor_flag = false;
|
||||||
|
var syscall = false;
|
||||||
|
var family: u8 = 0;
|
||||||
|
var umip = false;
|
||||||
|
|
||||||
var vendor_string: [12]u8 = undefined;
|
var vendor_string: [12]u8 = undefined;
|
||||||
var brand_string: [48]u8 = undefined;
|
var brand_string: [48]u8 = undefined;
|
||||||
@@ -534,8 +584,10 @@ pub fn detect_cpu_features() void {
|
|||||||
std.mem.writeInt(u32, vendor_string[4..8], vendor_info.edx, .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);
|
std.mem.writeInt(u32, vendor_string[8..12], vendor_info.ecx, .little);
|
||||||
|
|
||||||
|
const vendor = detect_vendor(vendor_string);
|
||||||
|
|
||||||
if (max_basic >= 0x1) {
|
if (max_basic >= 0x1) {
|
||||||
const r = CpuidRequest.execute(.feature_info);
|
const r = CpuidRequest.execute(.FeatureInfo);
|
||||||
const ecx: FeatureInfoEcx = @bitCast(r.ecx);
|
const ecx: FeatureInfoEcx = @bitCast(r.ecx);
|
||||||
const edx: FeatureInfoEdx = @bitCast(r.edx);
|
const edx: FeatureInfoEdx = @bitCast(r.edx);
|
||||||
|
|
||||||
@@ -545,30 +597,38 @@ pub fn detect_cpu_features() void {
|
|||||||
pcid = ecx.pcid;
|
pcid = ecx.pcid;
|
||||||
fxsave = edx.fxsave;
|
fxsave = edx.fxsave;
|
||||||
pge = edx.pge;
|
pge = edx.pge;
|
||||||
hypervisor = ecx.hypervisor;
|
hypervisor_flag = ecx.hypervisor;
|
||||||
|
|
||||||
|
const sig = r.eax;
|
||||||
|
family = @truncate((sig >> 8) & 0xf);
|
||||||
|
if (family == 0xf) {
|
||||||
|
family +%= @truncate((sig >> 20) & 0xff);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_basic >= 0x7) {
|
if (max_basic >= 0x7) {
|
||||||
const r = CpuidRequest.execute(.{ .extended_features = .first });
|
const r = CpuidRequest.execute(.{ .ExtendedFeatures = .First });
|
||||||
const ecx: ExtendedFeaturesEcx = @bitCast(r.ecx);
|
const ecx: ExtendedFeaturesEcx = @bitCast(r.ecx);
|
||||||
const ebx: ExtendedFeaturesEbx = @bitCast(r.ebx);
|
const ebx: ExtendedFeaturesEbx = @bitCast(r.ebx);
|
||||||
smap = ebx.smap;
|
smap = ebx.smap;
|
||||||
smep = ebx.smep;
|
smep = ebx.smep;
|
||||||
five_level_paging = ecx.la57;
|
five_level_paging = ecx.la57;
|
||||||
|
umip = ecx.umip;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_ext >= 0x80000001) {
|
if (max_ext >= 0x80000001) {
|
||||||
const r = CpuidRequest.execute(.extended_info);
|
const r = CpuidRequest.execute(.ExtendedInfo);
|
||||||
const edx: ExtendedProcessorInfoEdx = @bitCast(r.edx);
|
const edx: ExtendedProcessorInfoEdx = @bitCast(r.edx);
|
||||||
gib_pages = edx.pdpe1gb;
|
gib_pages = edx.pdpe1gb;
|
||||||
nx = edx.nx;
|
nx = edx.nx;
|
||||||
|
syscall = edx.syscall_sysret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_ext >= 0x80000004) {
|
if (max_ext >= 0x80000004) {
|
||||||
const parts = [_]CpuidResult{
|
const parts = [_]CpuidResult{
|
||||||
CpuidRequest.execute(.{ .brand_string = .part0 }),
|
CpuidRequest.execute(.{ .BrandString = .Part0 }),
|
||||||
CpuidRequest.execute(.{ .brand_string = .part1 }),
|
CpuidRequest.execute(.{ .BrandString = .Part1 }),
|
||||||
CpuidRequest.execute(.{ .brand_string = .part2 }),
|
CpuidRequest.execute(.{ .BrandString = .Part2 }),
|
||||||
};
|
};
|
||||||
|
|
||||||
var off: usize = 0;
|
var off: usize = 0;
|
||||||
@@ -582,13 +642,13 @@ pub fn detect_cpu_features() void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (max_ext >= 0x80000007) {
|
if (max_ext >= 0x80000007) {
|
||||||
const r = CpuidRequest.execute(.power_management_info);
|
const r = CpuidRequest.execute(.PowerManagementInfo);
|
||||||
const edx: PowerManagementInfoEdx = @bitCast(r.edx);
|
const edx: PowerManagementInfoEdx = @bitCast(r.edx);
|
||||||
invtsc = edx.invtsc;
|
invtsc = edx.invtsc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hypervisor) {
|
if (hypervisor_flag) {
|
||||||
detect_hypervisor();
|
hypervisor.detect();
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu_features = .{
|
cpu_features = .{
|
||||||
@@ -603,9 +663,12 @@ pub fn detect_cpu_features() void {
|
|||||||
.pcid = pcid,
|
.pcid = pcid,
|
||||||
.smap = smap,
|
.smap = smap,
|
||||||
.smep = smep,
|
.smep = smep,
|
||||||
.vendor_string = vendor_string,
|
.vendor = vendor,
|
||||||
.brand_string = brand_string,
|
.brand_string = brand_string,
|
||||||
.pge = pge,
|
.pge = pge,
|
||||||
|
.family = family,
|
||||||
|
.umip = umip,
|
||||||
|
.syscall = syscall,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,11 @@
|
|||||||
const amd64 = @import("arch");
|
const amd64 = @import("arch");
|
||||||
|
const kvm = amd64.hypervisor.kvm;
|
||||||
const b = @import("base");
|
const b = @import("base");
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const mm = b.mm;
|
const mm = b.mm;
|
||||||
const ke = b.ke;
|
const ke = b.ke;
|
||||||
|
|
||||||
const PVClock = extern struct {
|
var pvclock_src: kvm.PVClockSource = undefined;
|
||||||
version: u32,
|
|
||||||
pad0: u32,
|
|
||||||
tsc_timestamp: u64,
|
|
||||||
system_time: u64,
|
|
||||||
tsc_to_system_mul: u32,
|
|
||||||
tsc_shift: i8,
|
|
||||||
flags: u8,
|
|
||||||
pad1: [2]u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
var pvclock: *PVClock = undefined;
|
|
||||||
|
|
||||||
var pvclock_tc: ke.TimeCounter = .{
|
var pvclock_tc: ke.TimeCounter = .{
|
||||||
.name = "pvclock",
|
.name = "pvclock",
|
||||||
.quality = 75,
|
.quality = 75,
|
||||||
@@ -27,35 +16,12 @@ var pvclock_tc: ke.TimeCounter = .{
|
|||||||
.n = 0,
|
.n = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
var time_at_boot: u64 = 0;
|
|
||||||
|
|
||||||
pub fn init() linksection(b.init) void {
|
pub fn init() linksection(b.init) void {
|
||||||
const page = mm.phys.alloc();
|
const page = mm.phys.alloc();
|
||||||
pvclock = @ptrFromInt(mm.p2v(page));
|
pvclock_src = kvm.PVClockSource.init(page, mm.p2v(page));
|
||||||
|
|
||||||
amd64.write_msr(.KvmSystemTimeNew, page | 1);
|
|
||||||
|
|
||||||
time_at_boot = read_pvclock();
|
|
||||||
|
|
||||||
ke.time.register_source(&pvclock_tc);
|
ke.time.register_source(&pvclock_tc);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_pvclock() u64 {
|
fn read_pvclock() u64 {
|
||||||
while (true) {
|
return pvclock_src.read();
|
||||||
const ver = b.mmio_read(u32, @intFromPtr(&pvclock.version));
|
|
||||||
if (ver & 1 != 0) continue; // Update in progress.
|
|
||||||
|
|
||||||
const tsc_shift = b.mmio_read(i8, @intFromPtr(&pvclock.tsc_shift));
|
|
||||||
|
|
||||||
const tsc_delta = amd64.rdtsc() - b.mmio_read(u64, @intFromPtr(&pvclock.tsc_timestamp));
|
|
||||||
const shifted = if (tsc_shift >= 0)
|
|
||||||
tsc_delta << @intCast(tsc_shift)
|
|
||||||
else
|
|
||||||
tsc_delta >> @intCast(-tsc_shift);
|
|
||||||
|
|
||||||
const ns = b.mmio_read(u64, @intFromPtr(&pvclock.system_time)) +
|
|
||||||
(shifted * @as(u128, b.mmio_read(u32, @intFromPtr(&pvclock.tsc_to_system_mul))) >> 32);
|
|
||||||
|
|
||||||
if (b.mmio_read(u32, @intFromPtr(&pvclock.version)) == ver) return @as(u64, @truncate(ns)) - time_at_boot;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user