fix(qemu): select the rva23s64 CPU for riscv64 under TCG

Ubuntu builds its riscv64 port against the RVA23 profile (since
25.10), and QEMU's default rv64 CPU does not implement all profile
extensions: Ubuntu binaries die with SIGILL during init and the
kernel panics with 'Attempted to kill init'. Select the rva23s64
profile CPU (QEMU 10.1+) for riscv64 under TCG; profiles are
supersets, so baseline rv64gc rootfses run unchanged on it.

KVM mode keeps -cpu host.
This commit is contained in:
2026-09-21 01:24:11 +02:00
parent 12f771d326
commit ba90e0f367
+31
View File
@@ -159,6 +159,9 @@ pub fn launch_qemu(config: QemuConfig) -> Result<()> {
args.push("-enable-kvm".to_string()); args.push("-enable-kvm".to_string());
args.push("-cpu".to_string()); args.push("-cpu".to_string());
args.push("host".to_string()); args.push("host".to_string());
} else if let Some(cpu) = cpu_for_arch(&config.arch) {
args.push("-cpu".to_string());
args.push(cpu.to_string());
} }
// Execute QEMU // Execute QEMU
@@ -201,6 +204,22 @@ fn machine_for_arch(arch: &str) -> Option<&'static str> {
} }
} }
/// Get the QEMU TCG CPU model to select for the target architecture, when
/// the emulator default is not sufficient.
///
/// Ubuntu builds its riscv64 port against the RVA23 profile (since 25.10),
/// so its binaries execute instructions QEMU's default `rv64` CPU does not
/// implement and die with SIGILL early in boot. `rva23s64` implements the
/// full supervisor profile; baseline rv64gc rootfses (Alpine, older
/// Ubuntu) run unchanged on it because profiles are supersets. The named
/// profile CPU needs QEMU 10.1+.
fn cpu_for_arch(arch: &str) -> Option<&'static str> {
match crate::utils::Arch::from_str(arch) {
crate::utils::Arch::Riscv64 => Some("rva23s64"),
_ => None,
}
}
/// Get architecture suffix for package names /// Get architecture suffix for package names
fn get_arch_package_suffix(arch: &str) -> &'static str { fn get_arch_package_suffix(arch: &str) -> &'static str {
crate::utils::Arch::from_str(arch).qemu_package_suffix() crate::utils::Arch::from_str(arch).qemu_package_suffix()
@@ -635,6 +654,18 @@ mod tests {
assert_eq!(machine_for_arch("s390x"), None); assert_eq!(machine_for_arch("s390x"), None);
} }
#[test]
fn test_cpu_for_arch() {
// Ubuntu's riscv64 userland needs the RVA23 profile CPU; QEMU's
// default `rv64` CPU SIGILLs on it early in boot
assert_eq!(cpu_for_arch("riscv64"), Some("rva23s64"));
// Other architectures keep their emulator's default CPU
assert_eq!(cpu_for_arch("amd64"), None);
assert_eq!(cpu_for_arch("x86_64"), None);
assert_eq!(cpu_for_arch("arm64"), None);
assert_eq!(cpu_for_arch("aarch64"), None);
}
/// Parse a newc cpio archive into (name, ino, mode, nlink, file_size, data) tuples /// Parse a newc cpio archive into (name, ino, mode, nlink, file_size, data) tuples
fn parse_cpio(archive: Vec<u8>) -> Vec<(String, u32, u32, u32, u32, Vec<u8>)> { fn parse_cpio(archive: Vec<u8>) -> Vec<(String, u32, u32, u32, u32, Vec<u8>)> {
let mut cursor = std::io::Cursor::new(archive); let mut cursor = std::io::Cursor::new(archive);