From 75ed04e7ef71f928f12ee5f3382572d30afed7b8 Mon Sep 17 00:00:00 2001 From: maksyuki Date: Fri, 25 Sep 2026 11:22:13 +0800 Subject: [PATCH] feat: update HP Linux configuration validation and adjust simulation time --- Makefile | 4 +- app/ports/linux/linux/retrosoc_hp.config | 4 + publications/datasheets/system-reference.json | 2 +- rtl/mini/top/axi4_data_crossbar.sv | 190 ++++++++++-------- scripts/build_hp_linux.py | 31 +++ tests/rtl/axi4_data_crossbar_tb.sv | 111 ++++++++++ tests/test_hp_platform.py | 28 ++- 7 files changed, 286 insertions(+), 84 deletions(-) diff --git a/Makefile b/Makefile index c9ff7259..49ce6280 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,7 @@ HP_BOOT_BUNDLE_NAME ?= retrosoc_hp_linux HP_BOOT_BUNDLE_BIN := $(SW_BUILD_DIR)/$(HP_BOOT_BUNDLE_NAME).bin HP_BOOT_BUNDLE_HEX := $(SW_BUILD_DIR)/$(HP_BOOT_BUNDLE_NAME).hex HP_BOOT_BUNDLE_MANIFEST := $(SW_BUILD_DIR)/$(HP_BOOT_BUNDLE_NAME).json -HP_LINUX_SIM_TIME ?= 7200 +HP_LINUX_SIM_TIME ?= 0 HP_SMOKE_SIM_TIME ?= 300 HP_SMOKE_BUILD_DIR := $(VARIANT_ROOT)/hp-smoke HP_SMOKE_STAMP := $(HP_SMOKE_BUILD_DIR)/images/.stamp @@ -731,4 +731,4 @@ regress-nightly: python3 $(ROOT_PATH)/scripts/regress.py --root $(ROOT_PATH) --suite nightly sim-asm: asm - $(MAKE) SIM_FIRMWARE_NAME=$(ASM_FIRMWARE_NAME) sim \ No newline at end of file + $(MAKE) SIM_FIRMWARE_NAME=$(ASM_FIRMWARE_NAME) sim diff --git a/app/ports/linux/linux/retrosoc_hp.config b/app/ports/linux/linux/retrosoc_hp.config index 61fd5c4f..e8549004 100644 --- a/app/ports/linux/linux/retrosoc_hp.config +++ b/app/ports/linux/linux/retrosoc_hp.config @@ -5,6 +5,10 @@ CONFIG_RISCV_ISA_A=y CONFIG_RISCV_ISA_C=y CONFIG_FPU=y CONFIG_SMP=n +CONFIG_PRINTK=y +CONFIG_TTY=y +CONFIG_BINFMT_ELF=y +CONFIG_BINFMT_SCRIPT=y CONFIG_HVC_RISCV_SBI=y CONFIG_SERIAL_EARLYCON_RISCV_SBI=y CONFIG_SIFIVE_PLIC=y diff --git a/publications/datasheets/system-reference.json b/publications/datasheets/system-reference.json index 1aae1f64..ef6922a9 100644 --- a/publications/datasheets/system-reference.json +++ b/publications/datasheets/system-reference.json @@ -5222,7 +5222,7 @@ { "id": "kernel-sbi", "file": "app/ports/linux/linux/retrosoc_hp.config", - "text": "CONFIG_SMP=n\nCONFIG_HVC_RISCV_SBI=y\nCONFIG_SERIAL_EARLYCON_RISCV_SBI=y" + "text": "CONFIG_SMP=n\nCONFIG_PRINTK=y\nCONFIG_TTY=y\nCONFIG_BINFMT_ELF=y\nCONFIG_BINFMT_SCRIPT=y\nCONFIG_HVC_RISCV_SBI=y\nCONFIG_SERIAL_EARLYCON_RISCV_SBI=y" }, { "id": "kernel-ready-support", diff --git a/rtl/mini/top/axi4_data_crossbar.sv b/rtl/mini/top/axi4_data_crossbar.sv index ba3e1009..470347bf 100644 --- a/rtl/mini/top/axi4_data_crossbar.sv +++ b/rtl/mini/top/axi4_data_crossbar.sv @@ -108,11 +108,11 @@ module axi4_data_crossbar #( logic user; } read_resp_t; - addr_channel_t m_aw [NumMasters]; - addr_channel_t m_ar [NumMasters]; - write_channel_t m_w [NumMasters]; - write_resp_t m_b [NumMasters]; - read_resp_t m_r [NumMasters]; + addr_channel_t m_aw [NumMasters]; + addr_channel_t m_ar [NumMasters]; + write_channel_t m_w [NumMasters]; + write_resp_t m_b [NumMasters]; + read_resp_t m_r [NumMasters]; logic [NumMasters-1:0] m_awvalid; logic [NumMasters-1:0] m_awready; logic [NumMasters-1:0] m_wvalid; @@ -124,11 +124,11 @@ module axi4_data_crossbar #( logic [NumMasters-1:0] m_rvalid; logic [NumMasters-1:0] m_rready; - addr_channel_t t_aw [NumTargets]; - addr_channel_t t_ar [NumTargets]; - write_channel_t t_w [NumTargets]; - write_resp_t t_b [NumTargets]; - read_resp_t t_r [NumTargets]; + addr_channel_t t_aw [NumTargets]; + addr_channel_t t_ar [NumTargets]; + write_channel_t t_w [NumTargets]; + write_resp_t t_b [NumTargets]; + read_resp_t t_r [NumTargets]; logic [NumTargets-1:0] t_awvalid; logic [NumTargets-1:0] t_awready; logic [NumTargets-1:0] t_wvalid; @@ -154,6 +154,7 @@ module axi4_data_crossbar #( logic [NumTargets-1:0] s_write_capture; logic [NumMasters-1:0][ NumTargets-1:0] s_read_resp_req; + logic [NumMasters-1:0][ NumTargets-1:0] s_read_resp_arb_req; logic [NumMasters-1:0][ NumTargets-1:0] s_write_resp_req; logic [NumMasters-1:0][ NumTargets-1:0] unused_read_resp_grant; logic [NumMasters-1:0][ NumTargets-1:0] unused_write_resp_grant; @@ -163,27 +164,30 @@ module axi4_data_crossbar #( logic [NumMasters-1:0] s_write_resp_valid; logic [NumMasters-1:0] s_read_terminal; logic [NumMasters-1:0] s_write_terminal; - logic [NumTargets-1:0] s_invalid_read_response; - logic [NumTargets-1:0] s_invalid_write_response; - logic [NumTargets-1:0] s_invalid_read_fault_accept; - logic [NumTargets-1:0] s_invalid_write_fault_accept; - logic s_protocol_fault_pending; - logic s_protocol_fault_event; - logic s_protocol_recovery_q; + logic [NumMasters-1:0] s_read_resp_lock_d, s_read_resp_lock_q; + logic [NumMasters-1:0][TargetWidth-1:0] s_read_resp_lock_target_d; + logic [NumMasters-1:0][TargetWidth-1:0] s_read_resp_lock_target_q; + logic [NumTargets-1:0] s_invalid_read_response; + logic [NumTargets-1:0] s_invalid_write_response; + logic [NumTargets-1:0] s_invalid_read_fault_accept; + logic [NumTargets-1:0] s_invalid_write_fault_accept; + logic s_protocol_fault_pending; + logic s_protocol_fault_event; + logic s_protocol_recovery_q; - logic [NumTargets-1:0] s_target_write_owner_full; - logic [NumTargets-1:0] s_target_write_owner_empty; - logic [NumTargets-1:0] s_target_write_owner_push; - logic [NumTargets-1:0] s_target_write_owner_pop; - logic [NumTargets-1:0][MasterWidth-1:0] s_target_write_owner_data; - logic [NumTargets-1:0][ 1:0] unused_target_write_owner_count; + logic [NumTargets-1:0] s_target_write_owner_full; + logic [NumTargets-1:0] s_target_write_owner_empty; + logic [NumTargets-1:0] s_target_write_owner_push; + logic [NumTargets-1:0] s_target_write_owner_pop; + logic [NumTargets-1:0][MasterWidth-1:0] s_target_write_owner_data; + logic [NumTargets-1:0][ 1:0] unused_target_write_owner_count; - logic [NumMasters-1:0][TargetWidth-1:0] s_read_decoded_target; - logic [NumMasters-1:0][TargetWidth-1:0] s_write_decoded_target; - logic [NumMasters-1:0][TargetWidth-1:0] s_read_routed_target; - logic [NumMasters-1:0][TargetWidth-1:0] s_write_routed_target; - logic [NumMasters-1:0][ 3:0] s_read_fault_reason; - logic [NumMasters-1:0][ 3:0] s_write_fault_reason; + logic [NumMasters-1:0][TargetWidth-1:0] s_read_decoded_target; + logic [NumMasters-1:0][TargetWidth-1:0] s_write_decoded_target; + logic [NumMasters-1:0][TargetWidth-1:0] s_read_routed_target; + logic [NumMasters-1:0][TargetWidth-1:0] s_write_routed_target; + logic [NumMasters-1:0][ 3:0] s_read_fault_reason; + logic [NumMasters-1:0][ 3:0] s_write_fault_reason; logic [NumMasters-1:0][CountWidth-1:0] s_master_read_count_d, s_master_read_count_q; logic [NumMasters-1:0][CountWidth-1:0] s_master_write_count_d, s_master_write_count_q; @@ -388,7 +392,7 @@ module axi4_data_crossbar #( .clk_i (clk_i), .rst_n_i (rst_n_i), .advance_i (s_read_terminal[master]), - .request_i (s_read_resp_req[master]), + .request_i (s_read_resp_arb_req[master]), .grant_o (unused_read_resp_grant[master]), .selected_o(s_read_resp_selected[master]), .valid_o (s_read_resp_valid[master]) @@ -406,6 +410,20 @@ module axi4_data_crossbar #( ); end + always_comb begin + // Keep all beats of one read burst on its selected target. AXI read + // responses may complete out of order by ID, but beats of a burst must + // not be interleaved with another target's burst on the same master. + s_read_resp_arb_req = s_read_resp_req; + for (int master = 0; master < NumMasters; master++) begin + if (s_read_resp_lock_q[master]) begin + s_read_resp_arb_req[master] = '0; + s_read_resp_arb_req[master][s_read_resp_lock_target_q[master]] = + s_read_resp_req[master][s_read_resp_lock_target_q[master]]; + end + end + end + for (genvar target = 0; target < NumTargets; target++) begin : gen_target_ports assign targets[target].awid = t_aw[target].id; assign targets[target].awaddr = t_aw[target].addr; @@ -846,18 +864,24 @@ module axi4_data_crossbar #( end always_comb begin - s_master_read_count_d = s_master_read_count_q; - s_master_write_count_d = s_master_write_count_q; - s_target_read_count_d = s_target_read_count_q; - s_target_write_count_d = s_target_write_count_q; - s_read_id_busy_d = s_read_id_busy_q; - s_write_id_busy_d = s_write_id_busy_q; + s_master_read_count_d = s_master_read_count_q; + s_master_write_count_d = s_master_write_count_q; + s_target_read_count_d = s_target_read_count_q; + s_target_write_count_d = s_target_write_count_q; + s_read_id_busy_d = s_read_id_busy_q; + s_write_id_busy_d = s_write_id_busy_q; + s_read_resp_lock_d = s_read_resp_lock_q; + s_read_resp_lock_target_d = s_read_resp_lock_target_q; for (int master = 0; master < NumMasters; master++) begin if (s_read_terminal[master]) begin s_master_read_count_d[master] = s_master_read_count_d[master] - 1'b1; s_target_read_count_d[s_read_resp_selected[master]] = s_target_read_count_d[s_read_resp_selected[master]] - 1'b1; s_read_id_busy_d[master][s_read_complete_id[master]] = 1'b0; + s_read_resp_lock_d[master] = 1'b0; + end else if (!s_read_resp_lock_q[master] && s_read_resp_valid[master]) begin + s_read_resp_lock_d[master] = 1'b1; + s_read_resp_lock_target_d[master] = s_read_resp_selected[master]; end if (s_write_terminal[master]) begin s_master_write_count_d[master] = s_master_write_count_d[master] - 1'b1; @@ -972,53 +996,59 @@ module axi4_data_crossbar #( always_ff @(posedge clk_i or negedge rst_n_i) begin if (!rst_n_i) begin - s_master_read_count_q <= '0; - s_master_write_count_q <= '0; - s_target_read_count_q <= '0; - s_target_write_count_q <= '0; - s_read_id_busy_q <= '0; - s_write_id_busy_q <= '0; - s_write_route_q <= '0; - s_route_read_ptr_q <= '0; - s_route_write_ptr_q <= '0; - s_route_count_q <= '0; - s_read_age_q <= '0; - s_write_age_q <= '0; - s_protocol_recovery_q <= 1'b0; - fault_valid_o <= 1'b0; - fault_master_o <= '0; - fault_target_o <= '0; - fault_addr_o <= '0; - fault_write_o <= 1'b0; - fault_reason_o <= '0; + s_master_read_count_q <= '0; + s_master_write_count_q <= '0; + s_target_read_count_q <= '0; + s_target_write_count_q <= '0; + s_read_id_busy_q <= '0; + s_write_id_busy_q <= '0; + s_read_resp_lock_q <= '0; + s_read_resp_lock_target_q <= '0; + s_write_route_q <= '0; + s_route_read_ptr_q <= '0; + s_route_write_ptr_q <= '0; + s_route_count_q <= '0; + s_read_age_q <= '0; + s_write_age_q <= '0; + s_protocol_recovery_q <= 1'b0; + fault_valid_o <= 1'b0; + fault_master_o <= '0; + fault_target_o <= '0; + fault_addr_o <= '0; + fault_write_o <= 1'b0; + fault_reason_o <= '0; end else begin if (flush_i) begin - s_master_read_count_q <= '0; - s_master_write_count_q <= '0; - s_target_read_count_q <= '0; - s_target_write_count_q <= '0; - s_read_id_busy_q <= '0; - s_write_id_busy_q <= '0; - s_write_route_q <= '0; - s_route_read_ptr_q <= '0; - s_route_write_ptr_q <= '0; - s_route_count_q <= '0; - s_read_age_q <= '0; - s_write_age_q <= '0; - s_protocol_recovery_q <= 1'b0; + s_master_read_count_q <= '0; + s_master_write_count_q <= '0; + s_target_read_count_q <= '0; + s_target_write_count_q <= '0; + s_read_id_busy_q <= '0; + s_write_id_busy_q <= '0; + s_read_resp_lock_q <= '0; + s_read_resp_lock_target_q <= '0; + s_write_route_q <= '0; + s_route_read_ptr_q <= '0; + s_route_write_ptr_q <= '0; + s_route_count_q <= '0; + s_read_age_q <= '0; + s_write_age_q <= '0; + s_protocol_recovery_q <= 1'b0; end else begin - s_master_read_count_q <= s_master_read_count_d; - s_master_write_count_q <= s_master_write_count_d; - s_target_read_count_q <= s_target_read_count_d; - s_target_write_count_q <= s_target_write_count_d; - s_read_id_busy_q <= s_read_id_busy_d; - s_write_id_busy_q <= s_write_id_busy_d; - s_write_route_q <= s_write_route_d; - s_route_read_ptr_q <= s_route_read_ptr_d; - s_route_write_ptr_q <= s_route_write_ptr_d; - s_route_count_q <= s_route_count_d; - s_read_age_q <= s_read_age_d; - s_write_age_q <= s_write_age_d; + s_master_read_count_q <= s_master_read_count_d; + s_master_write_count_q <= s_master_write_count_d; + s_target_read_count_q <= s_target_read_count_d; + s_target_write_count_q <= s_target_write_count_d; + s_read_id_busy_q <= s_read_id_busy_d; + s_write_id_busy_q <= s_write_id_busy_d; + s_read_resp_lock_q <= s_read_resp_lock_d; + s_read_resp_lock_target_q <= s_read_resp_lock_target_d; + s_write_route_q <= s_write_route_d; + s_route_read_ptr_q <= s_route_read_ptr_d; + s_route_write_ptr_q <= s_route_write_ptr_d; + s_route_count_q <= s_route_count_d; + s_read_age_q <= s_read_age_d; + s_write_age_q <= s_write_age_d; if (s_protocol_fault_event) s_protocol_recovery_q <= 1'b1; end if (!fault_valid_o || fault_ready_i) begin diff --git a/scripts/build_hp_linux.py b/scripts/build_hp_linux.py index 4d62e6c2..31d5dab8 100644 --- a/scripts/build_hp_linux.py +++ b/scripts/build_hp_linux.py @@ -19,6 +19,15 @@ LAYOUT = { "rootfs.cpio.gz": (0x39000000, 8 * 1024 * 1024), } +REQUIRED_LINUX_CONFIG = ( + "CONFIG_BINFMT_ELF", + "CONFIG_BINFMT_SCRIPT", + "CONFIG_PRINTK", + "CONFIG_TTY", + "CONFIG_HVC_RISCV_SBI", + "CONFIG_SERIAL_EARLYCON_RISCV_SBI", +) + def command(arguments: list[str], cwd: Path) -> None: environment = dict(os.environ) @@ -57,6 +66,27 @@ def find_toolchain(buildroot_output: Path) -> str: return str(matches[0])[: -len("gcc")] +def validate_linux_config(config: Path) -> None: + values: dict[str, str] = {} + for line in config.read_text(encoding="utf-8").splitlines(): + if line.startswith("CONFIG_") and "=" in line: + symbol, value = line.split("=", 1) + values[symbol] = value + elif line.startswith("# CONFIG_") and line.endswith(" is not set"): + symbol = line[len("# ") : -len(" is not set")] + values[symbol] = "n" + + invalid = [ + f"{symbol}={values.get(symbol, 'missing')}" + for symbol in REQUIRED_LINUX_CONFIG + if values.get(symbol) != "y" + ] + if invalid: + raise RuntimeError( + "invalid HP Linux effective configuration: " + ", ".join(invalid) + ) + + def build(args: argparse.Namespace) -> None: root = args.root.resolve() output = args.output.resolve() @@ -94,6 +124,7 @@ def build(args: argparse.Namespace) -> None: ["make", f"O={linux_output}", "ARCH=riscv", f"CROSS_COMPILE={cross_compile}", "olddefconfig"], linux, ) + validate_linux_config(linux_output / ".config") command( ["make", f"O={linux_output}", "ARCH=riscv", f"CROSS_COMPILE={cross_compile}", f"-j{args.jobs}", "Image"], diff --git a/tests/rtl/axi4_data_crossbar_tb.sv b/tests/rtl/axi4_data_crossbar_tb.sv index 818cb570..f1f9e43f 100644 --- a/tests/rtl/axi4_data_crossbar_tb.sv +++ b/tests/rtl/axi4_data_crossbar_tb.sv @@ -98,6 +98,54 @@ module axi4_data_crossbar_tb; end endtask + task automatic issue_master1_read_burst(input logic [6:0] id, input logic [31:0] addr); + begin + @(negedge clk_i); + masters[1].arid = id; + masters[1].araddr = addr; + masters[1].arlen = 8'd7; + masters[1].arsize = 3'd3; + masters[1].arburst = 2'b01; + masters[1].arvalid = 1'b1; + do @(posedge clk_i); while (!masters[1].arready); + @(negedge clk_i); + masters[1].arvalid = 1'b0; + masters[1].arlen = '0; + end + endtask + + task automatic return_target0_burst(input logic [6:0] id, input logic [63:0] data_base); + begin + for (int unsigned beat = 0; beat < 8; beat++) begin + @(negedge clk_i); + targets[0].rid = id; + targets[0].rdata = data_base + beat; + targets[0].rresp = 2'b00; + targets[0].rlast = (beat == 7); + targets[0].rvalid = 1'b1; + do @(posedge clk_i); while (!targets[0].rready); + @(negedge clk_i); + targets[0].rvalid = 1'b0; + end + end + endtask + + task automatic return_target1_burst(input logic [6:0] id, input logic [63:0] data_base); + begin + for (int unsigned beat = 0; beat < 8; beat++) begin + @(negedge clk_i); + targets[1].rid = id; + targets[1].rdata = data_base + beat; + targets[1].rresp = 2'b00; + targets[1].rlast = (beat == 7); + targets[1].rvalid = 1'b1; + do @(posedge clk_i); while (!targets[1].rready); + @(negedge clk_i); + targets[1].rvalid = 1'b0; + end + end + endtask + task automatic return_target0_read(input logic [6:0] id, input logic [63:0] data); begin @(negedge clk_i); @@ -405,6 +453,69 @@ module axi4_data_crossbar_tb; $fatal(1, "same-target reads did not drain the crossbar"); end + read_burst_target_lock : begin + logic [ 6:0] first_id; + logic [ 6:0] second_id; + logic [63:0] first_base; + logic [63:0] second_base; + logic [ 6:0] expected_id; + logic [63:0] expected_data; + + issue_master1_read_burst(6'b001_100, 32'h3000_0200); + issue_master1_read_burst(6'b001_101, 32'h3800_0200); + if (outstanding_read_o != 8'd2) begin + $fatal(1, "read bursts were not tracked concurrently"); + end + + fork + return_target0_burst(6'b001_100, 64'hAAAA_0000_0000_0000); + return_target1_burst(6'b001_101, 64'hBBBB_0000_0000_0000); + begin + for (int unsigned beat = 0; beat < 16; beat++) begin + do begin + @(negedge clk_i); + #1; + end while (!masters[1].rvalid); + + if (beat == 0) begin + first_id = masters[1].rid; + if (first_id == 6'b001_100) begin + first_base = 64'hAAAA_0000_0000_0000; + second_id = 6'b001_101; + second_base = 64'hBBBB_0000_0000_0000; + end else if (first_id == 6'b001_101) begin + first_base = 64'hBBBB_0000_0000_0000; + second_id = 6'b001_100; + second_base = 64'hAAAA_0000_0000_0000; + end else begin + $fatal(1, "read burst returned an unexpected ID"); + end + end + + if (beat < 8) begin + expected_id = first_id; + expected_data = first_base + beat; + end else begin + expected_id = second_id; + expected_data = second_base + (beat - 8); + end + if ((masters[1].rid != expected_id) || (masters[1].rdata != expected_data) || + (masters[1].rlast != (beat == 7 || beat == 15))) begin + $fatal( + 1, + "read response burst was interleaved or malformed at beat %0d rid=%h expected_id=%h data=%h expected_data=%h last=%b expected_last=%b", + beat, masters[1].rid, expected_id, masters[1].rdata, expected_data, + masters[1].rlast, (beat == 7 || beat == 15)); + end + end + end + join + @(negedge clk_i); + if (!idle_o || (outstanding_read_o != 8'd0)) begin + $fatal(1, "read burst target lock did not drain the crossbar"); + end + end + jpeg_master_admission_credit_priority_and_acl : begin // JPEG's normal class is above the LP gateway's class before aging. @(negedge clk_i); diff --git a/tests/test_hp_platform.py b/tests/test_hp_platform.py index 899b6605..4e071309 100644 --- a/tests/test_hp_platform.py +++ b/tests/test_hp_platform.py @@ -7,6 +7,10 @@ import shutil import subprocess from pathlib import Path +import pytest + +from scripts import build_hp_linux + ROOT = Path(__file__).resolve().parents[1] @@ -50,7 +54,7 @@ def test_hp_linux_simulation_uses_explicit_fast_flash_acceptance() -> None: verilator_makefile = (ROOT / "rtl/mini/mk/verilator.mk").read_text(encoding="utf-8") emulator = (ROOT / "rtl/mini/dv/verilator/csrc/main.cpp").read_text(encoding="utf-8") - assert "HP_LINUX_SIM_TIME ?= 7200" in makefile + assert "HP_LINUX_SIM_TIME ?= 0" in makefile assert "hp-linux-sim: hp-bundle comp" in makefile assert "VERILATOR_SIM_ARGS=--fast-flash sim" in makefile for marker in ( @@ -157,6 +161,28 @@ def test_linux_build_uses_external_opensbi_platform_and_actual_initrd_end() -> N assert "aclint_mtimer_cold_init" in platform +def test_hp_linux_effective_config_is_fail_closed(tmp_path: Path) -> None: + fragment = (ROOT / "app/ports/linux/linux/retrosoc_hp.config").read_text( + encoding="utf-8" + ) + for symbol in build_hp_linux.REQUIRED_LINUX_CONFIG: + assert f"{symbol}=y" in fragment + + config = tmp_path / ".config" + valid = "".join(f"{symbol}=y\n" for symbol in build_hp_linux.REQUIRED_LINUX_CONFIG) + config.write_text(valid, encoding="utf-8") + build_hp_linux.validate_linux_config(config) + + config.write_text(valid.replace("CONFIG_BINFMT_ELF=y", "# CONFIG_BINFMT_ELF is not set"), + encoding="utf-8") + with pytest.raises(RuntimeError, match="CONFIG_BINFMT_ELF=n"): + build_hp_linux.validate_linux_config(config) + + config.write_text(valid.replace("CONFIG_TTY=y\n", ""), encoding="utf-8") + with pytest.raises(RuntimeError, match="CONFIG_TTY=missing"): + build_hp_linux.validate_linux_config(config) + + def test_hp_linux_device_tree_compiles_and_can_patch_initrd_end(tmp_path: Path) -> None: dtc = shutil.which("dtc") fdtput = shutil.which("fdtput")