| 43 | "#; |
| 44 | |
| 45 | fn compile_and_run_kernel(kernel_src: &str) -> (String, Option<i64>, u64) { |
| 46 | let snippet_manifest = BuildManifest::from_file( |
| 47 | std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/kernel_snippet.build"), |
| 48 | ) |
| 49 | .expect("kernel snippet build file parse"); |
| 50 | let stdlib_objs = CompilationPipeline::compile_stdlib_objects(TargetMode::Kernel) |
| 51 | .expect("kernel stdlib compile"); |
| 52 | // Kernel module deps (trap_handler, vmm, ...) from the closure; drop `my_kernel` so the |
| 53 | // test's own kmain supplies the entry. |
| 54 | let kernel_objs = |
| 55 | CompilationPipeline::compile_kernel_module_objects().expect("kernel modules compile"); |
| 56 | |
| 57 | let user_pipeline = CompilationPipeline::new(); |
| 58 | let user = user_pipeline.compile(kernel_src).expect("kernel compile"); |
| 59 | let (_, user_tokens) = user_pipeline.compile_ir_to_assembly_with_tokens(&user.ir_program); |
| 60 | let mut user_obj = user_pipeline.assemble(&user_tokens).expect("user assemble"); |
| 61 | for export in &snippet_manifest.abi_exports { |
| 62 | user_obj.mark_entry_global(export); |
| 63 | } |
| 64 | |
| 65 | let mut modules: Vec<(&str, &AssembledOutput)> = |
| 66 | stdlib_objs.iter().map(|(n, o)| (n.as_str(), o)).collect(); |
| 67 | for (name, obj) in &kernel_objs { |
| 68 | if name != "my_kernel" { |
| 69 | modules.push((name.as_str(), obj)); |
| 70 | } |
| 71 | } |
| 72 | modules.push(("user", &user_obj)); |
| 73 | let assembled = user_pipeline |
| 74 | .link_assembled_objects(&modules) |
| 75 | .expect("link"); |
| 76 | let mut vm = VirtualMachine::new_kernel(&assembled); |
| 77 | |
| 78 | // Run for a bit to let kernel boot |
| 79 | let boot_run = vm.run(500_000); |
| 80 | let uart_after_boot = boot_run.uart_output.clone(); |
| 81 | |
| 82 | // Now inject a UART RX byte |
| 83 | vm.uart_receive(0x41); // 'A' |
| 84 | |
| 85 | // Run for more steps to process the interrupt |
| 86 | let run = vm.run(100_000); |
| 87 | |
| 88 | // Get the CSRs to check scause |
| 89 | let csrs = vm.peek_csrs(); |
| 90 | let scause = csrs.scause; |
| 91 | |
| 92 | let exit = match run.outcome { |
| 93 | StepOutcome::Halted(code) => Some(code), |
| 94 | _ => None, |
| 95 | }; |
| 96 | |
| 97 | ( |
| 98 | format!("{}\n{}", uart_after_boot, run.uart_output), |
| 99 | exit, |
| 100 | scause, |
| 101 | ) |
| 102 | } |