110 lines
3.5 KiB
Zig
110 lines
3.5 KiB
Zig
const std = @import("std");
|
|
|
|
const amd = @import("microcode/amd.zig");
|
|
const cpu = @import("cpu.zig");
|
|
const cpio = @import("formats/cpio.zig");
|
|
const intel = @import("microcode/intel.zig");
|
|
const log = @import("logger.zig").log;
|
|
const msr = @import("msr.zig");
|
|
|
|
/// Base path to microcode updates
|
|
const microcode_path = "sys/microcode/";
|
|
|
|
const amd_vendor_string = "AuthenticAMD";
|
|
const intel_vendor_string = "GenuineIntel";
|
|
|
|
const log_update_found = "[microcode] Found microcode update file";
|
|
const panic_filename_overflow = "Microcode filename buffer overflow";
|
|
|
|
/// Returns the patchlevel of the current logical processor,
|
|
/// if known
|
|
pub fn patchlevel() ?u64 {
|
|
const vendor = cpu.CpuId.vendor();
|
|
|
|
return if (std.mem.eql(u8, &vendor, amd_vendor_string))
|
|
cpu.rdmsr(msr.ucode_amd_patchlevel)
|
|
else
|
|
cpu.rdmsr(msr.ia32_bios_sign_id) >> 32;
|
|
}
|
|
|
|
/// Update the microcode of the current logical processor (manifacturer dependent)
|
|
/// Returns true if the update was successful
|
|
/// This function should be run sequentially on each logical core
|
|
/// to ensure the updates are fully applied
|
|
pub fn update(context: var, fileFn: fn (@TypeOf(context), []const u8) ?[]const u8) bool {
|
|
var filename_buffer = [_]u8{0} ** 64;
|
|
|
|
const sign = cpu.CpuId.signature();
|
|
const vendor = cpu.CpuId.vendor();
|
|
|
|
if (std.mem.eql(u8, &vendor, amd_vendor_string)) {
|
|
const family = sign.family();
|
|
const filename = std.fmt.bufPrint(&filename_buffer, microcode_path ++ "amd/microcode_amd_fam{0x:0>2}h.bin", .{family}) catch @panic(panic_filename_overflow);
|
|
|
|
const microcode = if (fileFn(context, filename)) |mc|
|
|
mc
|
|
else if (fileFn(context, microcode_path ++ "amd/microcode_amd.bin")) |mc|
|
|
mc
|
|
else
|
|
return false;
|
|
|
|
log(.Debug, log_update_found, .{});
|
|
|
|
if (amd.apply(microcode)) |applied| {
|
|
return applied;
|
|
} else |err| {
|
|
log(.Debug, "[microcode] Microcode update failed: {}", .{err});
|
|
return false;
|
|
}
|
|
} else if (std.mem.eql(u8, &vendor, intel_vendor_string)) {
|
|
const filename = std.fmt.bufPrint(&filename_buffer, microcode_path ++ "intel/{0x:0>2}-{1x:0>2}-{2x:0>2}", .{ sign.baseFamily(), sign.baseModel(), sign.stepping() }) catch @panic(panic_filename_overflow);
|
|
|
|
const microcode = if (fileFn(context, filename)) |mc|
|
|
mc
|
|
else
|
|
return false;
|
|
|
|
log(.Debug, log_update_found, .{});
|
|
|
|
const microcode_align = if (@ptrToInt(µcode[0]) & 0b1111 == 0) bl: {
|
|
break :bl @intToPtr([*]align(16) u8, @ptrToInt(µcode[0]))[0..microcode.len];
|
|
} else {
|
|
log(.Warning, "[microcode] Update failed due to misaligned data", .{});
|
|
return false;
|
|
};
|
|
|
|
if (intel.apply(microcode_align)) |applied| {
|
|
return applied;
|
|
} else |err| {
|
|
log(.Debug, "[microcode] Microcode update failed: {}", .{err});
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
pub fn update_cpio(disk: cpio.Cpio) bool {
|
|
const fileFn = struct {
|
|
pub fn fileFn(context: cpio.Cpio, filename: []const u8) ?[]const u8 {
|
|
var cpio_context = context;
|
|
|
|
if (cpio_context.findFile(filename)) |err_file| {
|
|
const file = err_file catch return null;
|
|
return file.data() catch return null;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}.fileFn;
|
|
|
|
return update(disk, fileFn);
|
|
}
|
|
|
|
pub const MicrocodeError = error{
|
|
EndOfData,
|
|
Invalid,
|
|
ChecksumMismatch,
|
|
Incompatible,
|
|
};
|