From 237f6a6a62944a6fcbf74e1aaad2a7b5805fd0f7 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Mon, 6 Aug 2018 12:32:16 +0200 Subject: [PATCH] nova: provide microcode data via platform_info Issue #2762 --- .../base-nova/include/nova/syscall-generic.h | 7 + repos/base-nova/ports/nova.hash | 2 +- repos/base-nova/ports/nova.port | 4 +- repos/base-nova/src/core/platform.cc | 19 +- repos/ports/run/microcode.run | 76 ++++++++ repos/ports/src/test/microcode/main.cc | 165 ++++++++++++++++++ repos/ports/src/test/microcode/target.mk | 5 + 7 files changed, 274 insertions(+), 4 deletions(-) create mode 100644 repos/ports/run/microcode.run create mode 100644 repos/ports/src/test/microcode/main.cc create mode 100644 repos/ports/src/test/microcode/target.mk diff --git a/repos/base-nova/include/nova/syscall-generic.h b/repos/base-nova/include/nova/syscall-generic.h index da1af48ea..82a127d75 100644 --- a/repos/base-nova/include/nova/syscall-generic.h +++ b/repos/base-nova/include/nova/syscall-generic.h @@ -135,6 +135,13 @@ namespace Nova { uint8_t thread; uint8_t core; uint8_t package; + uint8_t acpi_id; + uint8_t family; + uint8_t model; + uint8_t stepping:4; + uint8_t platform:3; + uint8_t reserved:1; + uint32_t patch; } __attribute__((packed)); unsigned cpu_max() const { diff --git a/repos/base-nova/ports/nova.hash b/repos/base-nova/ports/nova.hash index 8c7236710..ef975a03d 100644 --- a/repos/base-nova/ports/nova.hash +++ b/repos/base-nova/ports/nova.hash @@ -1 +1 @@ -79dfa0facd434fa14cc92d48d0474118e718139b +96a3ed33cf48798847b43f6023ae92a002224875 diff --git a/repos/base-nova/ports/nova.port b/repos/base-nova/ports/nova.port index fbc722796..9008ad492 100644 --- a/repos/base-nova/ports/nova.port +++ b/repos/base-nova/ports/nova.port @@ -2,9 +2,9 @@ LICENSE := GPLv2 VERSION := git DOWNLOADS := nova.git -# r9 branch - use r9_debug for more verbose kernel messages +# r10 branch URL(nova) := https://github.com/alex-ab/NOVA.git -REV(nova) := 720fd5033a830d9425dbb33d8ced86d01353881b +REV(nova) := b44329a8601ff3936aa77336752d85cff95f1a94 DIR(nova) := src/kernel/nova PATCHES := $(sort $(wildcard $(REP_DIR)/patches/*.patch)) diff --git a/repos/base-nova/src/core/platform.cc b/repos/base-nova/src/core/platform.cc index 1eed81280..40083c217 100644 --- a/repos/base-nova/src/core/platform.cc +++ b/repos/base-nova/src/core/platform.cc @@ -283,7 +283,7 @@ Platform::Platform() : { Hip *hip = (Hip *)__initial_sp; /* check for right API version */ - if (hip->api_version != 7) + if (hip->api_version != 8) nova_die(); /* @@ -700,6 +700,23 @@ Platform::Platform() : xml.attribute("invariant", cpuid_invariant_tsc()); xml.attribute("freq_khz" , hip->tsc_freq); }); + xml.node("cpus", [&] () { + unsigned const cpus = hip->cpus(); + for (unsigned i = 0; i < cpus; i++) { + xml.node("cpu", [&] () { + unsigned const kernel_cpu_id = Platform::kernel_cpu_id(i); + xml.attribute("id", i); + xml.attribute("package", hip->cpu_desc_of_cpu(kernel_cpu_id)->package); + xml.attribute("core", hip->cpu_desc_of_cpu(kernel_cpu_id)->core); + xml.attribute("thread", hip->cpu_desc_of_cpu(kernel_cpu_id)->thread); + xml.attribute("family", String<5>(Hex(hip->cpu_desc_of_cpu(kernel_cpu_id)->family))); + xml.attribute("model", String<5>(Hex(hip->cpu_desc_of_cpu(kernel_cpu_id)->model))); + xml.attribute("stepping", String<5>(Hex(hip->cpu_desc_of_cpu(kernel_cpu_id)->stepping))); + xml.attribute("platform", String<5>(Hex(hip->cpu_desc_of_cpu(kernel_cpu_id)->platform))); + xml.attribute("patch", String<12>(Hex(hip->cpu_desc_of_cpu(kernel_cpu_id)->patch))); + }); + } + }); }); }); diff --git a/repos/ports/run/microcode.run b/repos/ports/run/microcode.run new file mode 100644 index 000000000..13c3b850a --- /dev/null +++ b/repos/ports/run/microcode.run @@ -0,0 +1,76 @@ +assert_spec x86 + +if { [get_cmd_switch --autopilot] } { + + if {[have_include "power_on/qemu"]} { + puts "\nRun script does not support Qemu.\n" + exit 0 + } + + # platform_info data about CPUs on other kernels missing + assert_spec nova +} + +build "core init test/microcode" + +create_boot_directory + +install_config { + + + + + + + + + + + + + + + +} + +set ::env(MAKEFLAGS) s +set path_microcode [exec [genode_dir]/tool/ports/current microcode_intel] +set microcode_files [glob -dir $path_microcode/src/app/intel *-*-*] + +file copy -force {*}$microcode_files bin/ + + +set boot_modules { core ld.lib.so init test-microcode } + + +set microcode_files [glob -tails -dir bin {[0-9,a-f][0-9,a-f]-[0-9,a-f][0-9,a-f]-[0-9,a-f][0-9,a-f]}] +append boot_modules $microcode_files + + +build_boot_image $boot_modules + + +append qemu_args "-nographic " +append qemu_args "-smp 4 " + +run_genode_until "microcode check done" 30 + +# cleanup +if { [get_cmd_switch --autopilot] } { + foreach file $microcode_files { + file delete bin/$file + } +} + +# check results +grep_output {\[init -\> test-microcode} + +# no errors please +set filtered_output $output +grep_output {Error: } +compare_output_to {} + +# no warnings please +set output $filtered_output +grep_output {Warning: } +compare_output_to {} diff --git a/repos/ports/src/test/microcode/main.cc b/repos/ports/src/test/microcode/main.cc new file mode 100644 index 000000000..0a872f8be --- /dev/null +++ b/repos/ports/src/test/microcode/main.cc @@ -0,0 +1,165 @@ +/* + * \brief Testing microcode status + * \author Alexander Boetcher + * \date 2018-08-01 + * + */ + +/* + * Copyright (C) 2018 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include + +#include + +using Genode::uint8_t; + +struct Microcode : Genode::Mmio +{ + struct Version : Register< 0, 32> { }; + struct Revision : Register< 4, 32> { }; + struct Date : Register< 8, 32> { + struct Year : Bitfield< 0, 16> { }; + struct Day : Bitfield<16, 8> { }; + struct Month : Bitfield<24, 8> { }; + }; + struct Cpuid : Register<12, 32> { + struct Stepping : Bitfield< 0, 4> { }; + struct Model : Bitfield< 4, 4> { }; + struct Family : Bitfield< 8, 4> { }; + struct Type : Bitfield< 12, 2> { }; + struct Model_ext : Bitfield< 16, 4> { }; + struct Family_ext : Bitfield< 20, 8> { }; + }; + struct Processor_flags : Register<24, 32> { + struct Flags : Bitfield< 0, 8> { }; + }; + struct Datasize : Register<28, 32> { }; + struct Totalsize : Register<32, 32> { }; + + Microcode(Genode::addr_t const addr) : Mmio(addr) { } +}; + +static void read_micro_code_rom(Genode::Env &env, Genode::String<9> &rom_name, + unsigned const id, uint8_t const family, + uint8_t const model, uint8_t const stepping, + uint8_t const platform, unsigned const patch) +{ + using namespace Genode; + + try { + Attached_rom_dataspace mc_rom(env, rom_name.string()); + Microcode mc_bits(reinterpret_cast(mc_rom.local_addr())); + + unsigned total_size = mc_bits.read(); + unsigned data_size = mc_bits.read(); + + /* see Intel - 9.11 MICROCODE UPDATE FACILITIES */ + if (data_size == 0) data_size = 2000; + if (total_size == 0) total_size = data_size + 48; + + if (total_size < data_size || total_size <= 48) { + error(id, " ", rom_name, " - microcode sizes are bogus ", total_size, " ", data_size); + return; + } + unsigned const extension_size = total_size - data_size - 48; + if (extension_size) + warning("microcode patch contains extension we don't support yet!"); + + if (mc_bits.read() != 1) { + error(id, " ", rom_name, " - unsupported microcode version"); + return; + } + + uint8_t mc_family = (mc_bits.read() << 4) + | mc_bits.read(); + uint8_t mc_model = (mc_bits.read() << 4) + | mc_bits.read(); + uint8_t mc_stepping = mc_bits.read(); + unsigned mc_patch = mc_bits.read(); + uint8_t mc_flags = mc_bits.read(); + + bool const platform_match = (1U << platform) & mc_flags; + bool const match = (mc_family == family) && (mc_model == model) && + (mc_stepping == stepping) && platform_match; + + log(id, + " ", Hex(family, Hex::OMIT_PREFIX, Hex::PAD), + ":", Hex(model, Hex::OMIT_PREFIX, Hex::PAD), + ":", Hex(stepping, Hex::OMIT_PREFIX, Hex::PAD), + " [", Hex(patch, Hex::OMIT_PREFIX), "]", + " - microcode: " + " ", Hex(mc_family, Hex::OMIT_PREFIX, Hex::PAD), + ":", Hex(mc_model, Hex::OMIT_PREFIX, Hex::PAD), + ":", Hex(mc_stepping, Hex::OMIT_PREFIX, Hex::PAD), + " [", Hex(mc_patch, Hex::OMIT_PREFIX), "] from ", + Hex(mc_bits.read(), Hex::OMIT_PREFIX), "/", + Hex(mc_bits.read() , Hex::OMIT_PREFIX), "/", + Hex(mc_bits.read() , Hex::OMIT_PREFIX), + match ? " matches" : " mismatches", + platform_match ? "" : ", platform mismatch"); + + if (!match) + warning(id, " - microcode not applicable to CPU"); + else + if (mc_patch > patch) + warning(id, " - microcode of CPU is not on last patch level!"); + } catch (...) { + warning(id, " ", rom_name, " - no microcode available"); + } +} + +static void inline cpuid(unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) +{ + asm volatile ("cpuid" : "+a" (*eax), "+d" (*edx), "+b" (*ebx), "+c"(*ecx) :: "memory"); +} + +void Component::construct(Genode::Env &env) +{ + using namespace Genode; + + /* we support currently solely Intel CPUs */ + uint32_t eax = 0x0, ebx = 0, edx = 0, ecx = 0; + cpuid(&eax, &ebx, &ecx, &edx); + const char * intel = "GenuineIntel"; + + if (memcmp(intel, &ebx, 4) || memcmp(intel + 4, &edx, 4) || memcmp(intel + 8, &ecx, 4)) { + error("no Intel CPU detected"); + return; + } + + Attached_rom_dataspace const platform_info { env, "platform_info" }; + + log("CPU family:model:stepping [patch]"); + + try { + Xml_node const cpus = platform_info.xml().sub_node("hardware").sub_node("cpus"); + cpus.for_each_sub_node("cpu", [&] (Xml_node cpu) { + uint8_t family = 0, model = 0, stepping = 0, platform = 0; + unsigned id = 0, patch = 0; + + cpu.attribute("id").value(&id); + cpu.attribute("family").value(&family); + cpu.attribute("model").value(&model); + cpu.attribute("stepping").value(&stepping); + cpu.attribute("platform").value(&platform); + cpu.attribute("patch").value(&patch); + + String<9> name(Hex(family, Hex::OMIT_PREFIX, Hex::PAD), "-", + Hex(model, Hex::OMIT_PREFIX, Hex::PAD), "-", + Hex(stepping, Hex::OMIT_PREFIX, Hex::PAD)); + + read_micro_code_rom(env, name, id, family, model, stepping, + platform, patch); + }); + } catch (...) { + error("could not parse CPU data from platform_info"); + } + log("microcode check done"); +} diff --git a/repos/ports/src/test/microcode/target.mk b/repos/ports/src/test/microcode/target.mk new file mode 100644 index 000000000..13437bcdf --- /dev/null +++ b/repos/ports/src/test/microcode/target.mk @@ -0,0 +1,5 @@ +TARGET = test-microcode +SRC_CC = main.cc +LIBS = base + +REQUIRES = nova