feat(amd64): basic hypervisor detection

This commit is contained in:
Loïc Grégoire
2026-04-11 15:19:24 -04:00
parent 1a91a0bf52
commit ffe533c978
2 changed files with 57 additions and 1 deletions
+52
View File
@@ -18,6 +18,8 @@ pub const Msr = enum(u32) {
Star = 0xC000_0081,
/// IA32_LSTAR
LStar = 0xC000_0082,
/// MSR_KVM_SYSTEM_TIME_NEW
KvmSystemTimeNew = 0x4B564D01,
};
pub const IrqFrame = extern struct {
@@ -263,6 +265,7 @@ pub const CpuidRequest = union(enum) {
extended_features: ExtendedFeaturesSubLeaf,
brand_string: BrandStringPart,
power_management_info,
hypervisor_id,
pub const ExtendedFeaturesSubLeaf = enum(u32) {
first = 0,
@@ -285,6 +288,7 @@ pub const CpuidRequest = union(enum) {
.power_management_info => .{ 0x80000007, 0 },
.extended_features => |s| .{ 0x7, @intFromEnum(s) },
.brand_string => |p| .{ @intFromEnum(p), 0 },
.hypervisor_id => .{ 0x40000000, 0 },
};
return cpuid(leaf, subleaf);
}
@@ -425,8 +429,50 @@ pub const CpuFeatures = struct {
brand_string: [48]u8,
};
pub const HypervisorVendor = enum(u32) {
Unknown = 0,
KVM = 1,
};
pub const HypervisorInfo = struct {
brand_string: [12]u8,
vendor: HypervisorVendor,
highest_function: u32,
};
pub var hypervisor_info: ?HypervisorInfo = null;
pub var cpu_features: CpuFeatures = undefined;
const known_hypervisors = [_]struct {
vendor_string: *const [12:0]u8,
vendor: HypervisorVendor,
}{
.{ .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;
}
}
hypervisor_info = HypervisorInfo{
.brand_string = hypervisor_brand,
.vendor = vendor,
.highest_function = r.eax,
};
}
pub fn detect_cpu_features() void {
const vendor_info = CpuidRequest.execute(.vendor_info);
const max_ext = CpuidRequest.execute(.highest_extended_function).eax;
@@ -445,6 +491,7 @@ pub fn detect_cpu_features() void {
var smap = false;
var smep = false;
var pge = false;
var hypervisor = false;
var vendor_string: [12]u8 = undefined;
var brand_string: [48]u8 = undefined;
@@ -464,6 +511,7 @@ pub fn detect_cpu_features() void {
pcid = ecx.pcid;
fxsave = edx.fxsave;
pge = edx.pge;
hypervisor = ecx.hypervisor;
}
if (max_basic >= 0x7) {
@@ -505,6 +553,10 @@ pub fn detect_cpu_features() void {
invtsc = edx.invtsc;
}
if (hypervisor) {
detect_hypervisor();
}
cpu_features = .{
.x2apic = x2apic,
.five_level_paging = five_level_paging,
+5 -1
View File
@@ -34,7 +34,7 @@ pub fn early_init(boot_info: *pl.BootInfo) linksection(b.init) void {
const f = amd64.cpu_features;
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} features={}{}{}{}{}{}{}{}{}{}{}{}", .{
&f.vendor_string,
@intFromBool(f.x2apic),
@intFromBool(f.five_level_paging),
@@ -49,6 +49,10 @@ pub fn early_init(boot_info: *pl.BootInfo) linksection(b.init) void {
@intFromBool(f.fxsave),
@intFromBool(f.tsc_deadline),
});
if (amd64.hypervisor_info) |h| {
std.log.info("amd64/cpu: running on hypervisor {s}", .{@tagName(h.vendor)});
}
_ = boot_info;
}