plugins.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. // Copyright 2017 The ChromiumOS Authors
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #![cfg(feature = "plugin")]
  5. use std::env::current_exe;
  6. use std::env::var_os;
  7. use std::ffi::OsString;
  8. use std::fs::remove_file;
  9. use std::io::Read;
  10. use std::io::Write;
  11. use std::path::Path;
  12. use std::path::PathBuf;
  13. use std::process::Command;
  14. use std::process::Stdio;
  15. use std::thread::sleep;
  16. use std::time::Duration;
  17. use base::ioctl;
  18. use base::AsRawDescriptor;
  19. use net_util::TapTCommon;
  20. use once_cell::sync::Lazy;
  21. use rand::random;
  22. use tempfile::tempfile;
  23. static TAP_AVAILABLE: Lazy<bool> =
  24. Lazy::new(|| net_util::sys::linux::Tap::new(true, false).is_ok());
  25. struct RemovePath(PathBuf);
  26. impl Drop for RemovePath {
  27. fn drop(&mut self) {
  28. if let Err(e) = remove_file(&self.0) {
  29. eprintln!("failed to remove path: {}", e);
  30. }
  31. }
  32. }
  33. fn get_target_path() -> PathBuf {
  34. current_exe()
  35. .ok()
  36. .map(|mut path| {
  37. path.pop();
  38. path
  39. })
  40. .expect("failed to get crosvm binary directory")
  41. }
  42. fn get_crosvm_path() -> PathBuf {
  43. current_exe()
  44. .ok()
  45. .map(|mut path| {
  46. path.pop();
  47. if path.ends_with("deps") {
  48. path.pop();
  49. }
  50. path
  51. })
  52. .expect("failed to get crosvm binary directory")
  53. }
  54. fn build_plugin(src: &str) -> RemovePath {
  55. let libcrosvm_plugin_dir = get_target_path();
  56. let mut out_bin = libcrosvm_plugin_dir.clone();
  57. out_bin.push(format!("plugin-test-{:08X}", random::<u32>()));
  58. let mut child = Command::new(var_os("CC").unwrap_or(OsString::from("cc")))
  59. .args(["-Icrosvm_plugin", "-pthread", "-o"]) // crosvm.h location and set output path.
  60. .arg(&out_bin)
  61. .arg("-L") // Path of shared object to link to.
  62. .arg(&libcrosvm_plugin_dir)
  63. .arg("-Wl,-rpath") // Search for shared object in the same path when exec'd.
  64. .arg(&libcrosvm_plugin_dir)
  65. .args(["-Wl,-rpath", "."]) // Also check current directory in case of sandboxing.
  66. .args(["-xc", "-"]) // Read source code from piped stdin.
  67. .arg("-lcrosvm_plugin")
  68. .stdin(Stdio::piped())
  69. .spawn()
  70. .expect("failed to spawn compiler");
  71. let stdin = child.stdin.as_mut().expect("failed to open stdin");
  72. stdin
  73. .write_all(src.as_bytes())
  74. .expect("failed to write source to stdin");
  75. let status = child.wait().expect("failed to wait for compiler");
  76. assert!(status.success(), "failed to build plugin");
  77. RemovePath(out_bin)
  78. }
  79. fn run_plugin(bin_path: &Path, with_sandbox: bool) {
  80. let mut crosvm_path = get_crosvm_path();
  81. crosvm_path.push("crosvm");
  82. let mut cmd = Command::new(crosvm_path);
  83. cmd.args([
  84. "run",
  85. "-c",
  86. "1",
  87. "--seccomp-policy-dir",
  88. "tests",
  89. "--plugin",
  90. ])
  91. .arg(
  92. bin_path
  93. .canonicalize()
  94. .expect("failed to canonicalize plugin path"),
  95. );
  96. if *TAP_AVAILABLE {
  97. cmd.args([
  98. "--host-ip",
  99. "100.115.92.5",
  100. "--netmask",
  101. "255.255.255.252",
  102. "--mac",
  103. "de:21:e8:47:6b:6a",
  104. ]);
  105. }
  106. if !with_sandbox {
  107. cmd.arg("--disable-sandbox");
  108. }
  109. let mut child = cmd.spawn().expect("failed to spawn crosvm");
  110. for _ in 0..12 {
  111. match child.try_wait().expect("failed to wait for crosvm") {
  112. Some(status) => {
  113. assert!(status.success());
  114. return;
  115. }
  116. None => sleep(Duration::from_millis(100)),
  117. }
  118. }
  119. child.kill().expect("failed to kill crosvm");
  120. panic!("crosvm process has timed out");
  121. }
  122. fn test_plugin(src: &str) {
  123. let bin_path = build_plugin(src);
  124. // Run with and without the sandbox enabled.
  125. run_plugin(&bin_path.0, false);
  126. run_plugin(&bin_path.0, true);
  127. }
  128. fn keep_fd_on_exec<F: AsRawDescriptor>(f: &F) {
  129. // SAFETY: safe because function doesn't modify memory and we don't care about the return
  130. // value.
  131. unsafe {
  132. ioctl(f, 0x5450 /* FIONCLEX */);
  133. }
  134. }
  135. /// Takes assembly source code and returns the resulting assembly code.
  136. fn build_assembly(src: &str) -> Vec<u8> {
  137. // Creates a file with the assembly source code in it.
  138. let mut in_file = tempfile().expect("failed to create tempfile");
  139. keep_fd_on_exec(&in_file);
  140. in_file.write_all(src.as_bytes()).unwrap();
  141. // Creates a file that will hold the nasm output.
  142. let mut out_file = tempfile().expect("failed to create tempfile");
  143. keep_fd_on_exec(&out_file);
  144. // Runs nasm with the input and output files set to the FDs of the above shared memory regions,
  145. // which we have preserved accross exec.
  146. let status = Command::new("nasm")
  147. .arg(format!("/proc/self/fd/{}", in_file.as_raw_descriptor()))
  148. .args(["-f", "bin", "-o"])
  149. .arg(format!("/proc/self/fd/{}", out_file.as_raw_descriptor()))
  150. .status()
  151. .expect("failed to spawn assembler");
  152. assert!(status.success());
  153. let mut out_bytes = Vec::new();
  154. out_file.read_to_end(&mut out_bytes).unwrap();
  155. out_bytes
  156. }
  157. // Converts the input bytes to an output string in the format "0x01,0x02,0x03...".
  158. fn format_as_hex(data: &[u8]) -> String {
  159. let mut out = String::new();
  160. for (i, d) in data.iter().enumerate() {
  161. #[allow(clippy::format_push_string)]
  162. out.push_str(&format!("0x{:02x}", d));
  163. if i < data.len() - 1 {
  164. out.push(',')
  165. }
  166. }
  167. out
  168. }
  169. // A testing framework for creating simple plugins.
  170. struct MiniPlugin {
  171. // The size in bytes of the guest memory based at 0x0000.
  172. mem_size: u64,
  173. // The address in guest memory to load the assembly code.
  174. load_address: u32,
  175. // The nasm syntax 16-bit assembly code that will assembled and loaded into guest memory.
  176. assembly_src: &'static str,
  177. // The C source code that will be included in the mini_plugin_template.c file. This code must
  178. // define the forward declarations above the {src} line so that the completed plugin source
  179. // will compile.
  180. src: &'static str,
  181. }
  182. impl Default for MiniPlugin {
  183. fn default() -> Self {
  184. MiniPlugin {
  185. mem_size: 0x2000,
  186. load_address: 0x1000,
  187. assembly_src: "hlt",
  188. src: "",
  189. }
  190. }
  191. }
  192. // Builds and tests the given MiniPlugin definiton.
  193. fn test_mini_plugin(plugin: &MiniPlugin) {
  194. // Adds a preamble to ensure the output opcodes are 16-bit real mode and the lables start at the
  195. // load address.
  196. let assembly_src = format!(
  197. "org 0x{:x}\nbits 16\n{}",
  198. plugin.load_address, plugin.assembly_src
  199. );
  200. // Builds the assembly and convert it to a C literal array format.
  201. let assembly = build_assembly(&assembly_src);
  202. let assembly_hex = format_as_hex(&assembly);
  203. // Glues the pieces of this plugin together and tests the completed plugin.
  204. let generated_src = format!(
  205. include_str!("mini_plugin_template.c"),
  206. mem_size = plugin.mem_size,
  207. load_address = plugin.load_address,
  208. assembly_code = assembly_hex,
  209. src = plugin.src
  210. );
  211. test_plugin(&generated_src);
  212. }
  213. #[test]
  214. fn test_adder() {
  215. test_plugin(include_str!("plugin_adder.c"));
  216. }
  217. #[ignore] // TODO(b/239094055): fix the SIGSTOP usage that stops the cargo test runner
  218. #[test]
  219. fn test_hint() {
  220. test_plugin(include_str!("plugin_hint.c"));
  221. }
  222. #[test]
  223. fn test_async_write() {
  224. test_plugin(include_str!("plugin_async_write.c"));
  225. }
  226. #[test]
  227. fn test_dirty_log() {
  228. test_plugin(include_str!("plugin_dirty_log.c"));
  229. }
  230. #[test]
  231. fn test_ioevent() {
  232. test_plugin(include_str!("plugin_ioevent.c"));
  233. }
  234. #[test]
  235. fn test_irqfd() {
  236. test_plugin(include_str!("plugin_irqfd.c"));
  237. }
  238. #[test]
  239. fn test_extensions() {
  240. test_plugin(include_str!("plugin_extensions.c"));
  241. }
  242. #[test]
  243. fn test_supported_cpuid() {
  244. test_plugin(include_str!("plugin_supported_cpuid.c"));
  245. }
  246. // b:223675792
  247. #[ignore]
  248. #[test]
  249. fn test_enable_cap() {
  250. test_plugin(include_str!("plugin_enable_cap.c"));
  251. }
  252. #[test]
  253. fn test_msr_index_list() {
  254. test_plugin(include_str!("plugin_msr_index_list.c"));
  255. }
  256. #[test]
  257. fn test_vm_state_manipulation() {
  258. test_plugin(include_str!("plugin_vm_state.c"));
  259. }
  260. #[test]
  261. fn test_vcpu_pause() {
  262. test_plugin(include_str!("plugin_vcpu_pause.c"));
  263. }
  264. #[test]
  265. fn test_net_config() {
  266. if *TAP_AVAILABLE {
  267. test_plugin(include_str!("plugin_net_config.c"));
  268. }
  269. }
  270. #[test]
  271. fn test_debugregs() {
  272. let mini_plugin = MiniPlugin {
  273. assembly_src: "org 0x1000
  274. bits 16
  275. mov dr0, ebx
  276. mov eax, dr1
  277. mov byte [0x3000], 1",
  278. src: r#"
  279. #define DR1_VALUE 0x12
  280. #define RBX_VALUE 0xabcdef00
  281. #define KILL_ADDRESS 0x3000
  282. int g_kill_evt;
  283. struct kvm_regs g_regs;
  284. struct kvm_debugregs g_dregs;
  285. int setup_vm(struct crosvm *crosvm, void *mem) {
  286. g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
  287. crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
  288. return 0;
  289. }
  290. int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
  291. struct kvm_sregs *sregs)
  292. {
  293. regs->rbx = RBX_VALUE;
  294. struct kvm_debugregs dregs;
  295. crosvm_vcpu_get_debugregs(vcpu, &dregs);
  296. dregs.db[1] = DR1_VALUE;
  297. crosvm_vcpu_set_debugregs(vcpu, &dregs);
  298. return 0;
  299. }
  300. int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
  301. if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
  302. evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
  303. evt.io_access.address == KILL_ADDRESS &&
  304. evt.io_access.is_write &&
  305. evt.io_access.length == 1 &&
  306. evt.io_access.data[0] == 1)
  307. {
  308. uint64_t dummy = 1;
  309. crosvm_vcpu_get_debugregs(vcpu, &g_dregs);
  310. crosvm_vcpu_get_regs(vcpu, &g_regs);
  311. write(g_kill_evt, &dummy, sizeof(dummy));
  312. return 1;
  313. }
  314. return 0;
  315. }
  316. int check_result(struct crosvm *vcpu, void *mem) {
  317. if (g_dregs.db[1] != DR1_VALUE) {
  318. fprintf(stderr, "dr1 register has unexpected value: 0x%x\n", g_dregs.db[1]);
  319. return 1;
  320. }
  321. if (g_dregs.db[0] != RBX_VALUE) {
  322. fprintf(stderr, "dr0 register has unexpected value: 0x%x\n", g_dregs.db[0]);
  323. return 1;
  324. }
  325. if (g_regs.rax != DR1_VALUE) {
  326. fprintf(stderr, "eax register has unexpected value: 0x%x\n", g_regs.rax);
  327. return 1;
  328. }
  329. return 0;
  330. }"#,
  331. ..Default::default()
  332. };
  333. test_mini_plugin(&mini_plugin);
  334. }
  335. #[test]
  336. fn test_xcrs() {
  337. let mini_plugin = MiniPlugin {
  338. assembly_src: "org 0x1000
  339. bits 16
  340. mov byte [0x3000], 1",
  341. src: r#"
  342. #define XCR0_VALUE 0x1
  343. #define KILL_ADDRESS 0x3000
  344. int g_kill_evt;
  345. struct kvm_xcrs g_xcrs;
  346. int setup_vm(struct crosvm *crosvm, void *mem) {
  347. g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
  348. crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
  349. return 0;
  350. }
  351. int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
  352. struct kvm_sregs *sregs)
  353. {
  354. struct kvm_xcrs xcrs = {};
  355. xcrs.nr_xcrs = 1;
  356. xcrs.xcrs[0].value = XCR0_VALUE;
  357. crosvm_vcpu_set_xcrs(vcpu, &xcrs);
  358. return 0;
  359. }
  360. int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
  361. if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
  362. evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
  363. evt.io_access.address == KILL_ADDRESS &&
  364. evt.io_access.is_write &&
  365. evt.io_access.length == 1 &&
  366. evt.io_access.data[0] == 1)
  367. {
  368. uint64_t dummy = 1;
  369. crosvm_vcpu_get_xcrs(vcpu, &g_xcrs);
  370. write(g_kill_evt, &dummy, sizeof(dummy));
  371. return 1;
  372. }
  373. return 0;
  374. }
  375. int check_result(struct crosvm *vcpu, void *mem) {
  376. if (g_xcrs.xcrs[0].value != XCR0_VALUE) {
  377. fprintf(stderr, "xcr0 register has unexpected value: 0x%x\n",
  378. g_xcrs.xcrs[0].value);
  379. return 1;
  380. }
  381. return 0;
  382. }"#,
  383. ..Default::default()
  384. };
  385. test_mini_plugin(&mini_plugin);
  386. }
  387. #[test]
  388. fn test_msrs() {
  389. let mini_plugin = MiniPlugin {
  390. assembly_src: "org 0x1000
  391. bits 16
  392. rdmsr
  393. mov [0x0], eax
  394. mov [0x4], edx
  395. mov ecx, ebx
  396. mov eax, [0x8]
  397. mov edx, [0xc]
  398. wrmsr
  399. mov byte [es:0], 1",
  400. src: r#"
  401. #define MSR1_INDEX 0x00000174
  402. #define MSR1_DATA 1
  403. #define MSR2_INDEX 0x00000175
  404. #define MSR2_DATA 2
  405. #define KILL_ADDRESS 0x3000
  406. int g_kill_evt;
  407. uint32_t g_msr2_count;
  408. struct kvm_msr_entry g_msr2;
  409. int setup_vm(struct crosvm *crosvm, void *mem) {
  410. g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
  411. crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
  412. ((uint64_t*)mem)[1] = MSR2_DATA;
  413. return 0;
  414. }
  415. int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
  416. struct kvm_sregs *sregs)
  417. {
  418. regs->rcx = MSR1_INDEX;
  419. regs->rbx = MSR2_INDEX;
  420. sregs->es.base = KILL_ADDRESS;
  421. struct kvm_msr_entry msr1 = {0};
  422. msr1.index = MSR1_INDEX;
  423. msr1.data = MSR1_DATA;
  424. crosvm_vcpu_set_msrs(vcpu, 1, &msr1);
  425. return 0;
  426. }
  427. int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
  428. if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
  429. evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
  430. evt.io_access.address == KILL_ADDRESS &&
  431. evt.io_access.is_write &&
  432. evt.io_access.length == 1 &&
  433. evt.io_access.data[0] == 1)
  434. {
  435. uint64_t dummy = 1;
  436. g_msr2.index = MSR2_INDEX;
  437. crosvm_vcpu_get_msrs(vcpu, 1, &g_msr2, &g_msr2_count);
  438. write(g_kill_evt, &dummy, sizeof(dummy));
  439. return 1;
  440. }
  441. return 0;
  442. }
  443. int check_result(struct crosvm *vcpu, void *mem) {
  444. uint64_t msr1_data = ((uint64_t*)mem)[0];
  445. if (msr1_data != MSR1_DATA) {
  446. fprintf(stderr, "msr1 has unexpected value: 0x%x\n", msr1_data);
  447. return 1;
  448. }
  449. if (g_msr2_count != 1) {
  450. fprintf(stderr, "incorrect number of returned MSRSs: %d\n", g_msr2_count);
  451. return 1;
  452. }
  453. if (g_msr2.data != MSR2_DATA) {
  454. fprintf(stderr, "msr2 has unexpected value: 0x%x\n", g_msr2.data);
  455. return 1;
  456. }
  457. return 0;
  458. }"#,
  459. ..Default::default()
  460. };
  461. test_mini_plugin(&mini_plugin);
  462. }
  463. #[test]
  464. fn test_cpuid() {
  465. let mini_plugin = MiniPlugin {
  466. assembly_src: "org 0x1000
  467. bits 16
  468. push eax
  469. push ecx
  470. cpuid
  471. mov [0x0], eax
  472. mov [0x4], ebx
  473. mov [0x8], ecx
  474. mov [0xc], edx
  475. pop ecx
  476. pop eax
  477. add ecx, 1
  478. cpuid
  479. mov [0x10], eax
  480. mov [0x14], ebx
  481. mov [0x18], ecx
  482. mov [0x1c], edx
  483. mov byte [es:0], 1",
  484. src: r#"
  485. #define ENTRY1_INDEX 0
  486. #define ENTRY1_EAX 0x40414243
  487. #define ENTRY1_EBX 0x50515253
  488. #define ENTRY1_ECX 0x60616263
  489. #define ENTRY1_EDX 0x71727374
  490. #define ENTRY2_INDEX 1
  491. #define ENTRY2_EAX 0xAABBCCDD
  492. #define ENTRY2_EBX 0xEEFF0011
  493. #define ENTRY2_ECX 0x22334455
  494. #define ENTRY2_EDX 0x66778899
  495. #define KILL_ADDRESS 0x3000
  496. int g_kill_evt;
  497. struct kvm_msr_entry g_msr2;
  498. int setup_vm(struct crosvm *crosvm, void *mem) {
  499. g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
  500. crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
  501. return 0;
  502. }
  503. int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
  504. struct kvm_sregs *sregs)
  505. {
  506. regs->rax = ENTRY1_INDEX;
  507. regs->rcx = 0;
  508. regs->rsp = 0x1000;
  509. sregs->es.base = KILL_ADDRESS;
  510. struct kvm_cpuid_entry2 entries[2];
  511. entries[0].function = 0;
  512. entries[0].index = ENTRY1_INDEX;
  513. entries[0].flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
  514. entries[0].eax = ENTRY1_EAX;
  515. entries[0].ebx = ENTRY1_EBX;
  516. entries[0].ecx = ENTRY1_ECX;
  517. entries[0].edx = ENTRY1_EDX;
  518. entries[1].function = 0;
  519. entries[1].index = ENTRY2_INDEX;
  520. entries[1].flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
  521. entries[1].eax = ENTRY2_EAX;
  522. entries[1].ebx = ENTRY2_EBX;
  523. entries[1].ecx = ENTRY2_ECX;
  524. entries[1].edx = ENTRY2_EDX;
  525. return crosvm_vcpu_set_cpuid(vcpu, 2, entries);
  526. }
  527. int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
  528. if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
  529. evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
  530. evt.io_access.address == KILL_ADDRESS &&
  531. evt.io_access.is_write &&
  532. evt.io_access.length == 1 &&
  533. evt.io_access.data[0] == 1)
  534. {
  535. uint64_t dummy = 1;
  536. write(g_kill_evt, &dummy, sizeof(dummy));
  537. return 1;
  538. }
  539. return 0;
  540. }
  541. int check_result(struct crosvm *vcpu, void *memory) {
  542. uint32_t *mem = (uint32_t*)memory;
  543. if (mem[0] != ENTRY1_EAX) {
  544. fprintf(stderr, "entry 1 eax has unexpected value: 0x%x\n", mem[0]);
  545. return 1;
  546. }
  547. if (mem[1] != ENTRY1_EBX) {
  548. fprintf(stderr, "entry 1 ebx has unexpected value: 0x%x\n", mem[1]);
  549. return 1;
  550. }
  551. if (mem[2] != ENTRY1_ECX) {
  552. fprintf(stderr, "entry 1 ecx has unexpected value: 0x%x\n", mem[2]);
  553. return 1;
  554. }
  555. if (mem[3] != ENTRY1_EDX) {
  556. fprintf(stderr, "entry 1 edx has unexpected value: 0x%x\n", mem[3]);
  557. return 1;
  558. }
  559. if (mem[4] != ENTRY2_EAX) {
  560. fprintf(stderr, "entry 2 eax has unexpected value: 0x%x\n", mem[4]);
  561. return 1;
  562. }
  563. if (mem[5] != ENTRY2_EBX) {
  564. fprintf(stderr, "entry 2 ebx has unexpected value: 0x%x\n", mem[5]);
  565. return 1;
  566. }
  567. if (mem[6] != ENTRY2_ECX) {
  568. fprintf(stderr, "entry 2 ecx has unexpected value: 0x%x\n", mem[6]);
  569. return 1;
  570. }
  571. if (mem[7] != ENTRY2_EDX) {
  572. fprintf(stderr, "entry 2 edx has unexpected value: 0x%x\n", mem[7]);
  573. return 1;
  574. }
  575. return 0;
  576. }"#,
  577. ..Default::default()
  578. };
  579. test_mini_plugin(&mini_plugin);
  580. }
  581. #[test]
  582. fn test_vcpu_state_manipulation() {
  583. let mini_plugin = MiniPlugin {
  584. assembly_src: "org 0x1000
  585. bits 16
  586. mov byte [0x3000], 1",
  587. src: r#"
  588. #define KILL_ADDRESS 0x3000
  589. int g_kill_evt;
  590. bool success = false;
  591. int setup_vm(struct crosvm *crosvm, void *mem) {
  592. g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
  593. crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
  594. return 0;
  595. }
  596. int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
  597. struct kvm_sregs *sregs)
  598. {
  599. int ret;
  600. struct kvm_lapic_state lapic;
  601. ret = crosvm_vcpu_get_lapic_state(vcpu, &lapic);
  602. if (ret < 0) {
  603. fprintf(stderr, "failed to get initial LAPIC state: %d\n", ret);
  604. return 1;
  605. }
  606. ret = crosvm_vcpu_set_lapic_state(vcpu, &lapic);
  607. if (ret < 0) {
  608. fprintf(stderr, "failed to update LAPIC state: %d\n", ret);
  609. return 1;
  610. }
  611. ret = crosvm_vcpu_get_lapic_state(vcpu, &lapic);
  612. if (ret < 0) {
  613. fprintf(stderr, "failed to get updated LAPIC state: %d\n", ret);
  614. return 1;
  615. }
  616. struct kvm_mp_state mp_state;
  617. ret = crosvm_vcpu_get_mp_state(vcpu, &mp_state);
  618. if (ret < 0) {
  619. fprintf(stderr, "failed to get initial MP state: %d\n", ret);
  620. return 1;
  621. }
  622. ret = crosvm_vcpu_set_mp_state(vcpu, &mp_state);
  623. if (ret < 0) {
  624. fprintf(stderr, "failed to update MP state: %d\n", ret);
  625. return 1;
  626. }
  627. struct kvm_vcpu_events events;
  628. ret = crosvm_vcpu_get_vcpu_events(vcpu, &events);
  629. if (ret < 0) {
  630. fprintf(stderr, "failed to get VCPU events: %d\n", ret);
  631. return 1;
  632. }
  633. ret = crosvm_vcpu_set_vcpu_events(vcpu, &events);
  634. if (ret < 0) {
  635. fprintf(stderr, "failed to set VCPU events: %d\n", ret);
  636. return 1;
  637. }
  638. success = true;
  639. return 0;
  640. }
  641. int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
  642. if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
  643. evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
  644. evt.io_access.address == KILL_ADDRESS &&
  645. evt.io_access.is_write &&
  646. evt.io_access.length == 1 &&
  647. evt.io_access.data[0] == 1)
  648. {
  649. uint64_t dummy = 1;
  650. write(g_kill_evt, &dummy, sizeof(dummy));
  651. return 1;
  652. }
  653. return 0;
  654. }
  655. int check_result(struct crosvm *vcpu, void *mem) {
  656. if (!success) {
  657. fprintf(stderr, "test failed\n");
  658. return 1;
  659. }
  660. return 0;
  661. }"#,
  662. ..Default::default()
  663. };
  664. test_mini_plugin(&mini_plugin);
  665. }