123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744 |
- // Copyright 2017 The ChromiumOS Authors
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #![cfg(feature = "plugin")]
- use std::env::current_exe;
- use std::env::var_os;
- use std::ffi::OsString;
- use std::fs::remove_file;
- use std::io::Read;
- use std::io::Write;
- use std::path::Path;
- use std::path::PathBuf;
- use std::process::Command;
- use std::process::Stdio;
- use std::thread::sleep;
- use std::time::Duration;
- use base::ioctl;
- use base::AsRawDescriptor;
- use net_util::TapTCommon;
- use once_cell::sync::Lazy;
- use rand::random;
- use tempfile::tempfile;
- static TAP_AVAILABLE: Lazy<bool> =
- Lazy::new(|| net_util::sys::linux::Tap::new(true, false).is_ok());
- struct RemovePath(PathBuf);
- impl Drop for RemovePath {
- fn drop(&mut self) {
- if let Err(e) = remove_file(&self.0) {
- eprintln!("failed to remove path: {}", e);
- }
- }
- }
- fn get_target_path() -> PathBuf {
- current_exe()
- .ok()
- .map(|mut path| {
- path.pop();
- path
- })
- .expect("failed to get crosvm binary directory")
- }
- fn get_crosvm_path() -> PathBuf {
- current_exe()
- .ok()
- .map(|mut path| {
- path.pop();
- if path.ends_with("deps") {
- path.pop();
- }
- path
- })
- .expect("failed to get crosvm binary directory")
- }
- fn build_plugin(src: &str) -> RemovePath {
- let libcrosvm_plugin_dir = get_target_path();
- let mut out_bin = libcrosvm_plugin_dir.clone();
- out_bin.push(format!("plugin-test-{:08X}", random::<u32>()));
- let mut child = Command::new(var_os("CC").unwrap_or(OsString::from("cc")))
- .args(["-Icrosvm_plugin", "-pthread", "-o"]) // crosvm.h location and set output path.
- .arg(&out_bin)
- .arg("-L") // Path of shared object to link to.
- .arg(&libcrosvm_plugin_dir)
- .arg("-Wl,-rpath") // Search for shared object in the same path when exec'd.
- .arg(&libcrosvm_plugin_dir)
- .args(["-Wl,-rpath", "."]) // Also check current directory in case of sandboxing.
- .args(["-xc", "-"]) // Read source code from piped stdin.
- .arg("-lcrosvm_plugin")
- .stdin(Stdio::piped())
- .spawn()
- .expect("failed to spawn compiler");
- let stdin = child.stdin.as_mut().expect("failed to open stdin");
- stdin
- .write_all(src.as_bytes())
- .expect("failed to write source to stdin");
- let status = child.wait().expect("failed to wait for compiler");
- assert!(status.success(), "failed to build plugin");
- RemovePath(out_bin)
- }
- fn run_plugin(bin_path: &Path, with_sandbox: bool) {
- let mut crosvm_path = get_crosvm_path();
- crosvm_path.push("crosvm");
- let mut cmd = Command::new(crosvm_path);
- cmd.args([
- "run",
- "-c",
- "1",
- "--seccomp-policy-dir",
- "tests",
- "--plugin",
- ])
- .arg(
- bin_path
- .canonicalize()
- .expect("failed to canonicalize plugin path"),
- );
- if *TAP_AVAILABLE {
- cmd.args([
- "--host-ip",
- "100.115.92.5",
- "--netmask",
- "255.255.255.252",
- "--mac",
- "de:21:e8:47:6b:6a",
- ]);
- }
- if !with_sandbox {
- cmd.arg("--disable-sandbox");
- }
- let mut child = cmd.spawn().expect("failed to spawn crosvm");
- for _ in 0..12 {
- match child.try_wait().expect("failed to wait for crosvm") {
- Some(status) => {
- assert!(status.success());
- return;
- }
- None => sleep(Duration::from_millis(100)),
- }
- }
- child.kill().expect("failed to kill crosvm");
- panic!("crosvm process has timed out");
- }
- fn test_plugin(src: &str) {
- let bin_path = build_plugin(src);
- // Run with and without the sandbox enabled.
- run_plugin(&bin_path.0, false);
- run_plugin(&bin_path.0, true);
- }
- fn keep_fd_on_exec<F: AsRawDescriptor>(f: &F) {
- // SAFETY: safe because function doesn't modify memory and we don't care about the return
- // value.
- unsafe {
- ioctl(f, 0x5450 /* FIONCLEX */);
- }
- }
- /// Takes assembly source code and returns the resulting assembly code.
- fn build_assembly(src: &str) -> Vec<u8> {
- // Creates a file with the assembly source code in it.
- let mut in_file = tempfile().expect("failed to create tempfile");
- keep_fd_on_exec(&in_file);
- in_file.write_all(src.as_bytes()).unwrap();
- // Creates a file that will hold the nasm output.
- let mut out_file = tempfile().expect("failed to create tempfile");
- keep_fd_on_exec(&out_file);
- // Runs nasm with the input and output files set to the FDs of the above shared memory regions,
- // which we have preserved accross exec.
- let status = Command::new("nasm")
- .arg(format!("/proc/self/fd/{}", in_file.as_raw_descriptor()))
- .args(["-f", "bin", "-o"])
- .arg(format!("/proc/self/fd/{}", out_file.as_raw_descriptor()))
- .status()
- .expect("failed to spawn assembler");
- assert!(status.success());
- let mut out_bytes = Vec::new();
- out_file.read_to_end(&mut out_bytes).unwrap();
- out_bytes
- }
- // Converts the input bytes to an output string in the format "0x01,0x02,0x03...".
- fn format_as_hex(data: &[u8]) -> String {
- let mut out = String::new();
- for (i, d) in data.iter().enumerate() {
- #[allow(clippy::format_push_string)]
- out.push_str(&format!("0x{:02x}", d));
- if i < data.len() - 1 {
- out.push(',')
- }
- }
- out
- }
- // A testing framework for creating simple plugins.
- struct MiniPlugin {
- // The size in bytes of the guest memory based at 0x0000.
- mem_size: u64,
- // The address in guest memory to load the assembly code.
- load_address: u32,
- // The nasm syntax 16-bit assembly code that will assembled and loaded into guest memory.
- assembly_src: &'static str,
- // The C source code that will be included in the mini_plugin_template.c file. This code must
- // define the forward declarations above the {src} line so that the completed plugin source
- // will compile.
- src: &'static str,
- }
- impl Default for MiniPlugin {
- fn default() -> Self {
- MiniPlugin {
- mem_size: 0x2000,
- load_address: 0x1000,
- assembly_src: "hlt",
- src: "",
- }
- }
- }
- // Builds and tests the given MiniPlugin definiton.
- fn test_mini_plugin(plugin: &MiniPlugin) {
- // Adds a preamble to ensure the output opcodes are 16-bit real mode and the lables start at the
- // load address.
- let assembly_src = format!(
- "org 0x{:x}\nbits 16\n{}",
- plugin.load_address, plugin.assembly_src
- );
- // Builds the assembly and convert it to a C literal array format.
- let assembly = build_assembly(&assembly_src);
- let assembly_hex = format_as_hex(&assembly);
- // Glues the pieces of this plugin together and tests the completed plugin.
- let generated_src = format!(
- include_str!("mini_plugin_template.c"),
- mem_size = plugin.mem_size,
- load_address = plugin.load_address,
- assembly_code = assembly_hex,
- src = plugin.src
- );
- test_plugin(&generated_src);
- }
- #[test]
- fn test_adder() {
- test_plugin(include_str!("plugin_adder.c"));
- }
- #[ignore] // TODO(b/239094055): fix the SIGSTOP usage that stops the cargo test runner
- #[test]
- fn test_hint() {
- test_plugin(include_str!("plugin_hint.c"));
- }
- #[test]
- fn test_async_write() {
- test_plugin(include_str!("plugin_async_write.c"));
- }
- #[test]
- fn test_dirty_log() {
- test_plugin(include_str!("plugin_dirty_log.c"));
- }
- #[test]
- fn test_ioevent() {
- test_plugin(include_str!("plugin_ioevent.c"));
- }
- #[test]
- fn test_irqfd() {
- test_plugin(include_str!("plugin_irqfd.c"));
- }
- #[test]
- fn test_extensions() {
- test_plugin(include_str!("plugin_extensions.c"));
- }
- #[test]
- fn test_supported_cpuid() {
- test_plugin(include_str!("plugin_supported_cpuid.c"));
- }
- // b:223675792
- #[ignore]
- #[test]
- fn test_enable_cap() {
- test_plugin(include_str!("plugin_enable_cap.c"));
- }
- #[test]
- fn test_msr_index_list() {
- test_plugin(include_str!("plugin_msr_index_list.c"));
- }
- #[test]
- fn test_vm_state_manipulation() {
- test_plugin(include_str!("plugin_vm_state.c"));
- }
- #[test]
- fn test_vcpu_pause() {
- test_plugin(include_str!("plugin_vcpu_pause.c"));
- }
- #[test]
- fn test_net_config() {
- if *TAP_AVAILABLE {
- test_plugin(include_str!("plugin_net_config.c"));
- }
- }
- #[test]
- fn test_debugregs() {
- let mini_plugin = MiniPlugin {
- assembly_src: "org 0x1000
- bits 16
- mov dr0, ebx
- mov eax, dr1
- mov byte [0x3000], 1",
- src: r#"
- #define DR1_VALUE 0x12
- #define RBX_VALUE 0xabcdef00
- #define KILL_ADDRESS 0x3000
- int g_kill_evt;
- struct kvm_regs g_regs;
- struct kvm_debugregs g_dregs;
- int setup_vm(struct crosvm *crosvm, void *mem) {
- g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
- crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
- return 0;
- }
- int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
- struct kvm_sregs *sregs)
- {
- regs->rbx = RBX_VALUE;
- struct kvm_debugregs dregs;
- crosvm_vcpu_get_debugregs(vcpu, &dregs);
- dregs.db[1] = DR1_VALUE;
- crosvm_vcpu_set_debugregs(vcpu, &dregs);
- return 0;
- }
- int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
- if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
- evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
- evt.io_access.address == KILL_ADDRESS &&
- evt.io_access.is_write &&
- evt.io_access.length == 1 &&
- evt.io_access.data[0] == 1)
- {
- uint64_t dummy = 1;
- crosvm_vcpu_get_debugregs(vcpu, &g_dregs);
- crosvm_vcpu_get_regs(vcpu, &g_regs);
- write(g_kill_evt, &dummy, sizeof(dummy));
- return 1;
- }
- return 0;
- }
- int check_result(struct crosvm *vcpu, void *mem) {
- if (g_dregs.db[1] != DR1_VALUE) {
- fprintf(stderr, "dr1 register has unexpected value: 0x%x\n", g_dregs.db[1]);
- return 1;
- }
- if (g_dregs.db[0] != RBX_VALUE) {
- fprintf(stderr, "dr0 register has unexpected value: 0x%x\n", g_dregs.db[0]);
- return 1;
- }
- if (g_regs.rax != DR1_VALUE) {
- fprintf(stderr, "eax register has unexpected value: 0x%x\n", g_regs.rax);
- return 1;
- }
- return 0;
- }"#,
- ..Default::default()
- };
- test_mini_plugin(&mini_plugin);
- }
- #[test]
- fn test_xcrs() {
- let mini_plugin = MiniPlugin {
- assembly_src: "org 0x1000
- bits 16
- mov byte [0x3000], 1",
- src: r#"
- #define XCR0_VALUE 0x1
- #define KILL_ADDRESS 0x3000
- int g_kill_evt;
- struct kvm_xcrs g_xcrs;
- int setup_vm(struct crosvm *crosvm, void *mem) {
- g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
- crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
- return 0;
- }
- int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
- struct kvm_sregs *sregs)
- {
- struct kvm_xcrs xcrs = {};
- xcrs.nr_xcrs = 1;
- xcrs.xcrs[0].value = XCR0_VALUE;
- crosvm_vcpu_set_xcrs(vcpu, &xcrs);
- return 0;
- }
- int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
- if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
- evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
- evt.io_access.address == KILL_ADDRESS &&
- evt.io_access.is_write &&
- evt.io_access.length == 1 &&
- evt.io_access.data[0] == 1)
- {
- uint64_t dummy = 1;
- crosvm_vcpu_get_xcrs(vcpu, &g_xcrs);
- write(g_kill_evt, &dummy, sizeof(dummy));
- return 1;
- }
- return 0;
- }
- int check_result(struct crosvm *vcpu, void *mem) {
- if (g_xcrs.xcrs[0].value != XCR0_VALUE) {
- fprintf(stderr, "xcr0 register has unexpected value: 0x%x\n",
- g_xcrs.xcrs[0].value);
- return 1;
- }
- return 0;
- }"#,
- ..Default::default()
- };
- test_mini_plugin(&mini_plugin);
- }
- #[test]
- fn test_msrs() {
- let mini_plugin = MiniPlugin {
- assembly_src: "org 0x1000
- bits 16
- rdmsr
- mov [0x0], eax
- mov [0x4], edx
- mov ecx, ebx
- mov eax, [0x8]
- mov edx, [0xc]
- wrmsr
- mov byte [es:0], 1",
- src: r#"
- #define MSR1_INDEX 0x00000174
- #define MSR1_DATA 1
- #define MSR2_INDEX 0x00000175
- #define MSR2_DATA 2
- #define KILL_ADDRESS 0x3000
- int g_kill_evt;
- uint32_t g_msr2_count;
- struct kvm_msr_entry g_msr2;
- int setup_vm(struct crosvm *crosvm, void *mem) {
- g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
- crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
- ((uint64_t*)mem)[1] = MSR2_DATA;
- return 0;
- }
- int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
- struct kvm_sregs *sregs)
- {
- regs->rcx = MSR1_INDEX;
- regs->rbx = MSR2_INDEX;
- sregs->es.base = KILL_ADDRESS;
- struct kvm_msr_entry msr1 = {0};
- msr1.index = MSR1_INDEX;
- msr1.data = MSR1_DATA;
- crosvm_vcpu_set_msrs(vcpu, 1, &msr1);
- return 0;
- }
- int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
- if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
- evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
- evt.io_access.address == KILL_ADDRESS &&
- evt.io_access.is_write &&
- evt.io_access.length == 1 &&
- evt.io_access.data[0] == 1)
- {
- uint64_t dummy = 1;
- g_msr2.index = MSR2_INDEX;
- crosvm_vcpu_get_msrs(vcpu, 1, &g_msr2, &g_msr2_count);
- write(g_kill_evt, &dummy, sizeof(dummy));
- return 1;
- }
- return 0;
- }
- int check_result(struct crosvm *vcpu, void *mem) {
- uint64_t msr1_data = ((uint64_t*)mem)[0];
- if (msr1_data != MSR1_DATA) {
- fprintf(stderr, "msr1 has unexpected value: 0x%x\n", msr1_data);
- return 1;
- }
- if (g_msr2_count != 1) {
- fprintf(stderr, "incorrect number of returned MSRSs: %d\n", g_msr2_count);
- return 1;
- }
- if (g_msr2.data != MSR2_DATA) {
- fprintf(stderr, "msr2 has unexpected value: 0x%x\n", g_msr2.data);
- return 1;
- }
- return 0;
- }"#,
- ..Default::default()
- };
- test_mini_plugin(&mini_plugin);
- }
- #[test]
- fn test_cpuid() {
- let mini_plugin = MiniPlugin {
- assembly_src: "org 0x1000
- bits 16
- push eax
- push ecx
- cpuid
- mov [0x0], eax
- mov [0x4], ebx
- mov [0x8], ecx
- mov [0xc], edx
- pop ecx
- pop eax
- add ecx, 1
- cpuid
- mov [0x10], eax
- mov [0x14], ebx
- mov [0x18], ecx
- mov [0x1c], edx
- mov byte [es:0], 1",
- src: r#"
- #define ENTRY1_INDEX 0
- #define ENTRY1_EAX 0x40414243
- #define ENTRY1_EBX 0x50515253
- #define ENTRY1_ECX 0x60616263
- #define ENTRY1_EDX 0x71727374
- #define ENTRY2_INDEX 1
- #define ENTRY2_EAX 0xAABBCCDD
- #define ENTRY2_EBX 0xEEFF0011
- #define ENTRY2_ECX 0x22334455
- #define ENTRY2_EDX 0x66778899
- #define KILL_ADDRESS 0x3000
- int g_kill_evt;
- struct kvm_msr_entry g_msr2;
- int setup_vm(struct crosvm *crosvm, void *mem) {
- g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
- crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
- return 0;
- }
- int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
- struct kvm_sregs *sregs)
- {
- regs->rax = ENTRY1_INDEX;
- regs->rcx = 0;
- regs->rsp = 0x1000;
- sregs->es.base = KILL_ADDRESS;
- struct kvm_cpuid_entry2 entries[2];
- entries[0].function = 0;
- entries[0].index = ENTRY1_INDEX;
- entries[0].flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
- entries[0].eax = ENTRY1_EAX;
- entries[0].ebx = ENTRY1_EBX;
- entries[0].ecx = ENTRY1_ECX;
- entries[0].edx = ENTRY1_EDX;
- entries[1].function = 0;
- entries[1].index = ENTRY2_INDEX;
- entries[1].flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
- entries[1].eax = ENTRY2_EAX;
- entries[1].ebx = ENTRY2_EBX;
- entries[1].ecx = ENTRY2_ECX;
- entries[1].edx = ENTRY2_EDX;
- return crosvm_vcpu_set_cpuid(vcpu, 2, entries);
- }
- int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
- if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
- evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
- evt.io_access.address == KILL_ADDRESS &&
- evt.io_access.is_write &&
- evt.io_access.length == 1 &&
- evt.io_access.data[0] == 1)
- {
- uint64_t dummy = 1;
- write(g_kill_evt, &dummy, sizeof(dummy));
- return 1;
- }
- return 0;
- }
- int check_result(struct crosvm *vcpu, void *memory) {
- uint32_t *mem = (uint32_t*)memory;
- if (mem[0] != ENTRY1_EAX) {
- fprintf(stderr, "entry 1 eax has unexpected value: 0x%x\n", mem[0]);
- return 1;
- }
- if (mem[1] != ENTRY1_EBX) {
- fprintf(stderr, "entry 1 ebx has unexpected value: 0x%x\n", mem[1]);
- return 1;
- }
- if (mem[2] != ENTRY1_ECX) {
- fprintf(stderr, "entry 1 ecx has unexpected value: 0x%x\n", mem[2]);
- return 1;
- }
- if (mem[3] != ENTRY1_EDX) {
- fprintf(stderr, "entry 1 edx has unexpected value: 0x%x\n", mem[3]);
- return 1;
- }
- if (mem[4] != ENTRY2_EAX) {
- fprintf(stderr, "entry 2 eax has unexpected value: 0x%x\n", mem[4]);
- return 1;
- }
- if (mem[5] != ENTRY2_EBX) {
- fprintf(stderr, "entry 2 ebx has unexpected value: 0x%x\n", mem[5]);
- return 1;
- }
- if (mem[6] != ENTRY2_ECX) {
- fprintf(stderr, "entry 2 ecx has unexpected value: 0x%x\n", mem[6]);
- return 1;
- }
- if (mem[7] != ENTRY2_EDX) {
- fprintf(stderr, "entry 2 edx has unexpected value: 0x%x\n", mem[7]);
- return 1;
- }
- return 0;
- }"#,
- ..Default::default()
- };
- test_mini_plugin(&mini_plugin);
- }
- #[test]
- fn test_vcpu_state_manipulation() {
- let mini_plugin = MiniPlugin {
- assembly_src: "org 0x1000
- bits 16
- mov byte [0x3000], 1",
- src: r#"
- #define KILL_ADDRESS 0x3000
- int g_kill_evt;
- bool success = false;
- int setup_vm(struct crosvm *crosvm, void *mem) {
- g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
- crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
- return 0;
- }
- int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
- struct kvm_sregs *sregs)
- {
- int ret;
- struct kvm_lapic_state lapic;
- ret = crosvm_vcpu_get_lapic_state(vcpu, &lapic);
- if (ret < 0) {
- fprintf(stderr, "failed to get initial LAPIC state: %d\n", ret);
- return 1;
- }
- ret = crosvm_vcpu_set_lapic_state(vcpu, &lapic);
- if (ret < 0) {
- fprintf(stderr, "failed to update LAPIC state: %d\n", ret);
- return 1;
- }
- ret = crosvm_vcpu_get_lapic_state(vcpu, &lapic);
- if (ret < 0) {
- fprintf(stderr, "failed to get updated LAPIC state: %d\n", ret);
- return 1;
- }
- struct kvm_mp_state mp_state;
- ret = crosvm_vcpu_get_mp_state(vcpu, &mp_state);
- if (ret < 0) {
- fprintf(stderr, "failed to get initial MP state: %d\n", ret);
- return 1;
- }
- ret = crosvm_vcpu_set_mp_state(vcpu, &mp_state);
- if (ret < 0) {
- fprintf(stderr, "failed to update MP state: %d\n", ret);
- return 1;
- }
- struct kvm_vcpu_events events;
- ret = crosvm_vcpu_get_vcpu_events(vcpu, &events);
- if (ret < 0) {
- fprintf(stderr, "failed to get VCPU events: %d\n", ret);
- return 1;
- }
- ret = crosvm_vcpu_set_vcpu_events(vcpu, &events);
- if (ret < 0) {
- fprintf(stderr, "failed to set VCPU events: %d\n", ret);
- return 1;
- }
- success = true;
- return 0;
- }
- int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
- if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
- evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
- evt.io_access.address == KILL_ADDRESS &&
- evt.io_access.is_write &&
- evt.io_access.length == 1 &&
- evt.io_access.data[0] == 1)
- {
- uint64_t dummy = 1;
- write(g_kill_evt, &dummy, sizeof(dummy));
- return 1;
- }
- return 0;
- }
- int check_result(struct crosvm *vcpu, void *mem) {
- if (!success) {
- fprintf(stderr, "test failed\n");
- return 1;
- }
- return 0;
- }"#,
- ..Default::default()
- };
- test_mini_plugin(&mini_plugin);
- }
|