├── cabi ├── dbg.cc ├── apic.cc ├── opcode-cabi.cc ├── devices-cabi.cc ├── gui.cc ├── system-cabi.cc ├── instr-cabi.cc ├── mem-cabi.cc ├── logfunctions-cabi.cc ├── siminterface-cabi.cc ├── cpu-cabi.cc └── paramtree.cc ├── TODO.md ├── src ├── lib.rs ├── opcode.rs ├── syncunsafecell.rs ├── mem │ ├── fastmap64_mem.rs │ ├── phy.rs │ ├── mod.rs │ └── virt.rs ├── logfunctions.rs ├── cpu │ ├── state.rs │ └── mod.rs ├── params.rs ├── sim.rs └── hook.rs ├── Cargo.toml ├── README.md └── .gitignore /cabi/dbg.cc: -------------------------------------------------------------------------------- 1 | #include "bochs.h" 2 | 3 | BOCHSAPI bx_debug_t bx_dbg; 4 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | - [ ] Fix SMP 2 | - [ ] Add CI 3 | - [ ] rustdoc all api methods :( 4 | - [ ] Fix variadic log functions 5 | - [ ] Figure out why Asan doesnt work with a rust binary 6 | - [-] Figure out how to do mutable references to a context struct 7 | - [ ] replace `lazy_static` with `phf` or `std::sync::Once` 8 | -------------------------------------------------------------------------------- /cabi/apic.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "bochs.h" 4 | 5 | // this is 0xff if xAPIC is supported or 0xf if not. AFAICT everything since 6 | // pentium 4 has supported xAPIC, so we'll just hardcode this. Values come from 7 | // bochs/main.cc 8 | BOCHSAPI bool simulate_xapic = true; 9 | BOCHSAPI Bit32u apic_id_mask = 0xff; 10 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate ctor; 3 | #[macro_use] 4 | extern crate log; 5 | 6 | pub static NUM_CPUS: usize = 255; 7 | 8 | pub type Address = u64; 9 | pub type PhyAddress = u64; 10 | 11 | mod logfunctions; 12 | mod params; 13 | mod sim; 14 | mod syncunsafecell; 15 | 16 | pub mod cpu; 17 | pub mod hook; 18 | pub mod mem; 19 | pub mod opcode; 20 | -------------------------------------------------------------------------------- /cabi/opcode-cabi.cc: -------------------------------------------------------------------------------- 1 | #include "bochs.h" 2 | #include "cpu/cpu.h" 3 | #include "cpu/decoder/ia_opcodes.h" 4 | 5 | #define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] 6 | 7 | C_ASSERT(BX_IA_ERROR == 0); 8 | // this is needed by over to detect end of trace events in before_exec hooks 9 | // to prevent double firing on some pc values 10 | C_ASSERT(BX_INSERTED_OPCODE == 1); 11 | -------------------------------------------------------------------------------- /cabi/devices-cabi.cc: -------------------------------------------------------------------------------- 1 | #include "bochs.h" 2 | 3 | #include "iodev/iodev.h" 4 | 5 | bx_devices_c::bx_devices_c() {} 6 | bx_devices_c::~bx_devices_c() {} 7 | Bit32u bx_devices_c::inp(Bit16u addr, unsigned len) { assert(false); return 0; } 8 | void bx_devices_c::outp(Bit16u addr, Bit32u value, unsigned len) { assert(false); } 9 | 10 | Bit32u bx_pci_device_c::pci_read_handler(unsigned char, unsigned int) { assert(false); return 0; } 11 | 12 | logfunctions *pluginlog; 13 | bx_devices_c bx_devices; 14 | -------------------------------------------------------------------------------- /src/opcode.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::c_void; 2 | 3 | // these should match the constants in opcode-cabi.cc and maybe eventually 4 | // be extracted with bindgen 5 | #[repr(u32)] 6 | #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] 7 | pub enum Opcode { 8 | Error = 0, 9 | Inserted = 1, 10 | } 11 | 12 | unsafe extern "C-unwind" { 13 | pub fn instr_bx_opcode(_: *const c_void) -> u32; 14 | pub fn instr_imm16(_: *const c_void) -> u16; 15 | pub fn instr_imm32(_: *const c_void) -> u32; 16 | pub fn instr_imm64(_: *const c_void) -> u64; 17 | // pub fn instr_dmp(); 18 | } 19 | -------------------------------------------------------------------------------- /src/syncunsafecell.rs: -------------------------------------------------------------------------------- 1 | use std::cell::UnsafeCell; 2 | use std::mem; 3 | 4 | pub struct SyncUnsafeCell(pub UnsafeCell); 5 | unsafe impl Sync for SyncUnsafeCell {} 6 | unsafe impl Send for SyncUnsafeCell {} 7 | 8 | impl SyncUnsafeCell { 9 | pub const fn new(a: T) -> Self { 10 | Self(UnsafeCell::new(a)) 11 | } 12 | } 13 | 14 | pub(crate) unsafe fn ptr_to_ref(ptr: *const T) -> &'static T { 15 | unsafe { mem::transmute(ptr) } 16 | } 17 | 18 | pub(crate) unsafe fn ptr_to_ref_mut(ptr: *mut T) -> &'static mut T { 19 | unsafe { mem::transmute(ptr) } 20 | } 21 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bochscpu" 3 | version = "0.1.0" 4 | authors = ["x"] 5 | edition = "2024" 6 | 7 | [lib] 8 | crate-type = ["dylib", "rlib"] 9 | 10 | [dependencies] 11 | blake3 = "1" 12 | ctor = "0.4" 13 | fnv = "1" 14 | log = { version = "0.4", features = ["release_max_level_off"] } 15 | serde = { version = "1", features = ["derive"], optional = true } 16 | 17 | [build-dependencies] 18 | cc = "1" 19 | 20 | [profile.dev] 21 | panic = "abort" 22 | 23 | [profile.release] 24 | panic = "abort" 25 | lto = true 26 | 27 | [profile.release-with-debuginfo] 28 | inherits = "release" 29 | debug = true 30 | -------------------------------------------------------------------------------- /cabi/gui.cc: -------------------------------------------------------------------------------- 1 | #include "bochs.h" 2 | #include "gui/gui.h" 3 | 4 | bx_gui_c *bx_gui = NULL; 5 | 6 | bx_gui_c::~bx_gui_c() {} 7 | 8 | void bx_gui_c::beep_on(float frequency) {} 9 | void bx_gui_c::beep_off() {} 10 | void bx_gui_c::get_capabilities(Bit16u *xres, Bit16u *yres, Bit16u *bpp) {} 11 | void bx_gui_c::show_ips(Bit32u ips_count) {} 12 | bx_svga_tileinfo_t *bx_gui_c::graphics_tile_info(bx_svga_tileinfo_t *info) { return NULL; } 13 | Bit8u *bx_gui_c::graphics_tile_get(unsigned x0, unsigned y0, unsigned *w, unsigned *h) { return NULL; } 14 | void bx_gui_c::graphics_tile_update_in_place(unsigned x0, unsigned y0, unsigned w, unsigned h) {} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bochscpu 2 | 3 | ## install 4 | 5 | Download the prebuilt artifacts from [bochscpu-build](https://github.com/yrp604/bochscpu-build). 6 | Install the `lib` and `bochs` folders into the `bochscpu` checkout. For example: 7 | ``` 8 | bochscpu$ ls -l 9 | total 20 10 | drwxrwxrwx 1 x x 4096 Jan 3 00:09 bochs # bochs directory from pre-built artifacts 11 | -rwxrwxrwx 1 x x 8318 Jan 2 23:28 build.rs 12 | drwxrwxrwx 1 x x 4096 Jan 2 23:28 cabi 13 | -rwxrwxrwx 1 x x 4772 Jan 3 00:16 Cargo.lock 14 | -rwxrwxrwx 1 x x 427 Jan 2 23:28 Cargo.toml 15 | drwxrwxrwx 1 x x 4096 Jan 3 00:09 lib # lib directory from pre-built artifacts 16 | -rwxrwxrwx 1 x x 502 Jan 2 23:28 README.md 17 | drwxrwxrwx 1 x x 4096 Jan 3 00:20 src 18 | drwxrwxrwx 1 x x 4096 Jan 3 00:16 target 19 | -rwxrwxrwx 1 x x 276 Jan 2 23:28 TODO.md 20 | ``` 21 | 22 | ## usage 23 | 24 | bochscpu exposes all the instrumentation points that bochs does. These are 25 | documented [here](http://bochs.sourceforge.net/cgi-bin/lxr/source/instrument/instrumentation.txt). 26 | 27 | For an example of initalizing and using the emulator, see the source code for 28 | the [benchmark example](https://github.com/yrp604/bochscpu-bench/blob/master/src/fib.rs). 29 | -------------------------------------------------------------------------------- /cabi/system-cabi.cc: -------------------------------------------------------------------------------- 1 | #include "bochs.h" 2 | #include "pc_system.h" 3 | 4 | bx_pc_system_c::bx_pc_system_c() { 5 | a20_mask = BX_CONST64(0xffffffffffffffff); 6 | kill_bochs_request = 0; 7 | currCountdown = 1; 8 | } 9 | 10 | int bx_pc_system_c::register_timer(void *this_ptr, bx_timer_handler_t, 11 | Bit32u useconds, bool continuous, bool active, const char *id) 12 | { 13 | assert(false); 14 | return 0; 15 | } 16 | 17 | int bx_pc_system_c::register_timer_ticks(void* this_ptr, 18 | bx_timer_handler_t funct, Bit64u ticks, bool continuous, bool active, 19 | const char *id) 20 | { 21 | return 0; // timer id 22 | } 23 | 24 | void bx_pc_system_c::activate_timer_ticks(unsigned int index, 25 | Bit64u instructions, bool continuous) 26 | { 27 | assert(false); 28 | } 29 | 30 | void bx_pc_system_c::deactivate_timer(unsigned int timer_index) { assert(false); } 31 | 32 | int bx_pc_system_c::Reset(unsigned int) { assert(false); return 0; } 33 | 34 | bool bx_pc_system_c::get_enable_a20(void) { assert(false); return true; } 35 | 36 | void bx_pc_system_c::countdownEvent(void) 37 | { 38 | bx_pc_system.currCountdown = 1; 39 | } 40 | void bx_pc_system_c::invlpg(bx_address addr) { assert(false); } 41 | 42 | bx_pc_system_c bx_pc_system; 43 | -------------------------------------------------------------------------------- /src/mem/fastmap64_mem.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::hash::BuildHasherDefault; 3 | 4 | use fnv::FnvHasher; 5 | 6 | use crate::PhyAddress; 7 | use crate::mem::page_off; 8 | use crate::syncunsafecell::{SyncUnsafeCell, ptr_to_ref_mut}; 9 | 10 | pub type FastMap64 = HashMap>; 11 | 12 | #[ctor] 13 | pub static MEM: SyncUnsafeCell> = 14 | unsafe { SyncUnsafeCell::new(FastMap64::default()) }; 15 | 16 | unsafe fn mem() -> &'static mut FastMap64 { 17 | unsafe { ptr_to_ref_mut(MEM.0.get()) } 18 | } 19 | 20 | pub unsafe fn resolve_hva(gpa: PhyAddress) -> *mut u8 { 21 | unsafe { 22 | let (page, off) = page_off(gpa); 23 | (*(mem().get(&page).unwrap())).add(off) 24 | } 25 | } 26 | 27 | pub unsafe fn resolve_hva_checked(gpa: PhyAddress) -> Option<*mut u8> { 28 | unsafe { 29 | let (page, off) = page_off(gpa); 30 | 31 | mem().get(&page).map(|p| p.add(off)) 32 | } 33 | } 34 | 35 | pub unsafe fn page_insert(gpa: PhyAddress, hva: *mut u8) { 36 | unsafe { 37 | let (page, _) = page_off(gpa); 38 | mem().insert(page, hva); 39 | } 40 | } 41 | 42 | pub unsafe fn page_remove(gpa: PhyAddress) { 43 | unsafe { 44 | let (page, _) = page_off(gpa); 45 | mem().remove(&page); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/mem/phy.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::slice; 3 | 4 | use crate::PhyAddress; 5 | use crate::mem::phy_translate; 6 | 7 | pub fn phy_read_u64(gpa: PhyAddress) -> u64 { 8 | let mut buf = [0; mem::size_of::()]; 9 | phy_read_slice(gpa, &mut buf); 10 | u64::from_le_bytes(buf) 11 | } 12 | 13 | pub fn phy_read_slice(gpa: PhyAddress, buf: &mut [u8]) { 14 | // make sure we dont span pages 15 | debug_assert!(gpa + (buf.len() as PhyAddress) <= (gpa & !0xfff) + 0x1000); 16 | 17 | let src = unsafe { 18 | let src_ptr = phy_translate(gpa); 19 | slice::from_raw_parts(src_ptr, buf.len()) 20 | }; 21 | 22 | buf.copy_from_slice(src); 23 | } 24 | 25 | pub fn phy_read(gpa: PhyAddress, buf: &mut Vec, sz: usize) { 26 | // make sure we dont span pages 27 | debug_assert!(gpa + (sz as PhyAddress) <= (gpa & !0xfff) + 0x1000); 28 | 29 | let len = buf.len(); 30 | buf.reserve(sz); 31 | let buf_slice = &mut buf[len..len + sz]; 32 | phy_read_slice(gpa, buf_slice) 33 | } 34 | 35 | pub fn phy_write(gpa: PhyAddress, data: &[u8]) { 36 | // make sure we dont span pages 37 | debug_assert!(gpa + (data.len() as PhyAddress) <= (gpa & !0xfff) + 0x1000); 38 | 39 | let dst = unsafe { 40 | let dst_ptr = phy_translate(gpa); 41 | slice::from_raw_parts_mut(dst_ptr, data.len()) 42 | }; 43 | 44 | dst.copy_from_slice(data); 45 | } 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bochs/* 2 | 3 | # will have compiled files and executables 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # Prerequisites 14 | *.d 15 | 16 | # Object files 17 | *.o 18 | *.ko 19 | *.obj 20 | *.elf 21 | 22 | # Linker output 23 | *.ilk 24 | *.map 25 | *.exp 26 | 27 | # Precompiled Headers 28 | *.gch 29 | *.pch 30 | 31 | # Libraries 32 | *.lib 33 | *.a 34 | *.la 35 | *.lo 36 | 37 | # Shared objects (inc. Windows DLLs) 38 | *.dll 39 | *.so 40 | *.so.* 41 | *.dylib 42 | 43 | # Executables 44 | *.exe 45 | *.out 46 | *.app 47 | *.i*86 48 | *.x86_64 49 | *.hex 50 | 51 | # Debug files 52 | *.dSYM/ 53 | *.su 54 | *.idb 55 | *.pdb 56 | 57 | # Kernel Module Compile Results 58 | *.mod* 59 | *.cmd 60 | .tmp_versions/ 61 | modules.order 62 | Module.symvers 63 | Mkfile.old 64 | dkms.conf 65 | 66 | # Prerequisites 67 | *.d 68 | 69 | # Compiled Object files 70 | *.slo 71 | *.lo 72 | *.o 73 | *.obj 74 | 75 | # Precompiled Headers 76 | *.gch 77 | *.pch 78 | 79 | # Compiled Dynamic libraries 80 | *.so 81 | *.dylib 82 | *.dll 83 | 84 | # Fortran module files 85 | *.mod 86 | *.smod 87 | 88 | # Compiled Static libraries 89 | *.lai 90 | *.la 91 | *.a 92 | *.lib 93 | 94 | # Executables 95 | *.exe 96 | *.out 97 | *.app 98 | -------------------------------------------------------------------------------- /cabi/instr-cabi.cc: -------------------------------------------------------------------------------- 1 | #include "bochs.h" 2 | #include "cpu/cpu.h" 3 | 4 | #include "cpu/decoder/ia_opcodes.h" 5 | 6 | extern "C" { 7 | // NOTE: this is the _bochs_ opcode, not the intel opcode 8 | unsigned instr_bx_opcode(void *i) { 9 | bxInstruction_c *instr = (bxInstruction_c *)i; 10 | return instr->getIaOpcode(); 11 | } 12 | 13 | Bit16u instr_imm16(void *i) { 14 | bxInstruction_c *instr = (bxInstruction_c *)i; 15 | return instr->Iw(); 16 | } 17 | 18 | Bit32u instr_imm32(void *i) { 19 | bxInstruction_c *instr = (bxInstruction_c *)i; 20 | return instr->Id(); 21 | } 22 | 23 | Bit64u instr_imm64(void *i) { 24 | bxInstruction_c *instr = (bxInstruction_c *)i; 25 | return instr->Iq(); 26 | } 27 | 28 | /* 29 | void instr_dmp() { 30 | // 64 31 | printf("const BX_IA_CMP_RAXId: u32 = %#x;\n", BX_IA_CMP_RAXId); 32 | printf("const BX_IA_CMP_EqsIb: u32 = %#x;\n", BX_IA_CMP_EqsIb); 33 | printf("const BX_IA_CMP_EqId: u32 = %#x;\n", BX_IA_CMP_EqId); 34 | 35 | // 32 36 | printf("const BX_IA_CMP_EAXId: u32 = %#x;\n", BX_IA_CMP_EAXId); 37 | printf("const BX_IA_CMP_EdId: u32 = %#x;\n", BX_IA_CMP_EdId); 38 | printf("const BX_IA_CMP_EdsIb: u32 = %#x;\n", BX_IA_CMP_EdsIb); 39 | 40 | // 16 41 | printf("const BX_IA_CMP_AXIw: u32 = %#x;\n", BX_IA_CMP_AXIw); 42 | printf("const BX_IA_CMP_EwIw: u32 = %#x;\n", BX_IA_CMP_EwIw); 43 | printf("const BX_IA_CMP_EwsIb: u32 = %#x;\n", BX_IA_CMP_EwsIb); 44 | } 45 | */ 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/logfunctions.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::CStr; 2 | use std::os::raw::c_char; 3 | use std::process; 4 | 5 | #[unsafe(no_mangle)] 6 | extern "C-unwind" fn logfunctions_error(p: *const c_char) { 7 | let s = unsafe { 8 | assert!(!p.is_null()); 9 | 10 | CStr::from_ptr(p).to_str().unwrap() 11 | }; 12 | 13 | error!("{}", s); 14 | } 15 | 16 | #[unsafe(no_mangle)] 17 | extern "C-unwind" fn logfunctions_fatal1(p: *const c_char) { 18 | logfunctions_error(p); 19 | 20 | process::exit(1); 21 | } 22 | 23 | #[unsafe(no_mangle)] 24 | extern "C-unwind" fn logfunctions_info(p: *const c_char) { 25 | let s = unsafe { 26 | assert!(!p.is_null()); 27 | 28 | CStr::from_ptr(p).to_str().unwrap() 29 | }; 30 | 31 | info!("{}", s); 32 | } 33 | 34 | #[unsafe(no_mangle)] 35 | extern "C-unwind" fn logfunctions_ldebug(p: *const c_char) { 36 | let s = unsafe { 37 | assert!(!p.is_null()); 38 | 39 | CStr::from_ptr(p).to_str().unwrap() 40 | }; 41 | 42 | debug!("{}", s); 43 | } 44 | 45 | #[unsafe(no_mangle)] 46 | extern "C-unwind" fn logfunctions_lwarn(p: *const c_char) { 47 | let s = unsafe { 48 | assert!(!p.is_null()); 49 | 50 | CStr::from_ptr(p).to_str().unwrap() 51 | }; 52 | 53 | warn!("{}", s); 54 | } 55 | 56 | #[unsafe(no_mangle)] 57 | extern "C-unwind" fn logfunctions_panic(p: *const c_char) { 58 | let s = unsafe { 59 | assert!(!p.is_null()); 60 | 61 | CStr::from_ptr(p).to_str().unwrap() 62 | }; 63 | 64 | println!("{}", s); 65 | process::exit(1); 66 | } 67 | -------------------------------------------------------------------------------- /cabi/mem-cabi.cc: -------------------------------------------------------------------------------- 1 | #include "bochs.h" 2 | #include "cpu/cpu.h" 3 | #include "memory/memory-bochs.h" 4 | 5 | namespace rust { 6 | extern "C" { 7 | Bit8u* mem_guest_to_host(unsigned, bx_phy_address, unsigned); 8 | void mem_read_phy(unsigned, bx_phy_address, unsigned, void *); 9 | void mem_write_phy(unsigned, bx_phy_address, unsigned, void *); 10 | } 11 | } 12 | 13 | BX_MEM_C::BX_MEM_C() = default; 14 | BX_MEM_C::~BX_MEM_C() = default; 15 | BX_MEMORY_STUB_C::BX_MEMORY_STUB_C() = default; 16 | BX_MEMORY_STUB_C::~BX_MEMORY_STUB_C() = default; 17 | 18 | void BX_MEM_C::writePhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, 19 | unsigned len, void *data) 20 | { 21 | return rust::mem_write_phy(cpu->which_cpu(), addr, len, data); 22 | } 23 | 24 | void BX_MEM_C::readPhysicalPage(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data) 25 | { 26 | return rust::mem_read_phy(cpu->which_cpu(), addr, len, data); 27 | } 28 | 29 | Bit8u *BX_MEM_C::getHostMemAddr(BX_CPU_C *cpu, bx_phy_address addr, unsigned rw) 30 | { 31 | return rust::mem_guest_to_host(cpu->which_cpu(), addr, rw); 32 | } 33 | 34 | bool BX_MEM_C::dbg_fetch_mem(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, Bit8u *buf) 35 | { 36 | assert(false); 37 | 38 | return false; 39 | } 40 | 41 | 42 | bool BX_MEM_C::registerMemoryHandlers( 43 | void *param, 44 | memory_handler_t read_handler, 45 | memory_handler_t write_handler, 46 | memory_direct_access_handler_t da_handler, 47 | bx_phy_address begin_addr, 48 | bx_phy_address end_addr) 49 | { 50 | assert(false); 51 | 52 | return false; 53 | } 54 | 55 | Bit64u BX_MEMORY_STUB_C::get_memory_len() 56 | { 57 | return (BX_MEM_THIS len); 58 | } 59 | 60 | BOCHSAPI BX_MEM_C bx_mem; 61 | -------------------------------------------------------------------------------- /src/cpu/state.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "serde")] 2 | use serde::{Deserialize, Serialize}; 3 | 4 | use crate::cpu::{Float80, GlobalSeg, Seg, Zmm}; 5 | 6 | #[derive(Clone, PartialEq, Eq, Debug, Default, Hash)] 7 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 8 | #[repr(C)] 9 | pub struct State { 10 | pub bochscpu_seed: u64, 11 | 12 | pub rax: u64, 13 | pub rcx: u64, 14 | pub rdx: u64, 15 | pub rbx: u64, 16 | pub rsp: u64, 17 | pub rbp: u64, 18 | pub rsi: u64, 19 | pub rdi: u64, 20 | pub r8: u64, 21 | pub r9: u64, 22 | pub r10: u64, 23 | pub r11: u64, 24 | pub r12: u64, 25 | pub r13: u64, 26 | pub r14: u64, 27 | pub r15: u64, 28 | pub rip: u64, 29 | pub rflags: u64, 30 | pub ssp: u64, 31 | 32 | pub es: Seg, 33 | pub cs: Seg, 34 | pub ss: Seg, 35 | pub ds: Seg, 36 | pub fs: Seg, 37 | pub gs: Seg, 38 | 39 | pub ldtr: Seg, 40 | pub tr: Seg, 41 | pub gdtr: GlobalSeg, 42 | pub idtr: GlobalSeg, 43 | 44 | pub cr0: u32, 45 | pub cr2: u64, 46 | pub cr3: u64, 47 | pub cr4: u32, 48 | pub cr8: u64, 49 | 50 | pub dr0: u64, 51 | pub dr1: u64, 52 | pub dr2: u64, 53 | pub dr3: u64, 54 | pub dr6: u32, 55 | pub dr7: u32, 56 | 57 | pub xcr0: u32, 58 | 59 | pub zmm: [Zmm; 32], 60 | 61 | // TODO fp regs 62 | // TODO fp control info 63 | pub fpcw: u16, 64 | pub fpsw: u16, 65 | pub fptw: u16, 66 | pub fpop: u16, 67 | pub fpst: [Float80; 8], 68 | 69 | // TODO xmm control info 70 | pub mxcsr: u32, 71 | pub mxcsr_mask: u32, 72 | 73 | // TODO cmm control info 74 | pub tsc: u64, 75 | pub efer: u32, 76 | pub kernel_gs_base: u64, 77 | pub apic_base: u64, 78 | pub pat: u64, 79 | pub sysenter_cs: u64, 80 | pub sysenter_eip: u64, 81 | pub sysenter_esp: u64, 82 | pub star: u64, 83 | pub lstar: u64, 84 | pub cstar: u64, 85 | pub sfmask: u64, 86 | pub tsc_aux: u64, 87 | pub cet_control_u: u64, 88 | pub cet_control_s: u64, 89 | pub pl0_ssp: u64, 90 | pub pl1_ssp: u64, 91 | pub pl2_ssp: u64, 92 | pub pl3_ssp: u64, 93 | pub interrupt_ssp_table: u64, 94 | } 95 | -------------------------------------------------------------------------------- /src/params.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::{CStr, c_void}; 2 | use std::marker::Sync; 3 | use std::os::raw::c_char; 4 | use std::ptr; 5 | 6 | unsafe extern "C-unwind" { 7 | fn sim_new_param_enum(name: *const c_char, val: *const *const c_char, idx: u32) -> *mut c_void; 8 | fn sim_delete_param_enum(name: *mut c_void); 9 | 10 | fn sim_new_param_num(name: *const c_char, min: u64, max: u64, val: u64) -> *mut c_void; 11 | fn sim_delete_param_num(n: *mut c_void); 12 | 13 | fn sim_new_param_bool(name: *const c_char, val: u32) -> *mut c_void; 14 | fn sim_delete_param_bool(n: *mut c_void); 15 | 16 | fn sim_new_param_string(name: *const c_char, val: *const c_char, sz: u32) -> *mut c_void; 17 | fn sim_delete_param_string(n: *mut c_void); 18 | } 19 | 20 | pub struct ParamEnum(pub *mut c_void, Vec<*const c_char>); 21 | impl ParamEnum { 22 | pub fn new(name: &'static CStr, val: &[&'static CStr], idx: usize) -> Self { 23 | let mut a: Vec<*const c_char> = 24 | val.iter().map(|x| x as *const _ as *const c_char).collect(); 25 | assert!(idx < a.len()); 26 | a.push(ptr::null()); 27 | 28 | let p = unsafe { sim_new_param_enum(name.as_ptr(), a.as_ptr(), idx as u32) }; 29 | 30 | Self(p, a) 31 | } 32 | } 33 | impl Drop for ParamEnum { 34 | fn drop(&mut self) { 35 | unsafe { sim_delete_param_enum(self.0) } 36 | } 37 | } 38 | unsafe impl Sync for ParamEnum {} 39 | 40 | pub struct ParamNum(pub *mut c_void); 41 | impl ParamNum { 42 | pub fn new(name: &'static CStr, min: u64, max: u64, val: u64) -> Self { 43 | let p = unsafe { sim_new_param_num(name.as_ptr(), min, max, val) }; 44 | 45 | Self(p) 46 | } 47 | } 48 | impl Drop for ParamNum { 49 | fn drop(&mut self) { 50 | unsafe { sim_delete_param_num(self.0) } 51 | } 52 | } 53 | unsafe impl Sync for ParamNum {} 54 | 55 | pub struct ParamBool(pub *mut c_void); 56 | impl ParamBool { 57 | pub fn new(name: &'static CStr, val: bool) -> Self { 58 | let p = unsafe { sim_new_param_bool(name.as_ptr(), val as u32) }; 59 | 60 | Self(p) 61 | } 62 | } 63 | impl Drop for ParamBool { 64 | fn drop(&mut self) { 65 | unsafe { sim_delete_param_bool(self.0) } 66 | } 67 | } 68 | unsafe impl Sync for ParamBool {} 69 | 70 | pub struct ParamString(pub *mut c_void); 71 | impl ParamString { 72 | pub fn new(name: &'static CStr, val: &'static CStr) -> Self { 73 | let p = unsafe { 74 | sim_new_param_string( 75 | name.as_ptr(), 76 | val.as_ptr(), 77 | val.to_bytes_with_nul().len() as _, 78 | ) 79 | }; 80 | 81 | Self(p) 82 | } 83 | } 84 | impl Drop for ParamString { 85 | fn drop(&mut self) { 86 | unsafe { sim_delete_param_string(self.0) } 87 | } 88 | } 89 | unsafe impl Sync for ParamString {} 90 | -------------------------------------------------------------------------------- /cabi/logfunctions-cabi.cc: -------------------------------------------------------------------------------- 1 | // 3/25/19: rust cannot currently define extern C variadic functions so were 2 | // stuck with this shit 3 | // 4 | // TODO when rust supports extern variadic functions, replace all of this 5 | // with var args versions 6 | // 7 | // 4/18/19 so because were stuck with this shit right now we spend a lot of 8 | // time inside vsnprintf, only to discard the formatted results. We'll hack 9 | // around this by not doing shit on release builds. 10 | #include 11 | #include 12 | 13 | #include "bochs.h" 14 | 15 | namespace rust { 16 | extern "C" { 17 | void logfunctions_error(const char *); 18 | void logfunctions_ldebug(const char *); 19 | void logfunctions_lwarn(const char *); 20 | void logfunctions_info(const char *); 21 | void logfunctions_panic(const char *); 22 | void logfunctions_fatal1(const char *); 23 | } 24 | } 25 | 26 | int logfunctions::default_onoff[N_LOGLEV] = 27 | { 28 | ACT_IGNORE, // ignore debug 29 | ACT_REPORT, // report info 30 | ACT_REPORT, // report error 31 | ACT_FATAL // on panic, quit 32 | }; 33 | 34 | logfunctions::logfunctions(void) {} 35 | logfunctions::~logfunctions(void) {} 36 | 37 | void logfunctions::error(const char *fmt, ...) { 38 | #ifndef RUST_CC_RELEASE 39 | char buf[0x1000]; 40 | 41 | va_list args; 42 | va_start(args, fmt); 43 | vsnprintf(buf, sizeof buf, fmt, args); 44 | va_end(args); 45 | 46 | rust::logfunctions_error(buf); 47 | #endif 48 | } 49 | 50 | void logfunctions::fatal1(const char *fmt, ...) { 51 | #ifndef RUST_CC_RELEASE 52 | char buf[0x1000]; 53 | 54 | va_list args; 55 | va_start(args, fmt); 56 | vsnprintf(buf, sizeof buf, fmt, args); 57 | va_end(args); 58 | 59 | rust::logfunctions_fatal1(buf); 60 | #endif 61 | } 62 | 63 | void logfunctions::info(const char *fmt, ...) { 64 | #ifndef RUST_CC_RELEASE 65 | char buf[0x1000]; 66 | 67 | va_list args; 68 | va_start(args, fmt); 69 | vsnprintf(buf, sizeof buf, fmt, args); 70 | va_end(args); 71 | 72 | rust::logfunctions_info(buf); 73 | #endif 74 | } 75 | 76 | void logfunctions::ldebug(const char *fmt, ...) { 77 | #ifndef RUST_CC_RELEASE 78 | char buf[0x1000]; 79 | 80 | va_list args; 81 | va_start(args, fmt); 82 | vsnprintf(buf, sizeof buf, fmt, args); 83 | va_end(args); 84 | 85 | rust::logfunctions_ldebug(buf); 86 | #endif 87 | } 88 | 89 | void logfunctions::lwarn(const char *fmt, ...) { 90 | #ifndef RUST_CC_RELEASE 91 | char buf[0x1000]; 92 | 93 | va_list args; 94 | va_start(args, fmt); 95 | vsnprintf(buf, sizeof buf, fmt, args); 96 | va_end(args); 97 | 98 | rust::logfunctions_lwarn(buf); 99 | #endif 100 | } 101 | 102 | void logfunctions::panic(const char *fmt, ...) { 103 | #ifndef RUST_CC_RELEASE 104 | char buf[0x1000]; 105 | 106 | va_list args; 107 | va_start(args, fmt); 108 | vsnprintf(buf, sizeof buf, fmt, args); 109 | va_end(args); 110 | 111 | rust::logfunctions_panic(buf); 112 | #endif 113 | } 114 | 115 | void logfunctions::put(const char *p, const char *q) {} 116 | 117 | BOCHSAPI class logfunctions *genlog = NULL; 118 | -------------------------------------------------------------------------------- /cabi/siminterface-cabi.cc: -------------------------------------------------------------------------------- 1 | #include "bochs.h" 2 | #include "gui/siminterface.h" 3 | 4 | namespace rust { 5 | extern "C" { 6 | bx_param_enum_c *sim_get_param_enum(const char *); 7 | bx_param_num_c *sim_get_param_num(const char *); 8 | bx_param_bool_c *sim_get_param_bool(const char *); 9 | bx_param_string_c *sim_get_param_string(const char *); 10 | } 11 | } 12 | 13 | class bx_real_sim_c : public bx_simulator_interface_c { 14 | public: 15 | bx_real_sim_c(); 16 | virtual bx_param_enum_c *get_param_enum(const char *pname, bx_param_c *base=NULL); 17 | virtual bx_param_num_c *get_param_num(const char *pname, bx_param_c *base=NULL); 18 | virtual bx_param_bool_c *get_param_bool(const char *pname, bx_param_c *base=NULL); 19 | virtual bx_param_string_c *get_param_string(const char *pname, bx_param_c *base=NULL); 20 | }; 21 | 22 | bx_real_sim_c::bx_real_sim_c() {} 23 | 24 | bx_param_enum_c *bx_real_sim_c::get_param_enum(const char *pname, bx_param_c *base) 25 | { 26 | return rust::sim_get_param_enum(pname); 27 | } 28 | 29 | bx_param_num_c *bx_real_sim_c::get_param_num(const char *pname, bx_param_c *base) 30 | { 31 | return rust::sim_get_param_num(pname); 32 | } 33 | 34 | bx_param_bool_c *bx_real_sim_c::get_param_bool(const char *pname, bx_param_c *base) 35 | { 36 | return rust::sim_get_param_bool(pname); 37 | } 38 | 39 | bx_param_string_c *bx_real_sim_c::get_param_string(const char *pname, bx_param_c *base) 40 | { 41 | return rust::sim_get_param_string(pname); 42 | } 43 | 44 | extern "C" { 45 | BOCHSAPI bx_param_enum_c* sim_new_param_enum(const char *name, const char **values, 46 | Bit32u idx) 47 | { 48 | return new bx_param_enum_c( 49 | NULL, 50 | name, 51 | NULL, 52 | NULL, 53 | values, 54 | idx, 55 | 0 56 | ); 57 | } 58 | 59 | BOCHSAPI void sim_delete_param_enum(bx_param_enum_c *e) { 60 | delete e; 61 | } 62 | 63 | BOCHSAPI bx_param_num_c* sim_new_param_num(const char *name, Bit64u min, Bit64u max, 64 | Bit64u val) 65 | { 66 | return new bx_param_num_c( 67 | NULL, 68 | name, 69 | NULL, 70 | NULL, 71 | min, 72 | max, 73 | val 74 | ); 75 | } 76 | 77 | BOCHSAPI void sim_delete_param_num(bx_param_num_c *n) { 78 | delete n; 79 | } 80 | 81 | BOCHSAPI bx_param_bool_c* sim_new_param_bool(const char *name, bool val) 82 | { 83 | return new bx_param_bool_c( 84 | NULL, 85 | name, 86 | NULL, 87 | NULL, 88 | val 89 | ); 90 | } 91 | 92 | BOCHSAPI void sim_delete_param_bool(bx_param_bool_c *b) { 93 | delete b; 94 | } 95 | 96 | BOCHSAPI bx_param_string_c* sim_new_param_string(const char *name, const char *val, unsigned max_sz) 97 | { 98 | return new bx_param_string_c( 99 | NULL, 100 | name, 101 | NULL, 102 | NULL, 103 | val, 104 | max_sz 105 | ); 106 | } 107 | 108 | BOCHSAPI void sim_delete_param_string(bx_param_string_c *b) { 109 | delete b; 110 | } 111 | } 112 | 113 | logfunctions *siminterface_log = NULL; 114 | bx_list_c *root_param = NULL; 115 | bx_simulator_interface_c *SIM = new bx_real_sim_c(); 116 | -------------------------------------------------------------------------------- /src/mem/mod.rs: -------------------------------------------------------------------------------- 1 | use std::slice; 2 | 3 | use crate::PhyAddress; 4 | use crate::cpu::{cpu_bail, cpu_killbit}; 5 | use crate::syncunsafecell::SyncUnsafeCell; 6 | 7 | mod phy; 8 | pub use phy::*; 9 | 10 | mod virt; 11 | pub use virt::*; 12 | 13 | // despite all the benchmarks claiming that fxhash + hashbrown wins, for our 14 | // benchmarks fnvhash + hashbrown seems to be the winning combo 15 | mod fastmap64_mem; 16 | use fastmap64_mem::page_insert as mem_insert; 17 | pub use fastmap64_mem::page_remove; 18 | use fastmap64_mem::{resolve_hva, resolve_hva_checked}; 19 | 20 | pub const fn phy_mask(gpa: PhyAddress) -> PhyAddress { 21 | gpa & 0x000f_ffff_ffff_ffff 22 | } 23 | 24 | #[ctor] 25 | static FAULT: SyncUnsafeCell> = 26 | unsafe { SyncUnsafeCell::new(Box::new(|_| panic!("no missing_page function set"))) }; 27 | 28 | const fn page_off(a: PhyAddress) -> (PhyAddress, usize) { 29 | (a & !0xfff, a as usize & 0xfff) 30 | } 31 | 32 | pub unsafe fn fault(gpa: PhyAddress) { 33 | unsafe { 34 | let f = FAULT.0.get(); 35 | (**f)(gpa); 36 | } 37 | } 38 | 39 | pub unsafe fn page_insert(gpa: PhyAddress, hva: *mut u8) { 40 | unsafe { 41 | assert_eq!(hva.align_offset(0x1000), 0); 42 | 43 | mem_insert(gpa, hva) 44 | } 45 | } 46 | 47 | #[unsafe(no_mangle)] 48 | extern "C-unwind" fn mem_guest_to_host(cpu: u32, gpa: PhyAddress, _rw: u32) -> *mut u8 { 49 | trace!("translating guest phys {:x}...", gpa); 50 | 51 | unsafe { guest_phy_translate(cpu, gpa) } 52 | } 53 | 54 | #[unsafe(no_mangle)] 55 | extern "C-unwind" fn mem_read_phy(cpu: u32, gpa: PhyAddress, sz: u32, dst: *mut u8) { 56 | trace!("mem read {} bytes from phys {:x}...", sz, gpa); 57 | 58 | let sz = sz as usize; 59 | 60 | unsafe { 61 | let src_ptr = guest_phy_translate(cpu, gpa); 62 | let src = slice::from_raw_parts(src_ptr, sz); 63 | let dst = slice::from_raw_parts_mut(dst, sz); 64 | 65 | dst.copy_from_slice(src); 66 | trace!("mem read {:x?}", src); 67 | } 68 | } 69 | 70 | #[unsafe(no_mangle)] 71 | extern "C-unwind" fn mem_write_phy(cpu: u32, gpa: PhyAddress, sz: u32, src: *const u8) { 72 | trace!("mem write {} bytes to phys {:x}...", sz, gpa); 73 | 74 | let sz = sz as usize; 75 | 76 | unsafe { 77 | let dst_ptr = guest_phy_translate(cpu, gpa); 78 | let dst = slice::from_raw_parts_mut(dst_ptr, sz); 79 | let src = slice::from_raw_parts(src, sz); 80 | 81 | dst.copy_from_slice(src); 82 | trace!("mem write {:x?}", src); 83 | } 84 | } 85 | 86 | pub unsafe fn guest_phy_translate(cpu: u32, gpa: PhyAddress) -> *mut u8 { 87 | unsafe { 88 | // i think this is needed because bochs will call into this with high bits 89 | // set? 90 | let real_gpa = gpa & 0x000f_ffff_ffff_ffff; 91 | 92 | if let Some(hva) = resolve_hva_checked(real_gpa) { 93 | return hva; 94 | } 95 | 96 | fault(real_gpa); 97 | 98 | // check to see if our fault handler requested the cpu be killed 99 | if cpu_killbit(cpu) != 0 { 100 | cpu_bail(cpu) 101 | } 102 | 103 | resolve_hva(real_gpa) 104 | } 105 | } 106 | 107 | // this function exists to split translations happening by the emulator and 108 | // those requested by the guest. Emulator translations requests do not have an 109 | // associated cpu and thus cannot be killed by the page fault hook. 110 | pub unsafe fn phy_translate(gpa: PhyAddress) -> *mut u8 { 111 | unsafe { 112 | // i think this is needed because bochs will call into this with high bits 113 | // set? 114 | let real_gpa = phy_mask(gpa); 115 | 116 | if let Some(hva) = resolve_hva_checked(real_gpa) { 117 | return hva; 118 | } 119 | 120 | fault(real_gpa); 121 | 122 | resolve_hva(real_gpa) 123 | } 124 | } 125 | 126 | pub unsafe fn missing_page(f: T) { 127 | unsafe { 128 | *(FAULT.0.get()) = Box::new(f); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/mem/virt.rs: -------------------------------------------------------------------------------- 1 | use std::error::Error; 2 | use std::fmt; 3 | use std::iter; 4 | use std::mem; 5 | 6 | use crate::mem::{phy_mask, phy_read_slice, phy_read_u64, phy_write}; 7 | use crate::{Address, PhyAddress}; 8 | 9 | const fn pml4_index(gva: Address) -> u64 { 10 | gva >> (12 + (9 * 3)) & 0x1ff 11 | } 12 | 13 | const fn pdpt_index(gva: Address) -> u64 { 14 | gva >> (12 + (9 * 2)) & 0x1ff 15 | } 16 | 17 | const fn pd_index(gva: Address) -> u64 { 18 | gva >> (12 + (9 * 1)) & 0x1ff 19 | } 20 | 21 | const fn pt_index(gva: Address) -> u64 { 22 | gva >> (12 + (9 * 0)) & 0x1ff 23 | } 24 | 25 | const fn base_flags(gpa: Address) -> (Address, u64) { 26 | (phy_mask(gpa) & !0xfff, gpa & 0x1ff) 27 | } 28 | 29 | const fn pte_flags(pte: Address) -> (PhyAddress, u64) { 30 | (phy_mask(pte) & !0xfff, pte & 0xfff) 31 | } 32 | 33 | const fn page_offset(gva: Address) -> u64 { 34 | gva & 0xfff 35 | } 36 | 37 | #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] 38 | pub enum VirtMemError { 39 | Pml4eNotPresent, 40 | PdpteNotPresent, 41 | PdeNotPresent, 42 | PteNotPresent, 43 | } 44 | 45 | impl fmt::Display for VirtMemError { 46 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 47 | write!(f, "{:?}", self) 48 | } 49 | } 50 | 51 | impl Error for VirtMemError { 52 | fn description(&self) -> &str { 53 | "virtual to physical translation error" 54 | } 55 | 56 | fn cause(&self) -> Option<&dyn Error> { 57 | None 58 | } 59 | } 60 | 61 | pub fn virt_read_u64(cr3: PhyAddress, gva: Address) -> u64 { 62 | let mut buf = [0; mem::size_of::()]; 63 | virt_read_slice(cr3, gva, &mut buf); 64 | u64::from_le_bytes(buf) 65 | } 66 | 67 | pub fn virt_read_u32(cr3: PhyAddress, gva: Address) -> u32 { 68 | let mut buf = [0; mem::size_of::()]; 69 | virt_read_slice(cr3, gva, &mut buf); 70 | u32::from_le_bytes(buf) 71 | } 72 | 73 | pub fn virt_read_u16(cr3: PhyAddress, gva: Address) -> u16 { 74 | let mut buf = [0; mem::size_of::()]; 75 | virt_read_slice(cr3, gva, &mut buf); 76 | u16::from_le_bytes(buf) 77 | } 78 | 79 | pub fn virt_read_u8(cr3: PhyAddress, gva: Address) -> u8 { 80 | let mut buf = [0; mem::size_of::()]; 81 | virt_read_slice(cr3, gva, &mut buf); 82 | u8::from_le_bytes(buf) 83 | } 84 | 85 | fn chunked(start: Address, sz: usize) -> impl Iterator { 86 | debug_assert!(start.checked_add(sz as u64).is_some()); 87 | 88 | let mut remaining = sz; 89 | let mut base = start; 90 | 91 | iter::from_fn(move || { 92 | if remaining == 0 { 93 | None 94 | } else { 95 | let chunk_base = base; 96 | 97 | let chunk_sz = if base as usize + remaining > (base as usize & !0xfff) + 0x1000 { 98 | ((base & !0xfff) + 0x1000 - base) as usize 99 | } else { 100 | remaining 101 | }; 102 | 103 | base += chunk_sz as Address; 104 | remaining -= chunk_sz; 105 | 106 | Some((chunk_base, chunk_sz)) 107 | } 108 | }) 109 | } 110 | 111 | pub fn virt_read(cr3: PhyAddress, gva: Address, buf: &mut Vec, sz: usize) { 112 | virt_read_checked(cr3, gva, buf, sz).unwrap() 113 | } 114 | 115 | pub fn virt_read_checked( 116 | cr3: PhyAddress, 117 | gva: Address, 118 | buf: &mut Vec, 119 | sz: usize, 120 | ) -> Result<(), VirtMemError> { 121 | debug_assert!(gva.checked_add(sz as u64).is_some()); 122 | 123 | let len = buf.len(); 124 | buf.reserve(sz); 125 | 126 | unsafe { 127 | buf.set_len(len + sz); 128 | 129 | let r = virt_read_slice_checked(cr3, gva, &mut buf[len..len + sz]); 130 | 131 | // if we errored, roll the length back to the original 132 | if r.is_err() { 133 | buf.set_len(len); 134 | } 135 | 136 | r 137 | } 138 | } 139 | 140 | pub fn virt_read_slice(cr3: PhyAddress, gva: Address, buf: &mut [u8]) { 141 | virt_read_slice_checked(cr3, gva, buf).unwrap() 142 | } 143 | 144 | pub fn virt_read_slice_checked( 145 | cr3: PhyAddress, 146 | gva: Address, 147 | buf: &mut [u8], 148 | ) -> Result<(), VirtMemError> { 149 | debug_assert!(gva.checked_add(buf.len() as u64).is_some()); 150 | 151 | let mut off = 0; 152 | 153 | for (start, sz) in chunked(gva, buf.len()) { 154 | let gpa = virt_translate_checked(cr3, start)?; 155 | phy_read_slice(gpa, &mut buf[off..off + sz]); 156 | off += sz; 157 | } 158 | 159 | Ok(()) 160 | } 161 | 162 | pub fn virt_write(cr3: PhyAddress, gva: Address, buf: &[u8]) { 163 | virt_write_checked(cr3, gva, buf).unwrap() 164 | } 165 | 166 | pub fn virt_write_checked(cr3: PhyAddress, gva: Address, buf: &[u8]) -> Result<(), VirtMemError> { 167 | debug_assert!(gva.checked_add(buf.len() as u64).is_some()); 168 | 169 | let mut off = 0; 170 | 171 | for (start, sz) in chunked(gva, buf.len()) { 172 | let gpa = virt_translate_checked(cr3, start)?; 173 | 174 | phy_write(gpa, &buf[off..off + sz]); 175 | 176 | off += sz; 177 | } 178 | 179 | Ok(()) 180 | } 181 | 182 | pub fn virt_translate(cr3: PhyAddress, gva: Address) -> PhyAddress { 183 | virt_translate_checked(cr3, gva).unwrap() 184 | } 185 | 186 | pub fn virt_translate_checked(cr3: PhyAddress, gva: Address) -> Result { 187 | let (pml4_base, _) = base_flags(cr3); 188 | 189 | let pml4e_addr = pml4_base + pml4_index(gva) * 8; 190 | let pml4e = phy_read_u64(pml4e_addr); 191 | 192 | let (pdpt_base, pml4e_flags) = base_flags(pml4e); 193 | 194 | if pml4e_flags & 1 == 0 { 195 | return Err(VirtMemError::Pml4eNotPresent); 196 | } 197 | 198 | let pdpte_addr = pdpt_base + pdpt_index(gva) * 8; 199 | let pdpte = phy_read_u64(pdpte_addr); 200 | 201 | let (pd_base, pdpte_flags) = base_flags(pdpte); 202 | 203 | if pdpte_flags & 1 == 0 { 204 | return Err(VirtMemError::PdpteNotPresent); 205 | } 206 | 207 | // huge pages: 208 | // 7 (PS) - Page size; must be 1 (otherwise, this entry references a page 209 | // directory; see Table 4-1 210 | if pdpte_flags & 1 << 7 != 0 { 211 | return Ok((pd_base & 0xffff_ffff_c000_0000) + (gva & 0x3fff_ffff)); 212 | } 213 | 214 | let pde_addr = pd_base + pd_index(gva) * 8; 215 | let pde = phy_read_u64(pde_addr); 216 | 217 | let (pt_base, pde_flags) = base_flags(pde); 218 | 219 | if pde_flags & 1 == 0 { 220 | return Err(VirtMemError::PdeNotPresent); 221 | } 222 | 223 | // large pages: 224 | // 7 (PS) - Page size; must be 1 (otherwise, this entry references a page 225 | // table; see Table 4-18 226 | if pde_flags & 1 << 7 != 0 { 227 | return Ok((pt_base & 0xffff_ffff_ffe0_0000) + (gva & 0x1f_ffff)); 228 | } 229 | 230 | let pte_addr = pt_base + pt_index(gva) * 8; 231 | let pte = phy_read_u64(pte_addr); 232 | 233 | let (pte_paddr, pte_flags) = pte_flags(pte); 234 | 235 | if pte_flags & 1 == 0 { 236 | return Err(VirtMemError::PteNotPresent); 237 | } 238 | 239 | Ok(pte_paddr + page_offset(gva)) 240 | } 241 | -------------------------------------------------------------------------------- /src/sim.rs: -------------------------------------------------------------------------------- 1 | use std::collections::BTreeMap; 2 | use std::ffi::{CStr, c_void}; 3 | use std::os::raw::c_char; 4 | use std::ptr; 5 | use std::sync::OnceLock; 6 | 7 | use crate::NUM_CPUS; 8 | use crate::params::*; 9 | use crate::syncunsafecell::{SyncUnsafeCell, ptr_to_ref}; 10 | 11 | static PARAMS_ENUM: OnceLock>> = OnceLock::new(); 12 | static PARAMS_NUM: OnceLock>> = OnceLock::new(); 13 | static PARAMS_BOOL: OnceLock>> = OnceLock::new(); 14 | static PARAMS_STRING: OnceLock>> = 15 | OnceLock::new(); 16 | 17 | fn init_params_enum() -> SyncUnsafeCell> { 18 | let mut m = BTreeMap::new(); 19 | 20 | // from cpudb.h 21 | m.insert( 22 | "cpu.model", 23 | ParamEnum::new( 24 | c"model", 25 | &[ 26 | c"bx_generic", 27 | c"i486dx4", 28 | c"pentium", 29 | c"pentium_mxx", 30 | c"amd_k6_2_chomper", 31 | c"athlon_xp", 32 | c"p2_klamath", 33 | c"p3_katmai", 34 | c"p4_willamette", 35 | c"core_duo_t2500_yonah", 36 | c"atom_n270", 37 | c"p4_prescott_celeron_336", 38 | c"athlon64_clawhammer", 39 | c"athlon64_venice", 40 | c"turion64_tyler", 41 | c"phenom_8650_toliman", 42 | c"core2_penryn_t9600", 43 | c"corei5_lynnfield_750", 44 | c"corei5_arrandale_m520", 45 | c"corei7_sandy_bridge_2600k", 46 | c"zambezi", 47 | c"trinity_apu", 48 | c"ryzen", 49 | c"corei7_ivy_bridge_3770k", 50 | c"corei7_haswell_4770", 51 | c"broadwell_ult", 52 | c"corei7_skylake_x", 53 | c"corei3_cnl", 54 | c"corei7_icelake_u", 55 | c"tigerlake", 56 | c"sapphire_rapids", 57 | c"arrow_lake", 58 | ], 59 | 29, // default to tigerlake 60 | ), 61 | ); 62 | 63 | m.insert( 64 | "cpuid.apic", 65 | ParamEnum::new(c"apic", &[c"legacy", c"xapic", c"xapic_ext", c"x2apic"], 3), 66 | ); 67 | 68 | m.insert( 69 | "cpuid.simd", 70 | ParamEnum::new( 71 | c"simd", 72 | &[ 73 | c"none", c"sse", c"sse2", c"sse3", c"ssse3", c"sse4_1", c"sse4_2", c"avx", c"avx2", 74 | ], 75 | 8, 76 | ), 77 | ); 78 | 79 | SyncUnsafeCell::new(m) 80 | } 81 | 82 | fn init_params_num() -> SyncUnsafeCell> { 83 | let mut m = BTreeMap::new(); 84 | 85 | m.insert("cpu.n_threads", ParamNum::new(c"n_threads", 1, 4, 1)); 86 | m.insert("cpu.n_cores", ParamNum::new(c"n_cores", 1, 8, 1)); 87 | m.insert( 88 | "cpu.n_processors", 89 | ParamNum::new(c"n_processors", 1, NUM_CPUS as u64, 1), 90 | ); 91 | m.insert("cpu.quantum", ParamNum::new(c"quantum", 1, 32, 16)); 92 | 93 | m.insert("cpuid.level", ParamNum::new(c"level", 5, 6, 6)); 94 | m.insert("cpuid.vmx", ParamNum::new(c"vmx", 0, 2, 2)); 95 | m.insert("cpuid.bmi", ParamNum::new(c"bmi", 0, 2, 2)); 96 | 97 | // cannot find values for these vvv 98 | m.insert("cpuid.stepping", ParamNum::new(c"stepping", 0, 0, 0)); 99 | m.insert("cpuid.model", ParamNum::new(c"model", 0, 0, 0)); 100 | m.insert("cpuid.family", ParamNum::new(c"family", 0, 6, 6)); 101 | 102 | SyncUnsafeCell::new(m) 103 | } 104 | 105 | fn init_params_bool() -> SyncUnsafeCell> { 106 | let mut m = BTreeMap::new(); 107 | 108 | m.insert("cpuid.mmx", ParamBool::new(c"mmx", true)); 109 | m.insert("cpuid.sse4a", ParamBool::new(c"sse4a", true)); 110 | m.insert( 111 | "cpuid.misaligned_sse", 112 | ParamBool::new(c"misaligned_sse", true), 113 | ); 114 | m.insert("cpuid.sep", ParamBool::new(c"sep", true)); 115 | m.insert("cpuid.xsave", ParamBool::new(c"xsave", true)); 116 | m.insert("cpuid.xsaveopt", ParamBool::new(c"xsaveopt", true)); 117 | m.insert("cpuid.aes", ParamBool::new(c"aes", true)); 118 | m.insert("cpuid.sha", ParamBool::new(c"sha", true)); 119 | m.insert("cpuid.adx", ParamBool::new(c"adx", true)); 120 | m.insert("cpuid.x86_64", ParamBool::new(c"x86_64", true)); 121 | m.insert("cpuid.fsgsbase", ParamBool::new(c"fsgsbase", true)); 122 | m.insert("cpuid.pcid", ParamBool::new(c"pcid", true)); 123 | m.insert("cpuid.smep", ParamBool::new(c"smep", true)); 124 | m.insert("cpuid.smap", ParamBool::new(c"smap", true)); 125 | m.insert("cpuid.cet", ParamBool::new(c"cet", true)); 126 | 127 | 128 | m.insert("cpuid.mwait", ParamBool::new(c"mwait", false)); 129 | m.insert("cpuid.movbe", ParamBool::new(c"movbe", false)); 130 | m.insert("cpuid.1g_pages", ParamBool::new(c"1g_pages", false)); 131 | m.insert("cpuid.avx_f16c", ParamBool::new(c"avx_f16c", true)); 132 | m.insert("cpuid.avx_fma", ParamBool::new(c"avx_fma", true)); 133 | m.insert("cpuid.fma4", ParamBool::new(c"fma4", false)); 134 | m.insert("cpuid.xop", ParamBool::new(c"xop", false)); 135 | m.insert("cpuid.tbm", ParamBool::new(c"tbm", false)); 136 | 137 | m.insert( 138 | "cpu.cpuid_limit_winnt", 139 | ParamBool::new(c"cpuid_limit_winnt", false), 140 | ); 141 | m.insert( 142 | "cpu.ignore_bad_msrs", 143 | ParamBool::new(c"ignore_bad_msrs", false), 144 | ); 145 | // this needs to be set to false, because the reset path calls DEV_cmos_get_reg(0x0f), 146 | // which segfaults as I haven't implemented that stub yet... 147 | m.insert( 148 | "cpu.reset_on_triple_fault", 149 | ParamBool::new(c"reset_on_triple_fault", false), 150 | ); 151 | m.insert( 152 | "cpu.ignore_bad_msrs", 153 | ParamBool::new(c"ignore_base_msrs", true), 154 | ); 155 | 156 | SyncUnsafeCell::new(m) 157 | } 158 | 159 | fn init_params_string() -> SyncUnsafeCell> { 160 | let mut m = BTreeMap::new(); 161 | 162 | // this key just needs to exist, doesnt need to be a valid file name 163 | m.insert("cpu.msrs", ParamString::new(c"msrs", c"")); 164 | m.insert( 165 | "cpu.brand_string", 166 | ParamString::new(c"Intel(R) Core(TM) i7-7800X CPU @ 3.50GHz", c""), 167 | ); 168 | 169 | m.insert("cpu.add_features", ParamString::new(c"add_features", c"")); 170 | 171 | m.insert( 172 | "cpu.exclude_features", 173 | ParamString::new(c"exclude_features", c""), 174 | ); 175 | 176 | SyncUnsafeCell::new(m) 177 | } 178 | 179 | #[unsafe(no_mangle)] 180 | extern "C-unwind" fn sim_get_param_enum(p: *const c_char) -> *mut c_void { 181 | let s = unsafe { 182 | assert!(!p.is_null()); 183 | 184 | CStr::from_ptr(p).to_str().unwrap() 185 | }; 186 | 187 | trace!("looking up enum param for {}...", s); 188 | 189 | match unsafe { ptr_to_ref(PARAMS_ENUM.get_or_init(init_params_enum).0.get()) }.get(&s) { 190 | None => { 191 | warn!("no enum parameter: {}", s); 192 | ptr::null_mut::() 193 | } 194 | Some(v) => v.0, 195 | } 196 | } 197 | 198 | #[unsafe(no_mangle)] 199 | extern "C-unwind" fn sim_get_param_num(p: *const c_char) -> *mut c_void { 200 | let s = unsafe { 201 | assert!(!p.is_null()); 202 | 203 | CStr::from_ptr(p).to_str().unwrap() 204 | }; 205 | 206 | trace!("looking up num param for {}...", s); 207 | 208 | match unsafe { ptr_to_ref(PARAMS_NUM.get_or_init(init_params_num).0.get()) }.get(&s) { 209 | None => { 210 | warn!("no num parameter: {}", s); 211 | ptr::null_mut::() 212 | } 213 | Some(v) => v.0, 214 | } 215 | } 216 | 217 | #[unsafe(no_mangle)] 218 | extern "C-unwind" fn sim_get_param_bool(p: *const c_char) -> *mut c_void { 219 | let s = unsafe { 220 | assert!(!p.is_null()); 221 | 222 | CStr::from_ptr(p).to_str().unwrap() 223 | }; 224 | 225 | trace!("looking up bool param for {}...", s); 226 | 227 | match unsafe { ptr_to_ref(PARAMS_BOOL.get_or_init(init_params_bool).0.get()) }.get(&s) { 228 | None => { 229 | warn!("no bool parameter: {}", s); 230 | ptr::null_mut::() 231 | } 232 | Some(v) => v.0, 233 | } 234 | } 235 | 236 | #[unsafe(no_mangle)] 237 | extern "C-unwind" fn sim_get_param_string(p: *const c_char) -> *mut c_void { 238 | let s = unsafe { 239 | assert!(!p.is_null()); 240 | 241 | CStr::from_ptr(p).to_str().unwrap() 242 | }; 243 | 244 | trace!("looking up string param for {}...", s); 245 | 246 | match unsafe { ptr_to_ref(PARAMS_STRING.get_or_init(init_params_string).0.get()) }.get(&s) { 247 | None => { 248 | warn!("no string parameter: {}", s); 249 | ptr::null_mut::() 250 | } 251 | Some(v) => v.0, 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /cabi/cpu-cabi.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "bochs.h" 5 | #include "cpu/cpu.h" 6 | #include "cpu/apic.h" 7 | #include "pc_system.h" 8 | 9 | typedef BX_CPU_C *BX_CPU_C_PTR; 10 | 11 | 12 | extern "C" { 13 | BOCHSAPI void cpu_loop(unsigned id) { 14 | BX_CPU(id)->cpu_loop(); 15 | } 16 | 17 | BOCHSAPI void cpu_new(unsigned id) { 18 | #if BX_SUPPORT_SMP 19 | // bochs assumes that all things are init'd to zero, which breaks ASan so 20 | // we use placement new to zero the mem 21 | void *zero = malloc(sizeof(BX_CPU_C)); 22 | memset(zero, 0, sizeof(BX_CPU_C)); 23 | 24 | BX_CPU_C *c = new (zero) BX_CPU_C(id); 25 | 26 | BX_CPU(id) = c; 27 | #endif 28 | 29 | BX_CPU(id)->initialize(); 30 | BX_CPU(id)->reset(BX_RESET_HARDWARE); 31 | BX_CPU(id)->sanity_checks(); 32 | 33 | BX_INSTR_INITIALIZE(id); 34 | } 35 | 36 | BOCHSAPI void cpu_delete(unsigned id) { 37 | #if BX_SUPPORT_SMP 38 | 39 | BX_CPU(id)->~BX_CPU_C(); 40 | free(BX_CPU(id)); 41 | 42 | BX_CPU(id) = NULL; 43 | #endif 44 | } 45 | 46 | BOCHSAPI void cpu_bail(unsigned id) { 47 | BX_CPU_C *c = BX_CPU(id); 48 | 49 | longjmp(c->jmp_buf_env, 1); 50 | } 51 | 52 | BOCHSAPI void cpu_set_mode(unsigned id) { 53 | BX_CPU_C *c = BX_CPU(id); 54 | 55 | c->TLB_flush(); 56 | 57 | #if BX_CPU_LEVEL >= 4 58 | c->handleAlignmentCheck(/* CR0.AC reloaded */); 59 | #endif 60 | 61 | c->handleCpuModeChange(); 62 | 63 | #if BX_CPU_LEVEL >= 6 64 | c->handleSseModeChange(); 65 | #endif 66 | } 67 | 68 | // general purpose regs 69 | 70 | BOCHSAPI bx_address cpu_get_pc(unsigned id) { 71 | return BX_CPU(id)->get_instruction_pointer(); 72 | } 73 | 74 | BOCHSAPI void cpu_set_pc(unsigned id, Bit64u val) { 75 | BX_CPU(id)->gen_reg[BX_64BIT_REG_RIP].rrx = val; 76 | BX_CPU(id)->prev_rip = val; 77 | } 78 | 79 | BOCHSAPI void cpu_set_sp(unsigned id, Bit64u val) { 80 | BX_CPU(id)->gen_reg[BX_64BIT_REG_RSP].rrx = val; 81 | BX_CPU(id)->prev_rsp = val; 82 | } 83 | 84 | BOCHSAPI Bit64u cpu_get_ssp(unsigned id) { 85 | return BX_CPU(id)->get_ssp(); 86 | } 87 | 88 | BOCHSAPI void cpu_set_ssp(unsigned id, Bit64u val) { 89 | BX_CPU(id)->gen_reg[BX_64BIT_REG_SSP].rrx = val; 90 | } 91 | 92 | BOCHSAPI Bit64u cpu_get_reg64(unsigned id, unsigned reg) { 93 | return BX_CPU(id)->get_reg64(reg); 94 | } 95 | 96 | BOCHSAPI void cpu_set_reg64(unsigned id, unsigned reg, Bit64u val) { 97 | BX_CPU(id)->set_reg64(reg, val); 98 | } 99 | 100 | BOCHSAPI Bit32u cpu_get_eflags(unsigned id) { 101 | return BX_CPU(id)->eflags; 102 | } 103 | 104 | BOCHSAPI void cpu_set_eflags(unsigned id, Bit32u eflags) { 105 | BX_CPU(id)->setEFlags(eflags); 106 | } 107 | 108 | void get_seg( 109 | unsigned id, 110 | bx_segment_reg_t *seg, 111 | Bit32u *present, 112 | Bit16u *selector, 113 | bx_address *base, 114 | Bit32u *limit, 115 | Bit16u *attr) 116 | { 117 | *present = seg->cache.valid; 118 | *base = seg->cache.u.segment.base; 119 | *limit = seg->cache.u.segment.limit_scaled; 120 | *selector = seg->selector.value; 121 | *attr = (BX_CPU(id)->get_descriptor_h(&seg->cache) >> 8) & 0xffff; 122 | } 123 | 124 | void set_seg( 125 | unsigned id, 126 | bx_segment_reg_t *seg, 127 | Bit32u present, 128 | Bit16u selector, 129 | bx_address base, 130 | Bit32u limit, 131 | Bit16u attr) 132 | { 133 | BX_CPU(id)->set_segment_ar_data( 134 | seg, 135 | present, 136 | selector, 137 | base, 138 | limit, 139 | attr 140 | ); 141 | } 142 | 143 | BOCHSAPI void cpu_get_seg( 144 | unsigned id, 145 | unsigned sreg, 146 | Bit32u *present, 147 | Bit16u *selector, 148 | bx_address *base, 149 | Bit32u *limit, 150 | Bit16u *attr) 151 | { 152 | return get_seg(id, &BX_CPU(id)->sregs[sreg], present, selector, base, limit, attr); 153 | } 154 | 155 | BOCHSAPI void cpu_set_seg( 156 | unsigned id, 157 | unsigned sreg, 158 | Bit32u present, 159 | Bit16u selector, 160 | bx_address base, 161 | Bit32u limit, 162 | Bit16u attr) 163 | { 164 | return set_seg(id, &BX_CPU(id)->sregs[sreg], present, selector, base, limit, attr); 165 | } 166 | 167 | BOCHSAPI void cpu_get_ldtr( 168 | unsigned id, 169 | Bit32u *present, 170 | Bit16u *selector, 171 | bx_address *base, 172 | Bit32u *limit, 173 | Bit16u *attr) 174 | { 175 | return get_seg(id, &BX_CPU(id)->ldtr, present, selector, base, limit, attr); 176 | } 177 | 178 | BOCHSAPI void cpu_set_ldtr( 179 | unsigned id, 180 | Bit32u present, 181 | Bit16u selector, 182 | bx_address base, 183 | Bit32u limit, 184 | Bit16u attr) 185 | { 186 | return set_seg(id, &BX_CPU(id)->ldtr, present, selector, base, limit, attr); 187 | } 188 | 189 | BOCHSAPI void cpu_get_tr( 190 | unsigned id, 191 | Bit32u *present, 192 | Bit16u *selector, 193 | bx_address *base, 194 | Bit32u *limit, 195 | Bit16u *attr) 196 | { 197 | return get_seg(id, &BX_CPU(id)->tr, present, selector, base, limit, attr); 198 | } 199 | 200 | BOCHSAPI void cpu_set_tr( 201 | unsigned id, 202 | Bit32u present, 203 | Bit16u selector, 204 | bx_address base, 205 | Bit32u limit, 206 | Bit16u attr) 207 | { 208 | return set_seg(id, &BX_CPU(id)->tr, present, selector, base, limit, attr); 209 | } 210 | 211 | BOCHSAPI void cpu_get_gdtr(unsigned id, bx_address *base, Bit16u *limit) { 212 | *base= BX_CPU(id)->gdtr.base; 213 | *limit = BX_CPU(id)->gdtr.limit; 214 | } 215 | 216 | BOCHSAPI void cpu_set_gdtr(unsigned id, bx_address base, Bit16u limit) { 217 | BX_CPU(id)->gdtr.base = base; 218 | BX_CPU(id)->gdtr.limit = limit; 219 | } 220 | 221 | BOCHSAPI void cpu_get_idtr(unsigned id, bx_address *base, Bit16u *limit) { 222 | *base= BX_CPU(id)->idtr.base; 223 | *limit = BX_CPU(id)->idtr.limit; 224 | } 225 | 226 | BOCHSAPI void cpu_set_idtr(unsigned id, bx_address base, Bit16u limit) { 227 | BX_CPU(id)->idtr.base = base; 228 | BX_CPU(id)->idtr.limit = limit; 229 | } 230 | 231 | // debug registers 232 | 233 | BOCHSAPI bx_address cpu_get_dr(unsigned id, unsigned dr) { 234 | return BX_CPU(id)->dr[dr]; 235 | } 236 | 237 | BOCHSAPI void cpu_set_dr(unsigned id, unsigned dr, bx_address v) { 238 | BX_CPU(id)->dr[dr] = v; 239 | } 240 | 241 | BOCHSAPI Bit32u cpu_get_dr6(unsigned id) { 242 | return BX_CPU(id)->dr6.get32(); 243 | } 244 | 245 | BOCHSAPI void cpu_set_dr6(unsigned id, Bit32u v) { 246 | BX_CPU(id)->dr6.set32(v); 247 | } 248 | 249 | BOCHSAPI Bit32u cpu_get_dr7(unsigned id) { 250 | return BX_CPU(id)->dr7.get32(); 251 | } 252 | 253 | BOCHSAPI void cpu_set_dr7(unsigned id, Bit32u v) { 254 | BX_CPU(id)->dr7.set32(v); 255 | } 256 | 257 | // control registers 258 | 259 | BOCHSAPI Bit32u cpu_get_cr0(unsigned id) { 260 | return BX_CPU(id)->cr0.get32(); 261 | } 262 | 263 | BOCHSAPI void cpu_set_cr0(unsigned id, Bit32u v) { 264 | BX_CPU(id)->cr0.set32(v); 265 | } 266 | 267 | BOCHSAPI bx_address cpu_get_cr2(unsigned id) { 268 | return BX_CPU(id)->cr2; 269 | } 270 | 271 | BOCHSAPI void cpu_set_cr2(unsigned id, bx_address v) { 272 | BX_CPU(id)->cr2 = v; 273 | } 274 | 275 | BOCHSAPI bx_address cpu_get_cr3(unsigned id) { 276 | return BX_CPU(id)->cr3; 277 | } 278 | 279 | BOCHSAPI void cpu_set_cr3(unsigned id, bx_address v) { 280 | BX_CPU(id)->cr3 = v; 281 | } 282 | 283 | BOCHSAPI Bit32u cpu_get_cr4(unsigned id) { 284 | return BX_CPU(id)->cr4.get32(); 285 | } 286 | 287 | BOCHSAPI void cpu_set_cr4(unsigned id, Bit32u v) { 288 | BX_CPU(id)->cr4.set32(v); 289 | } 290 | 291 | BOCHSAPI Bit32u cpu_get_cr8(unsigned id) { 292 | return BX_CPU(id)->get_cr8(); 293 | } 294 | 295 | BOCHSAPI void cpu_set_cr8(unsigned id, Bit32u v) { 296 | #if BX_SUPPORT_APIC 297 | BX_CPU(id)->lapic->set_tpr((v & 0xf) << 4); 298 | #endif 299 | } 300 | 301 | BOCHSAPI Bit32u cpu_get_efer(unsigned id) { 302 | return BX_CPU(id)->efer.get32(); 303 | } 304 | 305 | BOCHSAPI void cpu_set_efer(unsigned id, Bit32u v) { 306 | BX_CPU(id)->efer.set32(v); 307 | } 308 | 309 | BOCHSAPI Bit32u cpu_get_xcr0(unsigned id) { 310 | return BX_CPU(id)->xcr0.get32(); 311 | } 312 | 313 | BOCHSAPI void cpu_set_xcr0(unsigned id, Bit32u v) { 314 | BX_CPU(id)->xcr0.set32(v); 315 | } 316 | 317 | // model specific registers 318 | 319 | BOCHSAPI Bit64u cpu_get_kernel_gs_base(unsigned id) { 320 | return BX_CPU(id)->msr.kernelgsbase; 321 | } 322 | 323 | BOCHSAPI void cpu_set_kernel_gs_base(unsigned id, Bit64u v) { 324 | BX_CPU(id)->msr.kernelgsbase = v; 325 | } 326 | 327 | BOCHSAPI Bit32u cpu_get_sysenter_cs(unsigned id) { 328 | return BX_CPU(id)->msr.sysenter_cs_msr; 329 | } 330 | 331 | BOCHSAPI void cpu_set_sysenter_cs(unsigned id, Bit32u v) { 332 | BX_CPU(id)->msr.sysenter_cs_msr = v; 333 | } 334 | 335 | BOCHSAPI bx_address cpu_get_sysenter_esp(unsigned id) { 336 | return BX_CPU(id)->msr.sysenter_esp_msr; 337 | } 338 | 339 | BOCHSAPI void cpu_set_sysenter_esp(unsigned id, bx_address v) { 340 | BX_CPU(id)->msr.sysenter_esp_msr = v; 341 | } 342 | 343 | BOCHSAPI bx_address cpu_get_sysenter_eip(unsigned id) { 344 | return BX_CPU(id)->msr.sysenter_eip_msr; 345 | } 346 | 347 | BOCHSAPI void cpu_set_sysenter_eip(unsigned id, bx_address v) { 348 | BX_CPU(id)->msr.sysenter_eip_msr = v; 349 | } 350 | 351 | BOCHSAPI Bit64u cpu_get_star(unsigned id) { 352 | return BX_CPU(id)->msr.star; 353 | } 354 | 355 | BOCHSAPI void cpu_set_star(unsigned id, Bit64u v) { 356 | BX_CPU(id)->msr.star = v; 357 | } 358 | 359 | BOCHSAPI Bit64u cpu_get_lstar(unsigned id) { 360 | return BX_CPU(id)->msr.lstar; 361 | } 362 | 363 | BOCHSAPI void cpu_set_lstar(unsigned id, Bit64u v) { 364 | BX_CPU(id)->msr.lstar = v; 365 | } 366 | 367 | BOCHSAPI Bit64u cpu_get_cstar(unsigned id) { 368 | return BX_CPU(id)->msr.cstar; 369 | } 370 | 371 | BOCHSAPI void cpu_set_cstar(unsigned id, Bit64u v) { 372 | BX_CPU(id)->msr.cstar = v; 373 | } 374 | 375 | BOCHSAPI Bit32u cpu_get_fmask(unsigned id) { 376 | return BX_CPU(id)->msr.fmask; 377 | } 378 | 379 | BOCHSAPI void cpu_set_fmask(unsigned id, Bit32u v) { 380 | BX_CPU(id)->msr.fmask = v; 381 | } 382 | 383 | BOCHSAPI Bit64u cpu_get_tsc(unsigned id) { 384 | return BX_CPU(id)->get_TSC(); 385 | } 386 | 387 | BOCHSAPI void cpu_set_tsc(unsigned id, Bit64u v) { 388 | BX_CPU(id)->set_TSC(v); 389 | } 390 | 391 | BOCHSAPI Bit64u cpu_get_tsc_aux(unsigned id) { 392 | return BX_CPU(id)->msr.tsc_aux; 393 | } 394 | 395 | BOCHSAPI void cpu_set_tsc_aux(unsigned id, Bit32u v) { 396 | BX_CPU(id)->msr.tsc_aux = v; 397 | } 398 | 399 | BOCHSAPI bx_phy_address cpu_get_apicbase(unsigned id) { 400 | return BX_CPU(id)->msr.apicbase; 401 | } 402 | 403 | BOCHSAPI void cpu_set_apicbase(unsigned id, bx_phy_address v) { 404 | BX_CPU(id)->msr.apicbase = v; 405 | } 406 | 407 | BOCHSAPI Bit64u cpu_get_pat(unsigned id) { 408 | return BX_CPU(id)->msr.pat._u64; 409 | } 410 | 411 | BOCHSAPI void cpu_set_pat(unsigned id, Bit64u v) { 412 | BX_CPU(id)->msr.pat._u64 = v; 413 | } 414 | 415 | BOCHSAPI Bit64u cpu_get_cet_control_u(unsigned id) { 416 | return BX_CPU(id)->msr.ia32_cet_control[1]; 417 | } 418 | 419 | BOCHSAPI void cpu_set_cet_control_u(unsigned id, Bit64u v) { 420 | BX_CPU(id)->msr.ia32_cet_control[1] = v; 421 | } 422 | 423 | BOCHSAPI Bit64u cpu_get_cet_control_s(unsigned id) { 424 | return BX_CPU(id)->msr.ia32_cet_control[0]; 425 | } 426 | 427 | BOCHSAPI void cpu_set_cet_control_s(unsigned id, Bit64u v) { 428 | BX_CPU(id)->msr.ia32_cet_control[0] = v; 429 | } 430 | 431 | BOCHSAPI Bit64u cpu_get_pl0_ssp(unsigned id) { 432 | return BX_CPU(id)->msr.ia32_pl_ssp[0]; 433 | } 434 | 435 | BOCHSAPI void cpu_set_pl0_ssp(unsigned id, Bit64u v) { 436 | BX_CPU(id)->msr.ia32_pl_ssp[0] = v; 437 | } 438 | 439 | BOCHSAPI Bit64u cpu_get_pl1_ssp(unsigned id) { 440 | return BX_CPU(id)->msr.ia32_pl_ssp[1]; 441 | } 442 | 443 | BOCHSAPI void cpu_set_pl1_ssp(unsigned id, Bit64u v) { 444 | BX_CPU(id)->msr.ia32_pl_ssp[1] = v; 445 | } 446 | 447 | BOCHSAPI Bit64u cpu_get_pl2_ssp(unsigned id) { 448 | return BX_CPU(id)->msr.ia32_pl_ssp[2]; 449 | } 450 | 451 | BOCHSAPI void cpu_set_pl2_ssp(unsigned id, Bit64u v) { 452 | BX_CPU(id)->msr.ia32_pl_ssp[2] = v; 453 | } 454 | 455 | BOCHSAPI Bit64u cpu_get_pl3_ssp(unsigned id) { 456 | return BX_CPU(id)->msr.ia32_pl_ssp[3]; 457 | } 458 | 459 | BOCHSAPI void cpu_set_pl3_ssp(unsigned id, Bit64u v) { 460 | BX_CPU(id)->msr.ia32_pl_ssp[3] = v; 461 | } 462 | 463 | BOCHSAPI Bit64u cpu_get_interrupt_ssp_table(unsigned id) { 464 | return BX_CPU(id)->msr.ia32_interrupt_ssp_table; 465 | } 466 | 467 | BOCHSAPI void cpu_set_interrupt_ssp_table(unsigned id, Bit64u v) { 468 | BX_CPU(id)->msr.ia32_interrupt_ssp_table = v; 469 | } 470 | 471 | // ZMM 472 | 473 | BOCHSAPI void cpu_get_zmm(unsigned id, unsigned reg, Bit64u z[]) { 474 | #if BX_SUPPORT_EVEX 475 | z[0] = BX_CPU(id)->vmm[reg].zmm_u64[0]; 476 | z[1] = BX_CPU(id)->vmm[reg].zmm_u64[1]; 477 | z[2] = BX_CPU(id)->vmm[reg].zmm_u64[2]; 478 | z[3] = BX_CPU(id)->vmm[reg].zmm_u64[3]; 479 | z[4] = BX_CPU(id)->vmm[reg].zmm_u64[4]; 480 | z[5] = BX_CPU(id)->vmm[reg].zmm_u64[5]; 481 | z[6] = BX_CPU(id)->vmm[reg].zmm_u64[6]; 482 | z[7] = BX_CPU(id)->vmm[reg].zmm_u64[7]; 483 | #elif BX_SUPPORT_AVX 484 | z[0] = BX_CPU(id)->vmm[reg].ymm_u64[0]; 485 | z[1] = BX_CPU(id)->vmm[reg].ymm_u64[1]; 486 | z[2] = BX_CPU(id)->vmm[reg].ymm_u64[2]; 487 | z[3] = BX_CPU(id)->vmm[reg].ymm_u64[3]; 488 | z[4] = 0; 489 | z[5] = 0; 490 | z[6] = 0; 491 | z[7] = 0; 492 | #else 493 | z[0] = BX_CPU(id)->vmm[reg].xmm_u64[0]; 494 | z[1] = BX_CPU(id)->vmm[reg].xmm_u64[1]; 495 | z[2] = 0; 496 | z[3] = 0; 497 | z[4] = 0; 498 | z[5] = 0; 499 | z[6] = 0; 500 | z[7] = 0; 501 | #endif 502 | } 503 | 504 | BOCHSAPI void cpu_set_zmm(unsigned id, unsigned reg, Bit64u z[]) { 505 | #if BX_SUPPORT_EVEX 506 | BX_CPU(id)->vmm[reg].zmm_u64[0] = z[0]; 507 | BX_CPU(id)->vmm[reg].zmm_u64[1] = z[1]; 508 | BX_CPU(id)->vmm[reg].zmm_u64[2] = z[2]; 509 | BX_CPU(id)->vmm[reg].zmm_u64[3] = z[3]; 510 | BX_CPU(id)->vmm[reg].zmm_u64[4] = z[4]; 511 | BX_CPU(id)->vmm[reg].zmm_u64[5] = z[5]; 512 | BX_CPU(id)->vmm[reg].zmm_u64[6] = z[6]; 513 | BX_CPU(id)->vmm[reg].zmm_u64[7] = z[7]; 514 | #elif BX_SUPPORT_AVX 515 | BX_CPU(id)->vmm[reg].ymm_u64[0] = z[0]; 516 | BX_CPU(id)->vmm[reg].ymm_u64[1] = z[1]; 517 | BX_CPU(id)->vmm[reg].ymm_u64[2] = z[2]; 518 | BX_CPU(id)->vmm[reg].ymm_u64[3] = z[3]; 519 | #else 520 | BX_CPU(id)->vmm[reg].xmm_u64[0] = z[0]; 521 | BX_CPU(id)->vmm[reg].xmm_u64[1] = z[1]; 522 | #endif 523 | } 524 | 525 | // FP registers 526 | 527 | BOCHSAPI Bit16u cpu_get_fp_cw(unsigned id) { 528 | return BX_CPU(id)->the_i387.cwd; 529 | } 530 | 531 | BOCHSAPI void cpu_set_fp_cw(unsigned id, Bit16u v) { 532 | BX_CPU(id)->the_i387.cwd = v; 533 | } 534 | 535 | BOCHSAPI Bit16u cpu_get_fp_sw(unsigned id) { 536 | return BX_CPU(id)->the_i387.swd; 537 | } 538 | 539 | BOCHSAPI void cpu_set_fp_sw(unsigned id, Bit16u v) { 540 | BX_CPU(id)->the_i387.swd = v; 541 | } 542 | 543 | BOCHSAPI Bit16u cpu_get_fp_tw(unsigned id) { 544 | return BX_CPU(id)->the_i387.twd; 545 | } 546 | 547 | BOCHSAPI void cpu_set_fp_tw(unsigned id, Bit16u v) { 548 | BX_CPU(id)->the_i387.twd = v; 549 | } 550 | 551 | BOCHSAPI Bit16u cpu_get_fp_op(unsigned id) { 552 | return BX_CPU(id)->the_i387.foo; 553 | } 554 | 555 | BOCHSAPI void cpu_set_fp_op(unsigned id, Bit16u v) { 556 | BX_CPU(id)->the_i387.foo = v; 557 | } 558 | 559 | BOCHSAPI void cpu_get_fp_st(unsigned id, unsigned reg, Bit64u *fraction, Bit16u *exp) { 560 | const floatx80 f = BX_CPU(id)->the_i387.st_space[reg]; 561 | *fraction = f.signif; 562 | *exp = f.signExp; 563 | } 564 | 565 | BOCHSAPI void cpu_set_fp_st(unsigned id, unsigned reg, const Bit64u fraction, const Bit16u exp) { 566 | floatx80 f; 567 | f.signif = fraction; 568 | f.signExp = exp; 569 | BX_CPU(id)->the_i387.st_space[reg] = f; 570 | } 571 | 572 | BOCHSAPI Bit32u cpu_get_mxcsr(unsigned id) { 573 | return BX_CPU(id)->mxcsr.mxcsr; 574 | } 575 | 576 | BOCHSAPI void cpu_set_mxcsr(unsigned id, Bit32u v) { 577 | BX_CPU(id)->mxcsr.mxcsr = v; 578 | } 579 | 580 | BOCHSAPI Bit32u cpu_get_mxcsr_mask(unsigned id) { 581 | return BX_CPU(id)->mxcsr_mask; 582 | } 583 | 584 | BOCHSAPI void cpu_set_mxcsr_mask(unsigned id, Bit32u v) { 585 | BX_CPU(id)->mxcsr_mask = v; 586 | } 587 | 588 | BOCHSAPI unsigned cpu_killbit(unsigned id) { 589 | return bx_pc_system.kill_bochs_request; 590 | } 591 | 592 | BOCHSAPI void cpu_set_killbit(unsigned id) { 593 | BX_CPU(id)->async_event = 1; 594 | bx_pc_system.kill_bochs_request = 1; 595 | } 596 | 597 | BOCHSAPI void cpu_clear_killbit(unsigned id) { 598 | BX_CPU(id)->async_event = 0; 599 | bx_pc_system.kill_bochs_request = 0; 600 | } 601 | 602 | BOCHSAPI void cpu_exception(unsigned id, unsigned vector, Bit16u error) { 603 | BX_CPU(id)->exception(vector, error); 604 | } 605 | } 606 | 607 | Bit8u bx_cpu_count = 0xff; // max number of processsors 608 | 609 | #if BX_SUPPORT_SMP 610 | BOCHSAPI BX_CPU_C_PTR *bx_cpu_array = new BX_CPU_C_PTR[BX_SMP_PROCESSORS]; 611 | #else 612 | BOCHSAPI BX_CPU_C bx_cpu = BX_CPU_C(0); 613 | #endif 614 | -------------------------------------------------------------------------------- /src/hook.rs: -------------------------------------------------------------------------------- 1 | use std::ffi::c_void; 2 | use std::hint::unreachable_unchecked; 3 | use std::mem; 4 | use std::slice; 5 | 6 | use crate::NUM_CPUS; 7 | use crate::cpu::{cpu_bail, cpu_exception}; 8 | use crate::syncunsafecell::{SyncUnsafeCell, ptr_to_ref_mut}; 9 | use crate::{Address, PhyAddress}; 10 | 11 | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] 12 | pub(crate) enum HookEvent { 13 | Stop, 14 | SetPc, 15 | Exception(u32, Option), 16 | } 17 | 18 | #[ctor] 19 | static HOOK_EVENTS: SyncUnsafeCell>> = 20 | unsafe { SyncUnsafeCell::new(vec![None; NUM_CPUS]) }; 21 | 22 | pub(crate) unsafe fn hook_event(id: u32) -> &'static mut Option { 23 | unsafe { &mut ptr_to_ref_mut(HOOK_EVENTS.0.get())[id as usize] } 24 | } 25 | 26 | pub(crate) unsafe fn set_hook_event(id: u32, he: Option) { 27 | unsafe { 28 | *hook_event(id) = he; 29 | } 30 | } 31 | 32 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] 33 | #[repr(u32)] 34 | pub enum ResetSource { 35 | Software = 10, 36 | Hardware = 11, 37 | } 38 | 39 | impl From for ResetSource { 40 | fn from(i: u32) -> Self { 41 | match i { 42 | 10 => ResetSource::Software, 43 | 11 => ResetSource::Hardware, 44 | _ => unsafe { unreachable_unchecked() }, 45 | } 46 | } 47 | } 48 | 49 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] 50 | #[repr(u32)] 51 | pub enum Branch { 52 | Jmp = 10, 53 | JmpIndirect = 11, 54 | Call = 12, 55 | CallIndirect = 13, 56 | Ret = 14, 57 | Iret = 15, 58 | Int = 16, 59 | Syscall = 17, 60 | Sysret = 18, 61 | Sysenter = 19, 62 | Sysexit = 20, 63 | } 64 | 65 | impl From for Branch { 66 | fn from(i: u32) -> Self { 67 | match i { 68 | 10 => Branch::Jmp, 69 | 11 => Branch::JmpIndirect, 70 | 12 => Branch::Call, 71 | 13 => Branch::CallIndirect, 72 | 14 => Branch::Ret, 73 | 15 => Branch::Iret, 74 | 16 => Branch::Int, 75 | 17 => Branch::Syscall, 76 | 18 => Branch::Sysret, 77 | 19 => Branch::Sysenter, 78 | 20 => Branch::Sysexit, 79 | _ => unsafe { unreachable_unchecked() }, 80 | } 81 | } 82 | } 83 | 84 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] 85 | #[repr(u32)] 86 | pub enum TlbCntrl { 87 | MovCr0 = 10, 88 | MovCr3 = 11, 89 | MovCr4 = 12, 90 | TaskSwitch = 13, 91 | ContextSwitch = 14, 92 | InvLpg = 15, 93 | InvEpt = 16, 94 | InvVpid = 17, 95 | InvPcid = 18, 96 | } 97 | 98 | impl From for TlbCntrl { 99 | fn from(i: u32) -> Self { 100 | match i { 101 | 10 => TlbCntrl::MovCr0, 102 | 11 => TlbCntrl::MovCr3, 103 | 12 => TlbCntrl::MovCr4, 104 | 13 => TlbCntrl::TaskSwitch, 105 | 14 => TlbCntrl::ContextSwitch, 106 | 15 => TlbCntrl::InvLpg, 107 | 16 => TlbCntrl::InvEpt, 108 | 17 => TlbCntrl::InvVpid, 109 | 18 => TlbCntrl::InvPcid, 110 | _ => unsafe { unreachable_unchecked() }, 111 | } 112 | } 113 | } 114 | 115 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] 116 | #[repr(u32)] 117 | pub enum CacheCntrl { 118 | Invd = 10, 119 | Wbind = 11, 120 | } 121 | 122 | impl From for CacheCntrl { 123 | fn from(i: u32) -> Self { 124 | match i { 125 | 10 => CacheCntrl::Invd, 126 | 11 => CacheCntrl::Wbind, 127 | _ => unsafe { unreachable_unchecked() }, 128 | } 129 | } 130 | } 131 | 132 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] 133 | #[repr(u32)] 134 | pub enum PrefetchHint { 135 | Nta = 0, 136 | T0 = 1, 137 | T1 = 2, 138 | T2 = 3, 139 | } 140 | 141 | impl From for PrefetchHint { 142 | fn from(i: u32) -> Self { 143 | match i { 144 | 0 => PrefetchHint::Nta, 145 | 1 => PrefetchHint::T0, 146 | 2 => PrefetchHint::T1, 147 | 3 => PrefetchHint::T2, 148 | _ => unsafe { unreachable_unchecked() }, 149 | } 150 | } 151 | } 152 | 153 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] 154 | #[repr(u32)] 155 | pub enum MemAccess { 156 | Read = 0, 157 | Write = 1, 158 | Execute = 2, 159 | RW = 3, 160 | } 161 | 162 | impl From for MemAccess { 163 | fn from(i: u32) -> Self { 164 | match i { 165 | 0 => MemAccess::Read, 166 | 1 => MemAccess::Write, 167 | 2 => MemAccess::Execute, 168 | 3 => MemAccess::RW, 169 | _ => unsafe { unreachable_unchecked() }, 170 | } 171 | } 172 | } 173 | 174 | #[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] 175 | #[repr(u32)] 176 | pub enum MemType { 177 | Uc = 0, 178 | Wc = 1, 179 | Reserved2 = 2, 180 | Reserved3 = 3, 181 | Wt = 4, 182 | Wp = 5, 183 | Wb = 6, 184 | UcWeak = 7, 185 | Invalid = 8, 186 | } 187 | 188 | impl From for MemType { 189 | fn from(i: u32) -> Self { 190 | match i { 191 | 0 => MemType::Uc, 192 | 1 => MemType::Wc, 193 | 2 => MemType::Reserved2, 194 | 3 => MemType::Reserved3, 195 | 4 => MemType::Wt, 196 | 5 => MemType::Wp, 197 | 6 => MemType::Wb, 198 | 7 => MemType::UcWeak, 199 | 8 => MemType::Invalid, 200 | _ => unsafe { unreachable_unchecked() }, 201 | } 202 | } 203 | } 204 | 205 | pub trait Hooks { 206 | fn reset(&mut self, _id: u32, _ty: ResetSource) {} 207 | fn hlt(&mut self, _id: u32) {} 208 | fn mwait(&mut self, _id: u32, _addr: PhyAddress, _len: usize, _flags: u32) {} 209 | 210 | fn cnear_branch_taken(&mut self, _id: u32, _branch_pc: Address, _new_pc: Address) {} 211 | fn cnear_branch_not_taken(&mut self, _id: u32, _pc: Address, _new_pc: Address) {} 212 | fn ucnear_branch(&mut self, _id: u32, _what: Branch, _branch_pc: Address, _new_pc: Address) {} 213 | fn far_branch( 214 | &mut self, 215 | _id: u32, 216 | _what: Branch, 217 | _branch_pc: (u16, Address), 218 | _new_pc: (u16, Address), 219 | ) { 220 | } 221 | 222 | fn opcode( 223 | &mut self, 224 | _id: u32, 225 | _ins: *const c_void, 226 | _opcode: &[u8], 227 | _is_32: bool, 228 | _is_64: bool, 229 | ) { 230 | } 231 | fn interrupt(&mut self, _id: u32, _vector: u32) {} 232 | fn exception(&mut self, _id: u32, _vector: u32, _error_code: u32) {} 233 | fn hw_interrupt(&mut self, _id: u32, _vector: u32, _pc: (u16, Address)) {} 234 | 235 | fn tlb_cntrl(&mut self, _id: u32, _what: TlbCntrl, _new_cr: Option) {} 236 | fn cache_cntrl(&mut self, _id: u32, _what: CacheCntrl) {} 237 | fn prefetch_hint(&mut self, _id: u32, _what: PrefetchHint, _seg: u32, _off: Address) {} 238 | fn clflush(&mut self, _id: u32, _vaddr: Address, _paddr: PhyAddress) {} 239 | 240 | fn before_execution(&mut self, _id: u32, _ins: *mut c_void) {} 241 | fn after_execution(&mut self, _id: u32, _ins: *mut c_void) {} 242 | fn repeat_iteration(&mut self, _id: u32, _ins: *mut c_void) {} 243 | 244 | fn inp(&mut self, _addr: u16, _len: usize) {} 245 | fn inp2(&mut self, _addr: u16, _len: usize, _val: u32) {} 246 | fn outp(&mut self, _addr: u16, _len: usize, _val: u32) {} 247 | 248 | fn lin_access( 249 | &mut self, 250 | _id: u32, 251 | _vaddr: Address, 252 | _paddr: Address, 253 | _len: usize, 254 | _memty: MemType, 255 | _rw: MemAccess, 256 | ) { 257 | } 258 | fn phy_access( 259 | &mut self, 260 | _id: u32, 261 | _paddr: PhyAddress, 262 | _len: usize, 263 | _memty: MemType, 264 | _rw: MemAccess, 265 | ) { 266 | } 267 | 268 | fn cpuid(&mut self, _id: u32) {} 269 | 270 | fn wrmsr(&mut self, _id: u32, _msr: u32, _val: u64) {} 271 | 272 | fn vmexit(&mut self, _id: u32, _reason: u32, _qualification: u64) {} 273 | } 274 | 275 | static HOOKS: SyncUnsafeCell> = SyncUnsafeCell::new(Vec::new()); 276 | 277 | unsafe fn hooks() -> &'static mut Vec<&'static mut dyn Hooks> { 278 | unsafe { ptr_to_ref_mut(HOOKS.0.get()) } 279 | } 280 | 281 | pub(crate) unsafe fn register<'a>(h: &'a mut dyn Hooks) { 282 | unsafe { 283 | // we need to extend the lifetime of this hook object to 'static so we can insert it 284 | let hook = mem::transmute::<&'a mut dyn Hooks, &'static mut dyn Hooks>(h); 285 | hooks().push(hook); 286 | } 287 | } 288 | 289 | pub(crate) unsafe fn clear() { 290 | unsafe { 291 | hooks().clear(); 292 | } 293 | } 294 | 295 | // these should not be callable from the main cpu, thus shouldnt be hitable... 296 | #[unsafe(no_mangle)] 297 | extern "C" fn bx_instr_init_env() {} 298 | #[unsafe(no_mangle)] 299 | extern "C" fn bx_instr_exit_env() {} 300 | #[unsafe(no_mangle)] 301 | extern "C" fn bx_instr_initialize(_: u32) {} 302 | #[unsafe(no_mangle)] 303 | extern "C" fn bx_instr_exit(_: u32) {} 304 | 305 | // 306 | 307 | #[unsafe(no_mangle)] 308 | unsafe extern "C-unwind" fn bx_instr_reset(cpu: u32, ty: u32) { 309 | unsafe { 310 | let src: ResetSource = ty.into(); 311 | 312 | // this is kind of awkward -- we call reset during cpu init to initialize 313 | // parts of it, but the cpu is half-initialized when this callback gets 314 | // fired, so this crashes. We're going to assume that we're the only ones 315 | // that can do hardware resets, and only call hooks for software resets 316 | if src == ResetSource::Hardware { 317 | return; 318 | } 319 | 320 | hooks().iter_mut().for_each(|x| x.reset(cpu, src)); 321 | 322 | if let Some(e) = hook_event(cpu).take() { 323 | match e { 324 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 325 | HookEvent::Exception(vector, error) => { 326 | cpu_exception(cpu, vector, error.unwrap_or(0)) 327 | } 328 | } 329 | } 330 | } 331 | } 332 | 333 | #[unsafe(no_mangle)] 334 | unsafe extern "C-unwind" fn bx_instr_hlt(cpu: u32) { 335 | unsafe { 336 | hooks().iter_mut().for_each(|x| x.hlt(cpu)); 337 | 338 | if let Some(e) = hook_event(cpu).take() { 339 | match e { 340 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 341 | HookEvent::Exception(vector, error) => { 342 | cpu_exception(cpu, vector, error.unwrap_or(0)) 343 | } 344 | } 345 | } 346 | } 347 | } 348 | 349 | #[unsafe(no_mangle)] 350 | unsafe extern "C-unwind" fn bx_instr_mwait(cpu: u32, addr: PhyAddress, len: u32, flags: u32) { 351 | unsafe { 352 | hooks() 353 | .iter_mut() 354 | .for_each(|x| x.mwait(cpu, addr, len as usize, flags)); 355 | 356 | if let Some(e) = hook_event(cpu).take() { 357 | match e { 358 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 359 | HookEvent::Exception(vector, error) => { 360 | cpu_exception(cpu, vector, error.unwrap_or(0)) 361 | } 362 | } 363 | } 364 | } 365 | } 366 | 367 | #[unsafe(no_mangle)] 368 | unsafe extern "C-unwind" fn bx_instr_cnear_branch_taken( 369 | cpu: u32, 370 | branch_eip: Address, 371 | new_eip: Address, 372 | ) { 373 | unsafe { 374 | hooks() 375 | .iter_mut() 376 | .for_each(|x| x.cnear_branch_taken(cpu, branch_eip, new_eip)); 377 | 378 | if let Some(e) = hook_event(cpu).take() { 379 | match e { 380 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 381 | HookEvent::Exception(vector, error) => { 382 | cpu_exception(cpu, vector, error.unwrap_or(0)) 383 | } 384 | } 385 | } 386 | } 387 | } 388 | 389 | #[unsafe(no_mangle)] 390 | unsafe extern "C-unwind" fn bx_instr_cnear_branch_not_taken( 391 | cpu: u32, 392 | branch_eip: Address, 393 | new_eip: Address, 394 | ) { 395 | unsafe { 396 | hooks() 397 | .iter_mut() 398 | .for_each(|x| x.cnear_branch_not_taken(cpu, branch_eip, new_eip)); 399 | 400 | if let Some(e) = hook_event(cpu).take() { 401 | match e { 402 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 403 | HookEvent::Exception(vector, error) => { 404 | cpu_exception(cpu, vector, error.unwrap_or(0)) 405 | } 406 | } 407 | } 408 | } 409 | } 410 | 411 | #[unsafe(no_mangle)] 412 | unsafe extern "C-unwind" fn bx_instr_ucnear_branch( 413 | cpu: u32, 414 | what: u32, 415 | branch_eip: Address, 416 | new_eip: Address, 417 | ) { 418 | unsafe { 419 | hooks() 420 | .iter_mut() 421 | .for_each(|x| x.ucnear_branch(cpu, what.into(), branch_eip, new_eip)); 422 | 423 | if let Some(e) = hook_event(cpu).take() { 424 | match e { 425 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 426 | HookEvent::Exception(vector, error) => { 427 | cpu_exception(cpu, vector, error.unwrap_or(0)) 428 | } 429 | } 430 | } 431 | } 432 | } 433 | 434 | #[unsafe(no_mangle)] 435 | unsafe extern "C-unwind" fn bx_instr_far_branch( 436 | cpu: u32, 437 | what: u32, 438 | prev_cs: u16, 439 | prev_eip: Address, 440 | new_cs: u16, 441 | new_eip: Address, 442 | ) { 443 | unsafe { 444 | hooks() 445 | .iter_mut() 446 | .for_each(|x| x.far_branch(cpu, what.into(), (prev_cs, prev_eip), (new_cs, new_eip))); 447 | 448 | if let Some(e) = hook_event(cpu).take() { 449 | match e { 450 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 451 | HookEvent::Exception(vector, error) => { 452 | cpu_exception(cpu, vector, error.unwrap_or(0)) 453 | } 454 | } 455 | } 456 | } 457 | } 458 | 459 | #[unsafe(no_mangle)] 460 | unsafe extern "C-unwind" fn bx_instr_opcode( 461 | cpu: u32, 462 | i: *mut c_void, 463 | opcode: *const u8, 464 | len: u32, 465 | is32: u32, 466 | is64: u32, 467 | ) { 468 | unsafe { 469 | hooks().iter_mut().for_each(|x| { 470 | x.opcode( 471 | cpu, 472 | i, 473 | slice::from_raw_parts(opcode, len as usize), 474 | is32 != 0, 475 | is64 != 0, 476 | ) 477 | }); 478 | 479 | if let Some(e) = hook_event(cpu).take() { 480 | match e { 481 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 482 | HookEvent::Exception(vector, error) => { 483 | cpu_exception(cpu, vector, error.unwrap_or(0)) 484 | } 485 | } 486 | } 487 | } 488 | } 489 | 490 | #[unsafe(no_mangle)] 491 | unsafe extern "C-unwind" fn bx_instr_interrupt(cpu: u32, vector: u32) { 492 | unsafe { 493 | hooks().iter_mut().for_each(|x| x.interrupt(cpu, vector)); 494 | 495 | if let Some(e) = hook_event(cpu).take() { 496 | match e { 497 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 498 | HookEvent::Exception(vector, error) => { 499 | cpu_exception(cpu, vector, error.unwrap_or(0)) 500 | } 501 | } 502 | } 503 | } 504 | } 505 | 506 | #[unsafe(no_mangle)] 507 | unsafe extern "C-unwind" fn bx_instr_exception(cpu: u32, vector: u32, error_code: u32) { 508 | unsafe { 509 | hooks() 510 | .iter_mut() 511 | .for_each(|x| x.exception(cpu, vector, error_code)); 512 | 513 | if let Some(e) = hook_event(cpu).take() { 514 | match e { 515 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 516 | HookEvent::Exception(vector, error) => { 517 | cpu_exception(cpu, vector, error.unwrap_or(0)) 518 | } 519 | } 520 | } 521 | } 522 | } 523 | 524 | #[unsafe(no_mangle)] 525 | unsafe extern "C-unwind" fn bx_instr_hwinterrupt(cpu: u32, vector: u32, cs: u16, eip: Address) { 526 | unsafe { 527 | hooks() 528 | .iter_mut() 529 | .for_each(|x| x.hw_interrupt(cpu, vector, (cs, eip))); 530 | 531 | if let Some(e) = hook_event(cpu).take() { 532 | match e { 533 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 534 | HookEvent::Exception(vector, error) => { 535 | cpu_exception(cpu, vector, error.unwrap_or(0)) 536 | } 537 | } 538 | } 539 | } 540 | } 541 | 542 | #[unsafe(no_mangle)] 543 | extern "C-unwind" fn bx_instr_tlb_cntrl(cpu: u32, what: u32, new_cr3: PhyAddress) { 544 | let ty = what.into(); 545 | let maybe_cr3 = match ty { 546 | TlbCntrl::MovCr0 => Some(new_cr3), 547 | TlbCntrl::MovCr3 => Some(new_cr3), 548 | TlbCntrl::MovCr4 => Some(new_cr3), 549 | TlbCntrl::TaskSwitch => Some(new_cr3), 550 | _ => None, 551 | }; 552 | 553 | unsafe { 554 | hooks() 555 | .iter_mut() 556 | .for_each(|x| x.tlb_cntrl(cpu, ty, maybe_cr3)); 557 | 558 | if let Some(e) = hook_event(cpu).take() { 559 | match e { 560 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 561 | HookEvent::Exception(vector, error) => { 562 | cpu_exception(cpu, vector, error.unwrap_or(0)) 563 | } 564 | } 565 | } 566 | } 567 | } 568 | 569 | #[unsafe(no_mangle)] 570 | unsafe extern "C-unwind" fn bx_instr_cache_cntrl(cpu: u32, what: u32) { 571 | unsafe { 572 | hooks() 573 | .iter_mut() 574 | .for_each(|x| x.cache_cntrl(cpu, what.into())); 575 | 576 | if let Some(e) = hook_event(cpu).take() { 577 | match e { 578 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 579 | HookEvent::Exception(vector, error) => { 580 | cpu_exception(cpu, vector, error.unwrap_or(0)) 581 | } 582 | } 583 | } 584 | } 585 | } 586 | 587 | #[unsafe(no_mangle)] 588 | unsafe extern "C-unwind" fn bx_instr_prefetch_hint(cpu: u32, what: u32, seg: u32, offset: Address) { 589 | unsafe { 590 | hooks() 591 | .iter_mut() 592 | .for_each(|x| x.prefetch_hint(cpu, what.into(), seg, offset)); 593 | 594 | if let Some(e) = hook_event(cpu).take() { 595 | match e { 596 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 597 | HookEvent::Exception(vector, error) => { 598 | cpu_exception(cpu, vector, error.unwrap_or(0)) 599 | } 600 | } 601 | } 602 | 603 | if let Some(e) = hook_event(cpu).take() { 604 | match e { 605 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 606 | HookEvent::Exception(vector, error) => { 607 | cpu_exception(cpu, vector, error.unwrap_or(0)) 608 | } 609 | } 610 | } 611 | } 612 | } 613 | 614 | #[unsafe(no_mangle)] 615 | unsafe extern "C-unwind" fn bx_instr_clflush(cpu: u32, laddr: Address, paddr: PhyAddress) { 616 | unsafe { 617 | hooks() 618 | .iter_mut() 619 | .for_each(|x| x.clflush(cpu, laddr, paddr)); 620 | 621 | if let Some(e) = hook_event(cpu).take() { 622 | match e { 623 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 624 | HookEvent::Exception(vector, error) => { 625 | cpu_exception(cpu, vector, error.unwrap_or(0)) 626 | } 627 | } 628 | } 629 | } 630 | } 631 | 632 | #[unsafe(no_mangle)] 633 | unsafe extern "C-unwind" fn bx_instr_before_execution(cpu: u32, i: *mut c_void) { 634 | unsafe { 635 | hooks().iter_mut().for_each(|x| x.before_execution(cpu, i)); 636 | 637 | if let Some(e) = hook_event(cpu).take() { 638 | match e { 639 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 640 | HookEvent::Exception(vector, error) => { 641 | cpu_exception(cpu, vector, error.unwrap_or(0)) 642 | } 643 | } 644 | } 645 | } 646 | } 647 | 648 | #[unsafe(no_mangle)] 649 | unsafe extern "C-unwind" fn bx_instr_after_execution(cpu: u32, i: *mut c_void) { 650 | unsafe { 651 | hooks().iter_mut().for_each(|x| x.after_execution(cpu, i)); 652 | 653 | if let Some(e) = hook_event(cpu).take() { 654 | match e { 655 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 656 | HookEvent::Exception(vector, error) => { 657 | cpu_exception(cpu, vector, error.unwrap_or(0)) 658 | } 659 | } 660 | } 661 | } 662 | } 663 | 664 | #[unsafe(no_mangle)] 665 | unsafe extern "C-unwind" fn bx_instr_repeat_iteration(cpu: u32, i: *mut c_void) { 666 | unsafe { 667 | hooks().iter_mut().for_each(|x| x.repeat_iteration(cpu, i)); 668 | 669 | if let Some(e) = hook_event(cpu).take() { 670 | match e { 671 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 672 | HookEvent::Exception(vector, error) => { 673 | cpu_exception(cpu, vector, error.unwrap_or(0)) 674 | } 675 | } 676 | } 677 | } 678 | } 679 | 680 | #[unsafe(no_mangle)] 681 | unsafe extern "C-unwind" fn bx_instr_lin_access( 682 | cpu: u32, 683 | lin: Address, 684 | phy: Address, 685 | len: u32, 686 | memtype: u32, 687 | rw: u32, 688 | ) { 689 | unsafe { 690 | hooks() 691 | .iter_mut() 692 | .for_each(|x| x.lin_access(cpu, lin, phy, len as usize, memtype.into(), rw.into())); 693 | 694 | if let Some(e) = hook_event(cpu).take() { 695 | match e { 696 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 697 | HookEvent::Exception(vector, error) => { 698 | cpu_exception(cpu, vector, error.unwrap_or(0)) 699 | } 700 | } 701 | } 702 | } 703 | } 704 | 705 | #[unsafe(no_mangle)] 706 | unsafe extern "C-unwind" fn bx_instr_phy_access( 707 | cpu: u32, 708 | phy: Address, 709 | len: u32, 710 | memtype: u32, 711 | rw: u32, 712 | ) { 713 | unsafe { 714 | hooks() 715 | .iter_mut() 716 | .for_each(|x| x.phy_access(cpu, phy, len as usize, memtype.into(), rw.into())); 717 | 718 | if let Some(e) = hook_event(cpu).take() { 719 | match e { 720 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 721 | HookEvent::Exception(vector, error) => { 722 | cpu_exception(cpu, vector, error.unwrap_or(0)) 723 | } 724 | } 725 | } 726 | } 727 | } 728 | 729 | #[unsafe(no_mangle)] 730 | unsafe extern "C-unwind" fn bx_instr_inp(addr: u16, len: u32) { 731 | unsafe { 732 | hooks().iter_mut().for_each(|x| x.inp(addr, len as usize)); 733 | } 734 | } 735 | 736 | #[unsafe(no_mangle)] 737 | unsafe extern "C-unwind" fn bx_instr_inp2(addr: u16, len: u32, val: u32) { 738 | unsafe { 739 | hooks() 740 | .iter_mut() 741 | .for_each(|x| x.inp2(addr, len as usize, val)); 742 | } 743 | } 744 | 745 | #[unsafe(no_mangle)] 746 | unsafe extern "C-unwind" fn bx_instr_outp(addr: u16, len: u32, val: u32) { 747 | unsafe { 748 | hooks() 749 | .iter_mut() 750 | .for_each(|x| x.outp(addr, len as usize, val)); 751 | } 752 | } 753 | 754 | #[unsafe(no_mangle)] 755 | unsafe extern "C-unwind" fn bx_instr_cpuid(cpu: u32) { 756 | unsafe { 757 | hooks().iter_mut().for_each(|x| x.cpuid(cpu)); 758 | } 759 | } 760 | 761 | #[unsafe(no_mangle)] 762 | unsafe extern "C-unwind" fn bx_instr_wrmsr(cpu: u32, addr: u32, value: u64) { 763 | unsafe { 764 | hooks().iter_mut().for_each(|x| x.wrmsr(cpu, addr, value)); 765 | 766 | if let Some(e) = hook_event(cpu).take() { 767 | match e { 768 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 769 | HookEvent::Exception(vector, error) => { 770 | cpu_exception(cpu, vector, error.unwrap_or(0)) 771 | } 772 | } 773 | } 774 | } 775 | } 776 | 777 | #[unsafe(no_mangle)] 778 | unsafe extern "C-unwind" fn bx_instr_vmexit(cpu: u32, reason: u32, qualification: u64) { 779 | unsafe { 780 | hooks() 781 | .iter_mut() 782 | .for_each(|x| x.vmexit(cpu, reason, qualification)); 783 | 784 | if let Some(e) = hook_event(cpu).take() { 785 | match e { 786 | HookEvent::Stop | HookEvent::SetPc => cpu_bail(cpu), 787 | HookEvent::Exception(vector, error) => { 788 | cpu_exception(cpu, vector, error.unwrap_or(0)) 789 | } 790 | } 791 | } 792 | } 793 | } 794 | -------------------------------------------------------------------------------- /cabi/paramtree.cc: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////// 2 | // $Id: paramtree.cc 14206 2021-03-28 06:31:03Z vruppert $ 3 | ///////////////////////////////////////////////////////////////////////// 4 | // 5 | // Copyright (C) 2010-2021 The Bochs Project 6 | // 7 | // This library is free software; you can redistribute it and/or 8 | // modify it under the terms of the GNU Lesser General Public 9 | // License as published by the Free Software Foundation; either 10 | // version 2 of the License, or (at your option) any later version. 11 | // 12 | // This library is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | // Lesser General Public License for more details. 16 | // 17 | // You should have received a copy of the GNU Lesser General Public 18 | // License along with this library; if not, write to the Free Software 19 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | // 21 | ///////////////////////////////////////////////////////////////////////// 22 | 23 | #include "bochs.h" 24 | #include "siminterface.h" 25 | #include "paramtree.h" 26 | 27 | ///////////////////////////////////////////////////////////////////////// 28 | // define methods of bx_param_* and family 29 | ///////////////////////////////////////////////////////////////////////// 30 | 31 | extern bx_simulator_interface_c *SIM; 32 | extern logfunctions *siminterface_log; 33 | extern bx_list_c *root_param; 34 | #define LOG_THIS siminterface_log-> 35 | 36 | const char* bx_param_c::default_text_format = NULL; 37 | 38 | bx_param_c::bx_param_c(Bit32u id, const char *param_name, const char *param_desc) 39 | : bx_object_c(id), 40 | parent(NULL), 41 | description(NULL), 42 | label(NULL), 43 | ask_format(NULL), 44 | group_name(NULL) 45 | { 46 | set_type(BXT_PARAM); 47 | this->name = new char[strlen(param_name)+1]; 48 | strcpy(this->name, param_name); 49 | set_description(param_desc); 50 | this->text_format = (char*)default_text_format; 51 | this->long_text_format = (char*)default_text_format; 52 | this->runtime_param = 0; 53 | this->enabled = 1; 54 | this->options = 0; 55 | // dependent_list must be initialized before the set(), 56 | // because set calls update_dependents(). 57 | dependent_list = NULL; 58 | } 59 | 60 | bx_param_c::bx_param_c(Bit32u id, const char *param_name, const char *param_label, const char *param_desc) 61 | : bx_object_c(id), 62 | parent(NULL), 63 | description(NULL), 64 | label(NULL), 65 | ask_format(NULL), 66 | group_name(NULL) 67 | { 68 | set_type(BXT_PARAM); 69 | this->name = new char[strlen(param_name)+1]; 70 | strcpy(this->name, param_name); 71 | set_description(param_desc); 72 | set_label(param_label); 73 | this->text_format = (char*)default_text_format; 74 | this->long_text_format = (char*)default_text_format; 75 | this->runtime_param = 0; 76 | this->enabled = 1; 77 | this->options = 0; 78 | // dependent_list must be initialized before the set(), 79 | // because set calls update_dependents(). 80 | dependent_list = NULL; 81 | } 82 | 83 | bx_param_c::~bx_param_c() 84 | { 85 | delete [] name; 86 | delete [] label; 87 | delete [] description; 88 | delete [] ask_format; 89 | delete [] group_name; 90 | delete dependent_list; 91 | } 92 | 93 | void bx_param_c::set_description(const char *text) 94 | { 95 | delete [] this->description; 96 | if (text) { 97 | this->description = new char[strlen(text)+1]; 98 | strcpy(this->description, text); 99 | } else { 100 | this->description = NULL; 101 | } 102 | } 103 | 104 | void bx_param_c::set_label(const char *text) 105 | { 106 | delete [] label; 107 | if (text) { 108 | label = new char[strlen(text)+1]; 109 | strcpy(label, text); 110 | } else { 111 | label = NULL; 112 | } 113 | } 114 | 115 | void bx_param_c::set_ask_format(const char *format) 116 | { 117 | delete [] ask_format; 118 | if (format) { 119 | ask_format = new char[strlen(format)+1]; 120 | strcpy(ask_format, format); 121 | } else { 122 | ask_format = NULL; 123 | } 124 | } 125 | 126 | void bx_param_c::set_group(const char *group) 127 | { 128 | delete [] group_name; 129 | if (group) { 130 | group_name = new char[strlen(group)+1]; 131 | strcpy(group_name, group); 132 | } else { 133 | group_name = NULL; 134 | } 135 | } 136 | 137 | int bx_param_c::get_param_path(char *path_out, int maxlen) 138 | { 139 | if ((get_parent() == NULL) || (get_parent() == root_param)) { 140 | // Start with an empty string. 141 | // Never print the name of the root param. 142 | path_out[0] = 0; 143 | } else { 144 | // build path of the parent, add a period, add path of this node 145 | if (get_parent()->get_param_path(path_out, maxlen) > 0) { 146 | strncat(path_out, ".", maxlen); 147 | } 148 | } 149 | strncat(path_out, name, maxlen); 150 | return strlen(path_out); 151 | } 152 | 153 | const char* bx_param_c::set_default_format(const char *f) 154 | { 155 | const char *old = default_text_format; 156 | default_text_format = f; 157 | return old; 158 | } 159 | 160 | bx_param_num_c::bx_param_num_c(bx_param_c *parent, 161 | const char *name, 162 | const char *label, 163 | const char *description, 164 | Bit64s min, Bit64s max, Bit64s initial_val, 165 | bool is_shadow) 166 | : bx_param_c(SIM->gen_param_id(), name, label, description) 167 | { 168 | set_type(BXT_PARAM_NUM); 169 | this->min = min; 170 | this->max = max; 171 | this->initial_val = initial_val; 172 | this->val.number = initial_val; 173 | this->handler = NULL; 174 | this->save_handler = NULL; 175 | this->restore_handler = NULL; 176 | this->enable_handler = NULL; 177 | this->base = default_base; 178 | this->is_shadow = is_shadow; 179 | if (!is_shadow) { 180 | set(initial_val); 181 | } 182 | if (parent) { 183 | BX_ASSERT(parent->get_type() == BXT_LIST); 184 | this->parent = (bx_list_c *)parent; 185 | this->parent->add(this); 186 | } 187 | } 188 | 189 | Bit32u bx_param_num_c::default_base = BASE_DEC; 190 | 191 | Bit32u bx_param_num_c::set_default_base(Bit32u val) 192 | { 193 | Bit32u old = default_base; 194 | default_base = val; 195 | return old; 196 | } 197 | 198 | void bx_param_num_c::set_handler(param_event_handler handler) 199 | { 200 | this->handler = handler; 201 | // now that there's a handler, call set once to run the handler immediately 202 | //set (get ()); 203 | } 204 | 205 | void bx_param_num_c::set_sr_handlers(void *devptr, param_save_handler save, param_restore_handler restore) 206 | { 207 | sr_devptr = devptr; 208 | save_handler = save; 209 | restore_handler = restore; 210 | } 211 | 212 | void bx_param_num_c::set_dependent_list(bx_list_c *l) 213 | { 214 | dependent_list = l; 215 | update_dependents(); 216 | } 217 | 218 | Bit64s bx_param_num_c::get64() 219 | { 220 | if (save_handler) { 221 | return (*save_handler)(sr_devptr, this); 222 | } 223 | if (handler) { 224 | // the handler can decide what value to return and/or do some side effect 225 | return (*handler)(this, 0, val.number); 226 | } else { 227 | // just return the value 228 | return val.number; 229 | } 230 | } 231 | 232 | void bx_param_num_c::set(Bit64s newval) 233 | { 234 | if (!enabled) return; 235 | 236 | if (handler) { 237 | // the handler can override the new value and/or perform some side effect 238 | val.number = (*handler)(this, 1, newval); 239 | } else { 240 | // just set the value. This code does not check max/min. 241 | val.number = newval; 242 | } 243 | if (restore_handler) { 244 | val.number = newval; 245 | (*restore_handler)(sr_devptr, this, newval); 246 | } 247 | if ((val.number < min || val.number > max) && (Bit64u)max != BX_MAX_BIT64U) 248 | BX_PANIC(("numerical parameter '%s' was set to " FMT_LL "d, which is out of range " FMT_LL "d to " FMT_LL "d", get_name (), val.number, min, max)); 249 | if (dependent_list != NULL) update_dependents(); 250 | } 251 | 252 | void bx_param_num_c::set_range(Bit64u min, Bit64u max) 253 | { 254 | this->min = min; 255 | this->max = max; 256 | } 257 | 258 | void bx_param_num_c::set_initial_val(Bit64s initial_val) 259 | { 260 | this->val.number = this->initial_val = initial_val; 261 | } 262 | 263 | void bx_param_num_c::update_dependents() 264 | { 265 | if (dependent_list) { 266 | int en = val.number && enabled; 267 | for (int i=0; iget_size(); i++) { 268 | bx_param_c *param = dependent_list->get(i); 269 | if (param != this) 270 | param->set_enabled(en); 271 | } 272 | } 273 | } 274 | 275 | void bx_param_num_c::set_enabled(bool en) 276 | { 277 | // The enable handler may wish to allow/disallow the action 278 | if (enable_handler) { 279 | en = (*enable_handler)(this, en); 280 | } 281 | bx_param_c::set_enabled(en); 282 | update_dependents(); 283 | } 284 | 285 | int bx_param_num_c::parse_param(const char *ptr) 286 | { 287 | if (ptr != NULL) { 288 | Bit64u value; 289 | if (get_base() == BASE_DOUBLE) { 290 | double f2value = strtod(ptr, NULL); 291 | memcpy(&value, &f2value, sizeof(double)); 292 | set(value); 293 | } else if (get_base() == BASE_FLOAT) { 294 | float f1value = (float)strtod(ptr, NULL); 295 | memcpy(&value, &f1value, sizeof(float)); 296 | set(value); 297 | } else if ((ptr[0] == '0') && (ptr[1] == 'x')) { 298 | set(strtoull(ptr, NULL, 16)); 299 | } else { 300 | if (ptr[strlen(ptr)-1] == 'K') { 301 | set(1000 * strtoull(ptr, NULL, 10)); 302 | } 303 | else if (ptr[strlen(ptr)-1] == 'M') { 304 | set(1000000 * strtoull(ptr, NULL, 10)); 305 | } 306 | else { 307 | set(strtoull(ptr, NULL, 10)); 308 | } 309 | } 310 | return 1; 311 | } 312 | 313 | return 0; 314 | } 315 | 316 | void bx_param_num_c::dump_param(FILE *fp) 317 | { 318 | char tmpstr[BX_PATHNAME_LEN+1]; 319 | dump_param(tmpstr, BX_PATHNAME_LEN, 0); 320 | fputs(tmpstr, fp); 321 | } 322 | 323 | int bx_param_num_c::dump_param(char *buf, int len, bool dquotes) 324 | { 325 | Bit64s value = get64(); 326 | if (get_base() == BASE_DOUBLE) { 327 | double f2value; 328 | memcpy(&f2value, &value, sizeof(double)); 329 | snprintf(buf, len, "%f", f2value); 330 | } else if (get_base() == BASE_FLOAT) { 331 | float f1value; 332 | memcpy(&f1value, &value, sizeof(float)); 333 | snprintf(buf, len, "%f", f1value); 334 | } else if (get_base() == BASE_DEC) { 335 | if (get_min() >= BX_MIN_BIT64U) { 336 | if ((Bit64u) get_max() > BX_MAX_BIT32U) { 337 | snprintf(buf, len, FMT_LL"u", value); 338 | } else { 339 | snprintf(buf, len, "%u", (Bit32u) value); 340 | } 341 | } else { 342 | snprintf(buf, len, "%d", (Bit32s) value); 343 | } 344 | } else { 345 | if (get_format()) { 346 | snprintf(buf, len, get_format(), value); 347 | } else { 348 | if ((Bit64u)get_max() > BX_MAX_BIT32U) { 349 | snprintf(buf, len, "0x" FMT_LL "x", (Bit64u) value); 350 | } else { 351 | snprintf(buf, len, "0x%x", (Bit32u) value); 352 | } 353 | } 354 | } 355 | 356 | return strlen(buf); 357 | } 358 | 359 | // Signed 64 bit 360 | bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent, 361 | const char *name, 362 | Bit64s *ptr_to_real_val, 363 | int base, 364 | Bit8u highbit, 365 | Bit8u lowbit) 366 | : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT64S, BX_MAX_BIT64S, *ptr_to_real_val, 1) 367 | { 368 | this->varsize = 64; 369 | this->lowbit = lowbit; 370 | this->mask = ((BX_MAX_BIT64S >> (63 - (highbit - lowbit))) << lowbit); 371 | val.p64bit = ptr_to_real_val; 372 | if (base == BASE_HEX) { 373 | this->base = base; 374 | this->text_format = (char*)"0x" FMT_LL "x"; 375 | } 376 | } 377 | 378 | // Unsigned 64 bit 379 | bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent, 380 | const char *name, 381 | Bit64u *ptr_to_real_val, 382 | int base, 383 | Bit8u highbit, 384 | Bit8u lowbit) 385 | : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT64U, BX_MAX_BIT64U, *ptr_to_real_val, 1) 386 | { 387 | this->varsize = 64; 388 | this->lowbit = lowbit; 389 | this->mask = ((BX_MAX_BIT64U >> (63 - (highbit - lowbit))) << lowbit); 390 | val.p64bit = (Bit64s*) ptr_to_real_val; 391 | if (base == BASE_HEX) { 392 | this->base = base; 393 | this->text_format = (char*)"0x" FMT_LL "x"; 394 | } 395 | } 396 | 397 | // Signed 32 bit 398 | bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent, 399 | const char *name, 400 | Bit32s *ptr_to_real_val, 401 | int base, 402 | Bit8u highbit, 403 | Bit8u lowbit) 404 | : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT32S, BX_MAX_BIT32S, *ptr_to_real_val, 1) 405 | { 406 | this->varsize = 32; 407 | this->lowbit = lowbit; 408 | this->mask = ((BX_MAX_BIT32S >> (31 - (highbit - lowbit))) << lowbit); 409 | val.p32bit = ptr_to_real_val; 410 | if (base == BASE_HEX) { 411 | this->base = base; 412 | this->text_format = (char*)"0x%08x"; 413 | } 414 | } 415 | 416 | // Unsigned 32 bit 417 | bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent, 418 | const char *name, 419 | Bit32u *ptr_to_real_val, 420 | int base, 421 | Bit8u highbit, 422 | Bit8u lowbit) 423 | : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT32U, BX_MAX_BIT32U, *ptr_to_real_val, 1) 424 | { 425 | this->varsize = 32; 426 | this->lowbit = lowbit; 427 | this->mask = ((BX_MAX_BIT32U >> (31 - (highbit - lowbit))) << lowbit); 428 | val.p32bit = (Bit32s*) ptr_to_real_val; 429 | if (base == BASE_HEX) { 430 | this->base = base; 431 | this->text_format = (char*)"0x%08x"; 432 | } 433 | } 434 | 435 | // Signed 16 bit 436 | bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent, 437 | const char *name, 438 | Bit16s *ptr_to_real_val, 439 | int base, 440 | Bit8u highbit, 441 | Bit8u lowbit) 442 | : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT16S, BX_MAX_BIT16S, *ptr_to_real_val, 1) 443 | { 444 | this->varsize = 16; 445 | this->lowbit = lowbit; 446 | this->mask = ((BX_MAX_BIT16S >> (15 - (highbit - lowbit))) << lowbit); 447 | val.p16bit = ptr_to_real_val; 448 | if (base == BASE_HEX) { 449 | this->base = base; 450 | this->text_format = (char*)"0x%04x"; 451 | } 452 | } 453 | 454 | // Unsigned 16 bit 455 | bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent, 456 | const char *name, 457 | Bit16u *ptr_to_real_val, 458 | int base, 459 | Bit8u highbit, 460 | Bit8u lowbit) 461 | : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT16U, BX_MAX_BIT16U, *ptr_to_real_val, 1) 462 | { 463 | this->varsize = 16; 464 | this->lowbit = lowbit; 465 | this->mask = ((BX_MAX_BIT16U >> (15 - (highbit - lowbit))) << lowbit); 466 | val.p16bit = (Bit16s*) ptr_to_real_val; 467 | if (base == BASE_HEX) { 468 | this->base = base; 469 | this->text_format = (char*)"0x%04x"; 470 | } 471 | } 472 | 473 | // Signed 8 bit 474 | bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent, 475 | const char *name, 476 | Bit8s *ptr_to_real_val, 477 | int base, 478 | Bit8u highbit, 479 | Bit8u lowbit) 480 | : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT8S, BX_MAX_BIT8S, *ptr_to_real_val, 1) 481 | { 482 | this->varsize = 8; 483 | this->lowbit = lowbit; 484 | this->mask = ((BX_MAX_BIT8S >> (7 - (highbit - lowbit))) << lowbit); 485 | this->mask = (1 << (highbit - lowbit)) - 1; 486 | val.p8bit = ptr_to_real_val; 487 | if (base == BASE_HEX) { 488 | this->base = base; 489 | this->text_format = (char*)"0x%02x"; 490 | } 491 | } 492 | 493 | // Unsigned 8 bit 494 | bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent, 495 | const char *name, 496 | Bit8u *ptr_to_real_val, 497 | int base, 498 | Bit8u highbit, 499 | Bit8u lowbit) 500 | : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT8U, BX_MAX_BIT8U, *ptr_to_real_val, 1) 501 | { 502 | this->varsize = 8; 503 | this->lowbit = lowbit; 504 | this->mask = ((BX_MAX_BIT8U >> (7 - (highbit - lowbit))) << lowbit); 505 | val.p8bit = (Bit8s*) ptr_to_real_val; 506 | if (base == BASE_HEX) { 507 | this->base = base; 508 | this->text_format = (char*)"0x%02x"; 509 | } 510 | } 511 | 512 | // Float (floating point) 513 | bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent, 514 | const char *name, 515 | float *ptr_to_real_val) 516 | : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT64U, BX_MAX_BIT64U, 0, 1) 517 | { 518 | this->varsize = 32; 519 | this->lowbit = 0; 520 | this->mask = BX_MAX_BIT32U; 521 | val.pfloat = ptr_to_real_val; 522 | this->base = BASE_FLOAT; 523 | } 524 | 525 | // Double (floating point) 526 | bx_shadow_num_c::bx_shadow_num_c(bx_param_c *parent, 527 | const char *name, 528 | double *ptr_to_real_val) 529 | : bx_param_num_c(parent, name, NULL, NULL, BX_MIN_BIT64U, BX_MAX_BIT64U, 0, 1) 530 | { 531 | this->varsize = 64; 532 | this->lowbit = 0; 533 | this->mask = BX_MAX_BIT64U; 534 | val.pdouble = ptr_to_real_val; 535 | this->base = BASE_DOUBLE; 536 | } 537 | 538 | Bit64s bx_shadow_num_c::get64() 539 | { 540 | Bit64u current = 0; 541 | switch (varsize) { 542 | case 8: current = *(val.p8bit); break; 543 | case 16: current = *(val.p16bit); break; 544 | case 32: current = *(val.p32bit); break; 545 | case 64: current = *(val.p64bit); break; 546 | default: BX_PANIC(("unsupported varsize %d", varsize)); 547 | } 548 | current = (current >> lowbit) & mask; 549 | if (handler) { 550 | // the handler can decide what value to return and/or do some side effect 551 | return (*handler)(this, 0, current) & mask; 552 | } else { 553 | // just return the value 554 | return current; 555 | } 556 | } 557 | 558 | void bx_shadow_num_c::set(Bit64s newval) 559 | { 560 | Bit64u tmp = 0; 561 | if (((newval < min) || (newval > max)) && (min != BX_MIN_BIT64S) && ((Bit64u)max != BX_MAX_BIT64U)) 562 | BX_PANIC(("numerical parameter %s was set to " FMT_LL "d, which is out of range " FMT_LL "d to " FMT_LL "d", get_name (), newval, min, max)); 563 | switch (varsize) { 564 | case 8: 565 | tmp = *(val.p8bit) & ~(mask << lowbit); 566 | tmp |= (newval & mask) << lowbit; 567 | *(val.p8bit) = (Bit8s)tmp; 568 | break; 569 | case 16: 570 | tmp = *(val.p16bit) & ~(mask << lowbit); 571 | tmp |= (newval & mask) << lowbit; 572 | *(val.p16bit) = (Bit16s)tmp; 573 | break; 574 | case 32: 575 | tmp = *(val.p32bit) & ~(mask << lowbit); 576 | tmp |= (newval & mask) << lowbit; 577 | *(val.p32bit) = (Bit32s)tmp; 578 | break; 579 | case 64: 580 | tmp = *(val.p64bit) & ~(mask << lowbit); 581 | tmp |= (newval & mask) << lowbit; 582 | *(val.p64bit) = (Bit64s)tmp; 583 | break; 584 | default: 585 | BX_PANIC(("unsupported varsize %d", varsize)); 586 | } 587 | if (handler) { 588 | // the handler can override the new value and/or perform some side effect 589 | (*handler)(this, 1, tmp); 590 | } 591 | } 592 | 593 | void bx_shadow_num_c::reset() 594 | { 595 | BX_PANIC(("reset not supported on bx_shadow_num_c yet")); 596 | } 597 | 598 | bx_param_bool_c::bx_param_bool_c(bx_param_c *parent, 599 | const char *name, 600 | const char *label, 601 | const char *description, 602 | Bit64s initial_val, 603 | bool is_shadow) 604 | : bx_param_num_c(parent, name, label, description, 0, 1, initial_val, is_shadow) 605 | { 606 | set_type(BXT_PARAM_BOOL); 607 | } 608 | 609 | int bx_param_bool_c::parse_param(const char *ptr) 610 | { 611 | if (ptr != NULL) { 612 | if (!strcmp(ptr, "0") || !stricmp(ptr, "false")) { 613 | set(0); return 1; 614 | } 615 | if (!strcmp(ptr, "1") || !stricmp(ptr, "true")) { 616 | set(1); return 1; 617 | } 618 | } 619 | 620 | return 0; 621 | } 622 | 623 | void bx_param_bool_c::dump_param(FILE *fp) 624 | { 625 | fprintf(fp, "%s", get()?"true":"false"); 626 | } 627 | 628 | int bx_param_bool_c::dump_param(char *buf, int len, bool dquotes) 629 | { 630 | snprintf(buf, len, "%s", get()?"true":"false"); 631 | return strlen(buf); 632 | } 633 | 634 | bx_shadow_bool_c::bx_shadow_bool_c(bx_param_c *parent, 635 | const char *name, 636 | const char *label, 637 | bool *ptr_to_real_val) 638 | : bx_param_bool_c(parent, name, label, NULL, (Bit64s) *ptr_to_real_val, 1) 639 | { 640 | val.pbool = ptr_to_real_val; 641 | } 642 | 643 | bx_shadow_bool_c::bx_shadow_bool_c(bx_param_c *parent, 644 | const char *name, 645 | bool *ptr_to_real_val) 646 | : bx_param_bool_c(parent, name, NULL, NULL, (Bit64s) *ptr_to_real_val, 1) 647 | { 648 | val.pbool = ptr_to_real_val; 649 | } 650 | 651 | Bit64s bx_shadow_bool_c::get64() 652 | { 653 | if (handler) { 654 | // the handler can decide what value to return and/or do some side effect 655 | return (*handler)(this, 0, (Bit64s) *(val.pbool)); 656 | } else { 657 | // just return the value 658 | return (Bit64s)*(val.pbool); 659 | } 660 | } 661 | 662 | void bx_shadow_bool_c::set(Bit64s newval) 663 | { 664 | *(val.pbool) = (newval != 0); 665 | if (handler) { 666 | // the handler can override the new value and/or perform some side effect 667 | (*handler)(this, 1, (Bit64s)newval); 668 | } 669 | } 670 | 671 | bx_param_enum_c::bx_param_enum_c(bx_param_c *parent, 672 | const char *name, 673 | const char *label, 674 | const char *description, 675 | const char **choices, 676 | Bit64s initial_val, 677 | Bit64s value_base) 678 | : bx_param_num_c(parent, name, label, description, value_base, BX_MAX_BIT64S, initial_val) 679 | { 680 | set_type(BXT_PARAM_ENUM); 681 | this->choices = choices; 682 | // count number of choices, set max 683 | const char **p = choices; 684 | while (*p != NULL) p++; 685 | this->min = value_base; 686 | // now that the max is known, replace the BX_MAX_BIT64S sent to the parent 687 | // class constructor with the real max. 688 | this->max = value_base + (p - choices - 1); 689 | this->deps_bitmap = NULL; 690 | set(initial_val); 691 | } 692 | 693 | bx_param_enum_c::~bx_param_enum_c() 694 | { 695 | delete [] deps_bitmap; 696 | } 697 | 698 | 699 | void bx_param_enum_c::set(Bit64s val) 700 | { 701 | bx_param_num_c::set(val); 702 | update_dependents(); 703 | } 704 | 705 | int bx_param_enum_c::find_by_name(const char *s) 706 | { 707 | const char **p; 708 | for (p=&choices[0]; *p; p++) { 709 | if (!strcmp(s, *p)) 710 | return p-choices; 711 | } 712 | return -1; 713 | } 714 | 715 | bool bx_param_enum_c::set_by_name(const char *s) 716 | { 717 | int n = find_by_name(s); 718 | if (n<0) return 0; 719 | set(n + min); 720 | return 1; 721 | } 722 | 723 | void bx_param_enum_c::set_dependent_list(bx_list_c *l, bool enable_all) 724 | { 725 | dependent_list = l; 726 | deps_bitmap = new Bit64u[(unsigned)(max - min + 1)]; 727 | for (int i=0; i<(max-min+1); i++) { 728 | if (enable_all) { 729 | deps_bitmap[i] = (1 << (l->get_size())) - 1; 730 | } else { 731 | deps_bitmap[i] = 0; 732 | } 733 | } 734 | update_dependents(); 735 | } 736 | 737 | void bx_param_enum_c::set_dependent_bitmap(Bit64s value, Bit64u bitmap) 738 | { 739 | if (deps_bitmap != NULL) { 740 | deps_bitmap[value - min] = bitmap; 741 | } 742 | update_dependents(); 743 | } 744 | 745 | Bit64u bx_param_enum_c::get_dependent_bitmap(Bit64s value) 746 | { 747 | if (deps_bitmap != NULL) { 748 | return deps_bitmap[value - min]; 749 | } 750 | return 0; 751 | } 752 | 753 | void bx_param_enum_c::update_dependents() 754 | { 755 | if ((dependent_list != NULL) && (deps_bitmap != NULL)) { 756 | Bit64u en_bmap = deps_bitmap[val.number - min]; 757 | Bit64u mask = 0x1; 758 | for (int i=0; iget_size(); i++) { 759 | int en = (en_bmap & mask) && enabled; 760 | bx_param_c *param = dependent_list->get(i); 761 | if (param != this) 762 | param->set_enabled(en); 763 | mask <<= 1; 764 | } 765 | } 766 | } 767 | 768 | void bx_param_enum_c::set_enabled(bool en) 769 | { 770 | // The enable handler may wish to allow/disallow the action 771 | if (enable_handler) { 772 | en = (*enable_handler)(this, en); 773 | } 774 | bx_param_c::set_enabled(en); 775 | update_dependents(); 776 | } 777 | 778 | int bx_param_enum_c::parse_param(const char *ptr) 779 | { 780 | if (ptr != NULL) { 781 | return set_by_name(ptr); 782 | } 783 | 784 | return 0; 785 | } 786 | 787 | void bx_param_enum_c::dump_param(FILE *fp) 788 | { 789 | fprintf(fp, "%s", get_selected()); 790 | } 791 | 792 | int bx_param_enum_c::dump_param(char *buf, int len, bool dquotes) 793 | { 794 | snprintf(buf, len, "%s", get_selected()); 795 | return strlen(buf); 796 | } 797 | 798 | bx_param_string_c::bx_param_string_c(bx_param_c *parent, 799 | const char *name, 800 | const char *label, 801 | const char *description, 802 | const char *initial_val, 803 | int maxsize) 804 | : bx_param_c(SIM->gen_param_id(), name, label, description) 805 | { 806 | set_type(BXT_PARAM_STRING); 807 | int initial_val_size = strlen(initial_val) + 1; 808 | if (maxsize < 0) { 809 | maxsize = initial_val_size; 810 | } else if (initial_val_size > maxsize) { 811 | initial_val_size = maxsize; 812 | } 813 | this->val = new char[maxsize]; 814 | this->initial_val = new char[maxsize]; 815 | this->handler = NULL; 816 | this->enable_handler = NULL; 817 | this->maxsize = maxsize; 818 | strncpy(this->val, initial_val, initial_val_size); 819 | if (maxsize > initial_val_size) 820 | memset(this->val + initial_val_size, 0, maxsize - initial_val_size); 821 | strncpy(this->initial_val, initial_val, maxsize); 822 | this->options = 0; 823 | set(initial_val); 824 | if (parent) { 825 | BX_ASSERT(parent->get_type() == BXT_LIST); 826 | this->parent = (bx_list_c *)parent; 827 | this->parent->add(this); 828 | } 829 | } 830 | 831 | bx_param_string_c::~bx_param_string_c() 832 | { 833 | delete [] val; 834 | delete [] initial_val; 835 | } 836 | 837 | void bx_param_string_c::reset() 838 | { 839 | set(initial_val); 840 | } 841 | 842 | void bx_param_string_c::set_handler(param_string_event_handler handler) 843 | { 844 | this->handler = handler; 845 | } 846 | 847 | void bx_param_string_c::set_enable_handler(param_enable_handler handler) 848 | { 849 | this->enable_handler = handler; 850 | } 851 | 852 | void bx_param_string_c::update_dependents() 853 | { 854 | if (dependent_list) { 855 | int en = (strlen(val) > 0) && (strcmp(val, "none")) && enabled; 856 | for (int i=0; iget_size(); i++) { 857 | bx_param_c *param = dependent_list->get(i); 858 | if (param != this) 859 | param->set_enabled(en); 860 | } 861 | } 862 | } 863 | 864 | void bx_param_string_c::set_enabled(bool en) 865 | { 866 | // The enable handler may wish to allow/disallow the action 867 | if (enable_handler) { 868 | en = (*enable_handler)(this, en); 869 | } 870 | bx_param_c::set_enabled(en); 871 | if (dependent_list != NULL) update_dependents(); 872 | } 873 | 874 | void bx_param_string_c::set_dependent_list(bx_list_c *l) 875 | { 876 | dependent_list = l; 877 | update_dependents(); 878 | } 879 | 880 | Bit32s bx_param_string_c::get(char *buf, int len) 881 | { 882 | strncpy(buf, val, len); 883 | if (handler) { 884 | // the handler can choose to replace the value in val/len. Also its 885 | // return value is passed back as the return value of get. 886 | (*handler)(this, 0, buf, buf, len); 887 | } 888 | return 0; 889 | } 890 | 891 | void bx_param_string_c::set(const char *buf) 892 | { 893 | char *oldval = new char[maxsize]; 894 | 895 | strncpy(oldval, val, maxsize); 896 | oldval[maxsize - 1] = 0; 897 | if (handler) { 898 | // the handler can return a different char* to be copied into the value 899 | buf = (*handler)(this, 1, oldval, buf, -1); 900 | } 901 | strncpy(val, buf, maxsize); 902 | val[maxsize - 1] = 0; 903 | delete [] oldval; 904 | if (dependent_list != NULL) update_dependents(); 905 | } 906 | 907 | bool bx_param_string_c::equals(const char *buf) const 908 | { 909 | return (strncmp(val, buf, maxsize) == 0); 910 | } 911 | 912 | void bx_param_string_c::set_initial_val(const char *buf) 913 | { 914 | strncpy(initial_val, buf, maxsize); 915 | set(initial_val); 916 | } 917 | 918 | bool bx_param_string_c::isempty() const 919 | { 920 | return (strlen(val) == 0) || !strcmp(val, "none"); 921 | } 922 | 923 | int bx_param_string_c::parse_param(const char *ptr) 924 | { 925 | if (ptr != NULL) { 926 | set(ptr); 927 | } else { 928 | set(""); 929 | } 930 | 931 | return 1; 932 | } 933 | 934 | void bx_param_string_c::dump_param(FILE *fp) 935 | { 936 | char tmpstr[BX_PATHNAME_LEN+1]; 937 | dump_param(tmpstr, BX_PATHNAME_LEN, 0); 938 | fputs(tmpstr, fp); 939 | } 940 | 941 | int bx_param_string_c::dump_param(char *buf, int len, bool dquotes) 942 | { 943 | if (!isempty()) { 944 | if (dquotes) { 945 | snprintf(buf, len, "\"%s\"", val); 946 | } else { 947 | snprintf(buf, len, "%s", val); 948 | } 949 | } else { 950 | strcpy(buf, "none"); 951 | } 952 | return strlen(buf); 953 | } 954 | 955 | Bit32s bx_param_bytestring_c::get(char *buf, int len) 956 | { 957 | memcpy(buf, val, len); 958 | if (handler) { 959 | // the handler can choose to replace the value in val/len. Also its 960 | // return value is passed back as the return value of get. 961 | (*handler)(this, 0, buf, buf, len); 962 | } 963 | return 0; 964 | } 965 | 966 | void bx_param_bytestring_c::set(const char *buf) 967 | { 968 | char *oldval = new char[maxsize]; 969 | 970 | memcpy(oldval, val, maxsize); 971 | if (handler) { 972 | // the handler can return a different char* to be copied into the value 973 | buf = (*handler)(this, 1, oldval, buf, -1); 974 | } 975 | memcpy(val, buf, maxsize); 976 | delete [] oldval; 977 | if (dependent_list != NULL) update_dependents(); 978 | } 979 | 980 | bool bx_param_bytestring_c::equals(const char *buf) const 981 | { 982 | return (memcmp(val, buf, maxsize) == 0); 983 | } 984 | 985 | void bx_param_bytestring_c::set_initial_val(const char *buf) 986 | { 987 | memcpy(initial_val, buf, maxsize); 988 | set(initial_val); 989 | } 990 | 991 | bool bx_param_bytestring_c::isempty() const 992 | { 993 | return (memcmp(val, initial_val, maxsize) == 0); 994 | } 995 | 996 | int bx_param_bytestring_c::parse_param(const char *ptr) 997 | { 998 | int j, p = 0, ret = 1; 999 | unsigned n; 1000 | char buf[512]; 1001 | 1002 | memset(buf, 0, get_maxsize()); 1003 | for (j = 0; j < get_maxsize(); j++) { 1004 | if (ptr[p] == get_separator()) { 1005 | p++; 1006 | } 1007 | if (sscanf(ptr+p, "%02x", &n) == 1) { 1008 | buf[j] = n; 1009 | p += 2; 1010 | } else { 1011 | ret = 0; 1012 | } 1013 | } 1014 | if (!equals(buf)) set(buf); 1015 | 1016 | return ret; 1017 | } 1018 | 1019 | int bx_param_bytestring_c::dump_param(char *buf, int len, bool dquotes) 1020 | { 1021 | buf[0] = 0; 1022 | for (int j = 0; j < maxsize; j++) { 1023 | char tmpbyte[4]; 1024 | if (j > 0) { 1025 | tmpbyte[0] = separator; 1026 | tmpbyte[1] = 0; 1027 | strcat(buf, tmpbyte); 1028 | } 1029 | sprintf(tmpbyte, "%02x", (Bit8u)val[j]); 1030 | strcat(buf, tmpbyte); 1031 | } 1032 | return strlen(buf); 1033 | } 1034 | 1035 | #ifdef WIN32 1036 | void replace_slash_for_win32(char *str) 1037 | { 1038 | while (*str) { 1039 | if (*str == '/') 1040 | *str = '\\'; 1041 | str++; 1042 | } 1043 | } 1044 | #endif 1045 | 1046 | bx_param_filename_c::bx_param_filename_c(bx_param_c *parent, 1047 | const char *name, 1048 | const char *label, 1049 | const char *description, 1050 | const char *initial_val, 1051 | int maxsize) 1052 | : bx_param_string_c(parent, name, label, description, initial_val, maxsize) 1053 | { 1054 | set_options(IS_FILENAME); 1055 | int len = strlen(initial_val); 1056 | if ((len > 4) && (initial_val[len - 4] == '.')) { 1057 | ext = &initial_val[len - 3]; 1058 | } else { 1059 | ext = NULL; 1060 | } 1061 | #ifdef WIN32 1062 | replace_slash_for_win32(val); 1063 | #endif 1064 | } 1065 | 1066 | void bx_param_filename_c::set(const char *buf) 1067 | { 1068 | bx_param_string_c::set(buf); 1069 | #ifdef WIN32 1070 | replace_slash_for_win32(val); 1071 | #endif 1072 | } 1073 | 1074 | void bx_param_filename_c::set_initial_val(const char *buf) 1075 | { 1076 | bx_param_string_c::set_initial_val(buf); 1077 | #ifdef WIN32 1078 | replace_slash_for_win32(initial_val); 1079 | #endif 1080 | } 1081 | 1082 | bx_shadow_data_c::bx_shadow_data_c(bx_param_c *parent, 1083 | const char *name, 1084 | Bit8u *ptr_to_data, 1085 | Bit32u data_size, 1086 | bool is_text) 1087 | : bx_param_c(SIM->gen_param_id(), name, "") 1088 | { 1089 | set_type(BXT_PARAM_DATA); 1090 | this->data_ptr = ptr_to_data; 1091 | this->data_size = data_size; 1092 | this->is_text = is_text; 1093 | if (parent) { 1094 | BX_ASSERT(parent->get_type() == BXT_LIST); 1095 | this->parent = (bx_list_c *)parent; 1096 | this->parent->add(this); 1097 | } 1098 | } 1099 | 1100 | Bit8u bx_shadow_data_c::get(Bit32u index) 1101 | { 1102 | if (index < data_size) { 1103 | return data_ptr[index]; 1104 | } else { 1105 | return 0; 1106 | } 1107 | } 1108 | 1109 | void bx_shadow_data_c::set(Bit32u index, Bit8u value) 1110 | { 1111 | if (index < data_size) { 1112 | data_ptr[index] = value; 1113 | } 1114 | } 1115 | 1116 | bx_shadow_filedata_c::bx_shadow_filedata_c(bx_param_c *parent, 1117 | const char *name, FILE **scratch_file_ptr_ptr) 1118 | : bx_param_c(SIM->gen_param_id(), name, "") 1119 | { 1120 | set_type(BXT_PARAM_FILEDATA); 1121 | this->scratch_fpp = scratch_file_ptr_ptr; 1122 | this->save_handler = NULL; 1123 | this->restore_handler = NULL; 1124 | if (parent) { 1125 | BX_ASSERT(parent->get_type() == BXT_LIST); 1126 | this->parent = (bx_list_c *)parent; 1127 | this->parent->add(this); 1128 | } 1129 | } 1130 | 1131 | // Save handler: called before file save, Restore handler: called after file restore 1132 | void bx_shadow_filedata_c::set_sr_handlers(void *devptr, filedata_save_handler save, filedata_restore_handler restore) 1133 | { 1134 | this->sr_devptr = devptr; 1135 | this->save_handler = save; 1136 | this->restore_handler = restore; 1137 | } 1138 | 1139 | void bx_shadow_filedata_c::save(FILE *save_fp) 1140 | { 1141 | if (save_handler) 1142 | (*save_handler)(sr_devptr, save_fp); 1143 | } 1144 | 1145 | void bx_shadow_filedata_c::restore(FILE *save_fp) 1146 | { 1147 | if (restore_handler) 1148 | (*restore_handler)(sr_devptr, save_fp); 1149 | } 1150 | 1151 | bx_list_c::bx_list_c(bx_param_c *parent) 1152 | : bx_param_c(SIM->gen_param_id(), "list", "") 1153 | { 1154 | set_type(BXT_LIST); 1155 | this->size = 0; 1156 | this->list = NULL; 1157 | this->parent = NULL; 1158 | if (parent) { 1159 | BX_ASSERT(parent->get_type() == BXT_LIST); 1160 | this->parent = (bx_list_c *)parent; 1161 | this->parent->add(this); 1162 | } 1163 | init(""); 1164 | } 1165 | 1166 | bx_list_c::bx_list_c(bx_param_c *parent, const char *name) 1167 | : bx_param_c(SIM->gen_param_id(), name, "") 1168 | { 1169 | set_type (BXT_LIST); 1170 | this->size = 0; 1171 | this->list = NULL; 1172 | this->parent = NULL; 1173 | if (parent) { 1174 | BX_ASSERT(parent->get_type() == BXT_LIST); 1175 | this->parent = (bx_list_c *)parent; 1176 | this->parent->add(this); 1177 | } 1178 | this->restore_handler = NULL; 1179 | init(""); 1180 | } 1181 | 1182 | bx_list_c::bx_list_c(bx_param_c *parent, const char *name, const char *title) 1183 | : bx_param_c(SIM->gen_param_id(), name, "") 1184 | { 1185 | set_type (BXT_LIST); 1186 | this->size = 0; 1187 | this->list = NULL; 1188 | this->parent = NULL; 1189 | if (parent) { 1190 | BX_ASSERT(parent->get_type() == BXT_LIST); 1191 | this->parent = (bx_list_c *)parent; 1192 | this->parent->add(this); 1193 | } 1194 | this->restore_handler = NULL; 1195 | init(title); 1196 | } 1197 | 1198 | bx_list_c::bx_list_c(bx_param_c *parent, const char *name, const char *title, bx_param_c **init_list) 1199 | : bx_param_c(SIM->gen_param_id(), name, "") 1200 | { 1201 | set_type(BXT_LIST); 1202 | this->size = 0; 1203 | this->list = NULL; 1204 | while (init_list[this->size] != NULL) 1205 | add(init_list[this->size]); 1206 | this->parent = NULL; 1207 | if (parent) { 1208 | BX_ASSERT(parent->get_type() == BXT_LIST); 1209 | this->parent = (bx_list_c *)parent; 1210 | this->parent->add(this); 1211 | } 1212 | this->restore_handler = NULL; 1213 | init(title); 1214 | } 1215 | 1216 | bx_list_c::~bx_list_c() 1217 | { 1218 | if (list != NULL) { 1219 | clear(); 1220 | } 1221 | delete [] title; 1222 | } 1223 | 1224 | void bx_list_c::init(const char *list_title) 1225 | { 1226 | if (list_title) { 1227 | this->title = new char[strlen(list_title)+1]; 1228 | strcpy(this->title, list_title); 1229 | } else { 1230 | this->title = new char[1]; 1231 | this->title[0] = 0; 1232 | } 1233 | this->options = 0; 1234 | this->choice = 1; 1235 | } 1236 | 1237 | void bx_list_c::set_parent(bx_param_c *newparent) 1238 | { 1239 | if (parent) { 1240 | // if this object already had a parent, the correct thing 1241 | // to do would be to remove this object from the parent's 1242 | // list of children. Deleting children is currently 1243 | // not supported. 1244 | BX_PANIC(("bx_list_c::set_parent: changing from one parent to another is not supported")); 1245 | } 1246 | if (newparent) { 1247 | BX_ASSERT(newparent->get_type() == BXT_LIST); 1248 | parent = (bx_list_c *)newparent; 1249 | parent->add(this); 1250 | } 1251 | } 1252 | 1253 | bx_list_c* bx_list_c::clone() 1254 | { 1255 | bx_list_c *newlist = new bx_list_c(NULL, name, title); 1256 | for (int i=0; iadd(get(i)); 1258 | newlist->set_options(options); 1259 | return newlist; 1260 | } 1261 | 1262 | void bx_list_c::add(bx_param_c *param) 1263 | { 1264 | if ((get_by_name(param->get_name()) != NULL) && (param->get_parent() == this)) { 1265 | BX_PANIC(("parameter '%s' already exists in list '%s'", param->get_name(), this->get_name())); 1266 | return; 1267 | } 1268 | bx_listitem_t *item = new bx_listitem_t; 1269 | item->param = param; 1270 | item->next = NULL; 1271 | if (list == NULL) { 1272 | list = item; 1273 | } else { 1274 | bx_listitem_t *temp = list; 1275 | while (temp->next) 1276 | temp = temp->next; 1277 | temp->next = item; 1278 | } 1279 | if (runtime_param) { 1280 | param->set_runtime_param(1); 1281 | } 1282 | size++; 1283 | } 1284 | 1285 | bx_param_c* bx_list_c::get(int index) 1286 | { 1287 | BX_ASSERT(index >= 0 && index < size); 1288 | int i = 0; 1289 | bx_listitem_t *temp = list; 1290 | while (temp != NULL) { 1291 | if (i == index) { 1292 | return temp->param; 1293 | } 1294 | temp = temp->next; 1295 | i++; 1296 | } 1297 | return NULL; 1298 | } 1299 | 1300 | bx_param_c* bx_list_c::get_by_name(const char *name) 1301 | { 1302 | bx_listitem_t *temp = list; 1303 | while (temp != NULL) { 1304 | bx_param_c *p = temp->param; 1305 | if (!stricmp(name, p->get_name())) { 1306 | return p; 1307 | } 1308 | temp = temp->next; 1309 | } 1310 | return NULL; 1311 | } 1312 | 1313 | void bx_list_c::reset() 1314 | { 1315 | bx_listitem_t *temp = list; 1316 | while (temp != NULL) { 1317 | temp->param->reset(); 1318 | temp = temp->next; 1319 | } 1320 | } 1321 | 1322 | void bx_list_c::clear() 1323 | { 1324 | bx_listitem_t *temp = list, *next; 1325 | while (temp != NULL) { 1326 | if (temp->param->get_parent() == this) { 1327 | delete temp->param; 1328 | } 1329 | next = temp->next; 1330 | delete temp; 1331 | temp = next; 1332 | } 1333 | list = NULL; 1334 | size = 0; 1335 | } 1336 | 1337 | void bx_list_c::remove(const char *name) 1338 | { 1339 | bx_listitem_t *item, *prev = NULL; 1340 | 1341 | for (item = list; item; item = item->next) { 1342 | bx_param_c *p = item->param; 1343 | if (!stricmp(name, p->get_name())) { 1344 | if (p->get_parent() == this) { 1345 | delete p; 1346 | } 1347 | if (prev == NULL) { 1348 | list = item->next; 1349 | } else { 1350 | prev->next = item->next; 1351 | } 1352 | delete item; 1353 | size--; 1354 | break; 1355 | } else { 1356 | prev = item; 1357 | } 1358 | } 1359 | } 1360 | 1361 | void bx_list_c::set_runtime_param(bool val) 1362 | { 1363 | runtime_param = val; 1364 | if (runtime_param) { 1365 | for (bx_listitem_t * item = list; item; item = item->next) { 1366 | item->param->set_runtime_param(1); 1367 | } 1368 | } 1369 | } 1370 | 1371 | void bx_list_c::set_restore_handler(void *devptr, list_restore_handler restore) 1372 | { 1373 | sr_devptr = devptr; 1374 | restore_handler = restore; 1375 | } 1376 | 1377 | void bx_list_c::restore() 1378 | { 1379 | if (restore_handler) 1380 | (*restore_handler)(sr_devptr, this); 1381 | } 1382 | -------------------------------------------------------------------------------- /src/cpu/mod.rs: -------------------------------------------------------------------------------- 1 | use std::convert::TryInto; 2 | 3 | #[cfg(feature = "serde")] 4 | use serde::{Deserialize, Serialize}; 5 | 6 | use crate::hook::{self, HookEvent, Hooks, set_hook_event}; 7 | use crate::syncunsafecell::{SyncUnsafeCell, ptr_to_ref_mut}; 8 | use crate::{Address, NUM_CPUS, PhyAddress}; 9 | 10 | mod state; 11 | pub use state::State; 12 | 13 | // look at lock_api crate to see if I can figure out how to do cpu locking 14 | // so I dont need to make everything unsafe 15 | 16 | unsafe extern "C" { 17 | fn cpu_new(id: u32); 18 | fn cpu_delete(id: u32); 19 | 20 | fn cpu_loop(id: u32); 21 | 22 | fn cpu_set_mode(id: u32); 23 | 24 | fn cpu_get_pc(id: u32) -> u64; 25 | fn cpu_set_pc(id: u32, val: u64); 26 | fn cpu_set_sp(id: u32, val: u64); 27 | 28 | fn cpu_get_ssp(id: u32) -> u64; 29 | fn cpu_set_ssp(id: u32, val: u64); 30 | 31 | fn cpu_get_reg64(id: u32, reg: u32) -> u64; 32 | fn cpu_set_reg64(id: u32, reg: u32, val: u64); 33 | 34 | fn cpu_get_eflags(id: u32) -> u32; 35 | fn cpu_set_eflags(id: u32, eflags: u32); 36 | 37 | fn cpu_get_seg( 38 | id: u32, 39 | seg: u32, 40 | present: *mut u32, 41 | selector: *mut u16, 42 | base: *mut Address, 43 | limit: *mut u32, 44 | attr: *mut u16, 45 | ); 46 | fn cpu_set_seg( 47 | id: u32, 48 | seg: u32, 49 | present: u32, 50 | selector: u16, 51 | base: Address, 52 | limit: u32, 53 | attr: u16, 54 | ); 55 | fn cpu_get_ldtr( 56 | id: u32, 57 | present: *mut u32, 58 | selector: *mut u16, 59 | base: *mut Address, 60 | limit: *mut u32, 61 | attr: *mut u16, 62 | ); 63 | fn cpu_set_ldtr(id: u32, present: u32, selector: u16, base: Address, limit: u32, attr: u16); 64 | fn cpu_get_tr( 65 | id: u32, 66 | present: *mut u32, 67 | selector: *mut u16, 68 | base: *mut Address, 69 | limit: *mut u32, 70 | attr: *mut u16, 71 | ); 72 | fn cpu_set_tr(id: u32, present: u32, selector: u16, base: Address, limit: u32, attr: u16); 73 | fn cpu_get_gdtr(id: u32, base: *mut Address, limit: *mut u16); 74 | fn cpu_set_gdtr(id: u32, base: Address, limit: u16); 75 | fn cpu_get_idtr(id: u32, base: *mut Address, limit: *mut u16); 76 | fn cpu_set_idtr(id: u32, base: Address, limit: u16); 77 | 78 | fn cpu_get_dr(id: u32, reg: u32) -> Address; 79 | fn cpu_set_dr(id: u32, reg: u32, val: Address); 80 | fn cpu_get_dr6(id: u32) -> u32; 81 | fn cpu_set_dr6(id: u32, val: u32); 82 | fn cpu_get_dr7(id: u32) -> u32; 83 | fn cpu_set_dr7(id: u32, val: u32); 84 | 85 | fn cpu_get_cr0(id: u32) -> u32; 86 | fn cpu_set_cr0(id: u32, val: u32); 87 | fn cpu_get_cr2(id: u32) -> Address; 88 | fn cpu_set_cr2(id: u32, val: Address); 89 | fn cpu_get_cr3(id: u32) -> Address; 90 | fn cpu_set_cr3(id: u32, val: Address); 91 | fn cpu_get_cr4(id: u32) -> u32; 92 | fn cpu_set_cr4(id: u32, val: u32); 93 | fn cpu_get_cr8(id: u32) -> u32; 94 | fn cpu_set_cr8(id: u32, val: u32); 95 | fn cpu_get_efer(id: u32) -> u32; 96 | fn cpu_set_efer(id: u32, val: u32); 97 | fn cpu_get_xcr0(id: u32) -> u32; 98 | fn cpu_set_xcr0(id: u32, val: u32); 99 | 100 | fn cpu_get_kernel_gs_base(id: u32) -> u64; 101 | fn cpu_set_kernel_gs_base(id: u32, val: u64); 102 | fn cpu_get_sysenter_cs(id: u32) -> u32; 103 | fn cpu_set_sysenter_cs(id: u32, val: u32); 104 | fn cpu_get_sysenter_eip(id: u32) -> Address; 105 | fn cpu_set_sysenter_eip(id: u32, val: Address); 106 | fn cpu_get_sysenter_esp(id: u32) -> Address; 107 | fn cpu_set_sysenter_esp(id: u32, val: Address); 108 | fn cpu_get_star(id: u32) -> u64; 109 | fn cpu_set_star(id: u32, val: u64); 110 | fn cpu_get_lstar(id: u32) -> u64; 111 | fn cpu_set_lstar(id: u32, val: u64); 112 | fn cpu_get_cstar(id: u32) -> u64; 113 | fn cpu_set_cstar(id: u32, val: u64); 114 | fn cpu_get_fmask(id: u32) -> u32; 115 | fn cpu_set_fmask(id: u32, val: u32); 116 | fn cpu_get_tsc(id: u32) -> u64; 117 | fn cpu_set_tsc(id: u32, val: u64); 118 | fn cpu_get_tsc_aux(id: u32) -> u32; 119 | fn cpu_set_tsc_aux(id: u32, val: u32); 120 | fn cpu_get_apicbase(id: u32) -> PhyAddress; 121 | fn cpu_set_apicbase(id: u32, val: PhyAddress); 122 | fn cpu_get_pat(id: u32) -> u64; 123 | fn cpu_set_pat(id: u32, val: u64); 124 | 125 | fn cpu_get_zmm(id: u32, reg: u32, val: *mut u64); 126 | fn cpu_set_zmm(id: u32, reg: u32, val: *const u64); 127 | fn cpu_get_mxcsr(id: u32) -> u32; 128 | fn cpu_set_mxcsr(id: u32, val: u32); 129 | fn cpu_get_mxcsr_mask(id: u32) -> u32; 130 | fn cpu_set_mxcsr_mask(id: u32, val: u32); 131 | 132 | fn cpu_get_fp_cw(id: u32) -> u16; 133 | fn cpu_set_fp_cw(id: u32, val: u16); 134 | fn cpu_get_fp_sw(id: u32) -> u16; 135 | fn cpu_set_fp_sw(id: u32, val: u16); 136 | fn cpu_get_fp_tw(id: u32) -> u16; 137 | fn cpu_set_fp_tw(id: u32, val: u16); 138 | fn cpu_get_fp_op(id: u32) -> u16; 139 | fn cpu_set_fp_op(id: u32, val: u16); 140 | fn cpu_get_fp_st(id: u32, reg: u32, val: *mut u64, exp: *mut u16); 141 | fn cpu_set_fp_st(id: u32, reg: u32, val: u64, exp: u16); 142 | 143 | fn cpu_get_cet_control_u(id: u32) -> u64; 144 | fn cpu_set_cet_control_u(id: u32, val: u64); 145 | fn cpu_get_cet_control_s(id: u32) -> u64; 146 | fn cpu_set_cet_control_s(id: u32, val: u64); 147 | fn cpu_get_pl0_ssp(id: u32) -> u64; 148 | fn cpu_set_pl0_ssp(id: u32, val: u64); 149 | fn cpu_get_pl1_ssp(id: u32) -> u64; 150 | fn cpu_set_pl1_ssp(id: u32, val: u64); 151 | fn cpu_get_pl2_ssp(id: u32) -> u64; 152 | fn cpu_set_pl2_ssp(id: u32, val: u64); 153 | fn cpu_get_pl3_ssp(id: u32) -> u64; 154 | fn cpu_set_pl3_ssp(id: u32, val: u64); 155 | fn cpu_get_interrupt_ssp_table(id: u32) -> u64; 156 | fn cpu_set_interrupt_ssp_table(id: u32, val: u64); 157 | 158 | /// Bail out of the cpu eval loop 159 | /// 160 | /// This ffi's to longjmp, meaning some variables drop routines might be 161 | /// skipped, depending on the context and platform 162 | pub(crate) fn cpu_bail(id: u32) -> !; 163 | 164 | /// Return the current killbit status 165 | pub(crate) fn cpu_killbit(id: u32) -> u32; 166 | fn cpu_set_killbit(id: u32); 167 | fn cpu_clear_killbit(id: u32); 168 | pub(crate) fn cpu_exception(id: u32, vector: u32, error: u16) -> !; 169 | } 170 | 171 | enum GpRegs { 172 | Rax = 0, 173 | Rcx = 1, 174 | Rdx = 2, 175 | Rbx = 3, 176 | Rsp = 4, 177 | Rbp = 5, 178 | Rsi = 6, 179 | Rdi = 7, 180 | R8 = 8, 181 | R9 = 9, 182 | R10 = 10, 183 | R11 = 11, 184 | R12 = 12, 185 | R13 = 13, 186 | R14 = 14, 187 | R15 = 15, 188 | // unused Rip = 16, 189 | } 190 | 191 | enum SegRegs { 192 | Es = 0, 193 | Cs = 1, 194 | Ss = 2, 195 | Ds = 3, 196 | Fs = 4, 197 | Gs = 5, 198 | } 199 | 200 | enum DRegs { 201 | Dr0 = 0, 202 | Dr1 = 1, 203 | Dr2 = 2, 204 | Dr3 = 3, 205 | } 206 | 207 | #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] 208 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 209 | #[repr(C)] 210 | pub struct Float80 { 211 | pub fraction: u64, 212 | pub exp: u16, 213 | } 214 | 215 | #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] 216 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 217 | #[repr(C)] 218 | pub struct Zmm { 219 | pub q: [u64; 8], 220 | } 221 | 222 | #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] 223 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 224 | #[repr(C)] 225 | pub struct GlobalSeg { 226 | pub base: Address, 227 | pub limit: u16, 228 | } 229 | 230 | #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)] 231 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 232 | #[repr(C)] 233 | pub struct Seg { 234 | pub present: bool, 235 | pub selector: u16, 236 | pub base: Address, 237 | pub limit: u32, 238 | pub attr: u16, 239 | } 240 | 241 | #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] 242 | pub enum RunState { 243 | Go, 244 | Stop, 245 | } 246 | 247 | #[derive(Clone, Eq, PartialEq, Hash, Debug)] 248 | pub(crate) struct Tracking { 249 | seed: u64, 250 | pub(crate) state: RunState, 251 | } 252 | 253 | impl Default for Tracking { 254 | fn default() -> Self { 255 | Self { 256 | seed: 0, 257 | state: RunState::Stop, 258 | } 259 | } 260 | } 261 | 262 | #[ctor] 263 | static CPU_TRACKING: SyncUnsafeCell> = 264 | unsafe { SyncUnsafeCell::new(vec![Tracking::default(); NUM_CPUS]) }; 265 | 266 | unsafe fn cpu_tracking(id: u32) -> &'static mut Tracking { 267 | unsafe { &mut ptr_to_ref_mut(CPU_TRACKING.0.get())[id as usize] } 268 | } 269 | 270 | pub(crate) unsafe fn run_state(id: u32) -> RunState { 271 | unsafe { cpu_tracking(id).state } 272 | } 273 | 274 | pub(crate) unsafe fn set_run_state(id: u32, rs: RunState) { 275 | unsafe { 276 | cpu_tracking(id).state = rs; 277 | } 278 | } 279 | 280 | unsafe fn seed(id: u32) -> u64 { 281 | unsafe { cpu_tracking(id).seed } 282 | } 283 | 284 | unsafe fn set_seed(id: u32, seed: u64) { 285 | unsafe { 286 | cpu_tracking(id).seed = seed; 287 | } 288 | } 289 | 290 | #[unsafe(no_mangle)] 291 | extern "C" fn bochscpu_rand(id: u32) -> u64 { 292 | let seed = unsafe { seed(id) }; 293 | let hash = blake3::hash(&seed.to_le_bytes()); 294 | 295 | // set the seed from the low 64 bits 296 | let new_seed = u64::from_le_bytes(hash.as_bytes()[0..8].try_into().unwrap()); 297 | unsafe { set_seed(id, new_seed) }; 298 | 299 | // return the next 64 bits as entropy 300 | u64::from_le_bytes(hash.as_bytes()[8..16].try_into().unwrap()) 301 | } 302 | 303 | pub struct CpuRun<'a> { 304 | cpu: &'a Cpu, 305 | } 306 | 307 | impl<'a> CpuRun<'a> { 308 | pub fn new(cpu: &'a Cpu) -> Self { 309 | Self { cpu } 310 | } 311 | 312 | pub unsafe fn run(self) -> RunState { 313 | unsafe { 314 | set_hook_event(self.cpu.handle, None); 315 | 316 | self.cpu.set_run_state(RunState::Go); 317 | 318 | while cpu_killbit(self.cpu.handle) == 0 { 319 | match run_state(self.cpu.handle) { 320 | RunState::Stop => break, 321 | _ => cpu_loop(self.cpu.handle), 322 | } 323 | } 324 | 325 | self.cpu.run_state() 326 | } 327 | } 328 | 329 | pub unsafe fn register(self, hook: &mut dyn Hooks) -> Self { 330 | unsafe { 331 | hook::register(hook); 332 | 333 | self 334 | } 335 | } 336 | } 337 | 338 | impl<'a> Drop for CpuRun<'a> { 339 | fn drop(&mut self) { 340 | unsafe { hook::clear() }; 341 | } 342 | } 343 | 344 | pub struct Cpu { 345 | handle: u32, 346 | } 347 | 348 | impl Cpu { 349 | pub unsafe fn new(id: u32) -> Self { 350 | unsafe { 351 | cpu_new(id); 352 | 353 | Self { handle: id } 354 | } 355 | } 356 | 357 | pub unsafe fn new_with_seed(id: u32, seed: u64) -> Self { 358 | unsafe { 359 | let c = Self::new(id); 360 | c.set_seed(seed); 361 | 362 | c 363 | } 364 | } 365 | 366 | pub unsafe fn new_with_state(id: u32, s: &State) -> Self { 367 | unsafe { 368 | let c = Self::new(id); 369 | c.set_state(s); 370 | 371 | c 372 | } 373 | } 374 | 375 | pub fn from(id: u32) -> Self { 376 | Self { handle: id } 377 | } 378 | 379 | pub fn id(&self) -> u32 { 380 | self.handle 381 | } 382 | 383 | pub unsafe fn delete(self) { 384 | unsafe { 385 | cpu_delete(self.handle); 386 | } 387 | } 388 | 389 | pub unsafe fn prepare(&self) -> CpuRun { 390 | CpuRun::new(self) 391 | } 392 | 393 | pub unsafe fn run_state(&self) -> RunState { 394 | unsafe { run_state(self.handle) } 395 | } 396 | 397 | pub unsafe fn set_run_state(&self, rs: RunState) { 398 | unsafe { 399 | set_run_state(self.handle, rs); 400 | 401 | match rs { 402 | RunState::Stop => { 403 | set_hook_event(self.handle, Some(HookEvent::Stop)); 404 | cpu_set_killbit(self.handle); 405 | } 406 | _ => cpu_clear_killbit(self.handle), 407 | }; 408 | } 409 | } 410 | 411 | pub unsafe fn seed(&self) -> u64 { 412 | unsafe { seed(self.handle) } 413 | } 414 | 415 | pub unsafe fn set_seed(&self, new_seed: u64) { 416 | unsafe { set_seed(self.handle, new_seed) } 417 | } 418 | 419 | // rax=0000000000000000 rbx=00000202e01c5080 rcx=00000202e01b5c88 420 | // rdx=000000b69e6ef750 rsi=0000000000000000 rdi=000000b69e6ff750 421 | // rip=00007ffa91c37870 rsp=000000b69e6ef6b8 rbp=0000000000000000 422 | // r8=0000000000010000 r9=000000b69e6ef704 r10=00000202e01c9a40 423 | // r11=00000202e01e42a0 r12=0000000000000000 r13=0000000000000000 424 | // r14=0000000000000000 r15=0000000000000000 425 | pub unsafe fn print_gprs(&self) { 426 | unsafe { 427 | println!( 428 | "rax={:016x} rbx={:016x} rcx={:016x}", 429 | self.rax(), 430 | self.rbx(), 431 | self.rcx() 432 | ); 433 | println!( 434 | "rdx={:016x} rsi={:016x} rdi={:016x}", 435 | self.rdx(), 436 | self.rsi(), 437 | self.rdi() 438 | ); 439 | println!( 440 | "rip={:016x} rsp={:016x} rbp={:016x}", 441 | self.rip(), 442 | self.rsp(), 443 | self.rbp() 444 | ); 445 | println!( 446 | " r8={:016x} r9={:016x} r10={:016x}", 447 | self.r8(), 448 | self.r9(), 449 | self.r10() 450 | ); 451 | println!( 452 | "r11={:016x} r12={:016x} r13={:016x}", 453 | self.r11(), 454 | self.r12(), 455 | self.r13() 456 | ); 457 | println!("r14={:016x} r15={:016x}", self.r14(), self.r15()); 458 | } 459 | } 460 | 461 | pub unsafe fn state(&self) -> State { 462 | unsafe { 463 | State { 464 | bochscpu_seed: seed(self.handle), 465 | 466 | rip: self.rip(), 467 | 468 | rax: self.rax(), 469 | rcx: self.rcx(), 470 | rdx: self.rdx(), 471 | rbx: self.rbx(), 472 | rsp: self.rsp(), 473 | rbp: self.rbp(), 474 | rsi: self.rsi(), 475 | rdi: self.rdi(), 476 | r8: self.r8(), 477 | r9: self.r9(), 478 | r10: self.r10(), 479 | r11: self.r11(), 480 | r12: self.r12(), 481 | r13: self.r13(), 482 | r14: self.r14(), 483 | r15: self.r15(), 484 | rflags: self.rflags(), 485 | ssp: self.ssp(), 486 | 487 | es: self.es(), 488 | cs: self.cs(), 489 | ss: self.ss(), 490 | ds: self.ds(), 491 | fs: self.fs(), 492 | gs: self.gs(), 493 | 494 | ldtr: self.ldtr(), 495 | tr: self.tr(), 496 | gdtr: self.gdtr(), 497 | idtr: self.idtr(), 498 | 499 | dr0: self.dr0(), 500 | dr1: self.dr1(), 501 | dr2: self.dr2(), 502 | dr3: self.dr3(), 503 | dr6: self.dr6(), 504 | dr7: self.dr7(), 505 | 506 | cr0: self.cr0(), 507 | cr2: self.cr2(), 508 | cr3: self.cr3(), 509 | cr4: self.cr4(), 510 | cr8: self.cr8(), 511 | xcr0: self.xcr0(), 512 | 513 | kernel_gs_base: self.kernel_gs_base(), 514 | sysenter_cs: self.sysenter_cs(), 515 | sysenter_eip: self.sysenter_eip(), 516 | sysenter_esp: self.sysenter_esp(), 517 | star: self.star(), 518 | lstar: self.lstar(), 519 | cstar: self.cstar(), 520 | efer: self.efer(), 521 | sfmask: self.sfmask(), 522 | tsc: self.tsc(), 523 | apic_base: self.apic_base(), 524 | pat: self.pat(), 525 | tsc_aux: self.tsc_aux(), 526 | 527 | zmm: [ 528 | self.zmm(0), 529 | self.zmm(1), 530 | self.zmm(2), 531 | self.zmm(3), 532 | self.zmm(4), 533 | self.zmm(5), 534 | self.zmm(6), 535 | self.zmm(7), 536 | self.zmm(8), 537 | self.zmm(9), 538 | self.zmm(10), 539 | self.zmm(11), 540 | self.zmm(12), 541 | self.zmm(13), 542 | self.zmm(14), 543 | self.zmm(15), 544 | self.zmm(16), 545 | self.zmm(17), 546 | self.zmm(18), 547 | self.zmm(19), 548 | self.zmm(20), 549 | self.zmm(21), 550 | self.zmm(22), 551 | self.zmm(23), 552 | self.zmm(24), 553 | self.zmm(25), 554 | self.zmm(26), 555 | self.zmm(27), 556 | self.zmm(28), 557 | self.zmm(29), 558 | self.zmm(30), 559 | self.zmm(31), 560 | ], 561 | mxcsr: self.mxcsr(), 562 | mxcsr_mask: self.mxcsr_mask(), 563 | 564 | fpcw: self.fp_cw(), 565 | fpsw: self.fp_sw(), 566 | fptw: self.fp_tw(), 567 | fpop: self.fp_op(), 568 | fpst: [ 569 | self.fp_st(0), 570 | self.fp_st(1), 571 | self.fp_st(2), 572 | self.fp_st(3), 573 | self.fp_st(4), 574 | self.fp_st(5), 575 | self.fp_st(6), 576 | self.fp_st(7), 577 | ], 578 | 579 | cet_control_u: self.cet_control_u(), 580 | cet_control_s: self.cet_control_s(), 581 | pl0_ssp: self.pl0_ssp(), 582 | pl1_ssp: self.pl1_ssp(), 583 | pl2_ssp: self.pl2_ssp(), 584 | pl3_ssp: self.pl3_ssp(), 585 | interrupt_ssp_table: self.interrupt_ssp_table(), 586 | } 587 | } 588 | } 589 | 590 | pub unsafe fn set_state_no_flush(&self, s: &State) { 591 | unsafe { 592 | self.set_seed(s.bochscpu_seed); 593 | 594 | self.set_rip(s.rip); 595 | 596 | self.set_rax(s.rax); 597 | self.set_rcx(s.rcx); 598 | self.set_rdx(s.rdx); 599 | self.set_rbx(s.rbx); 600 | self.set_rsp(s.rsp); 601 | self.set_rbp(s.rbp); 602 | self.set_rsi(s.rsi); 603 | self.set_rdi(s.rdi); 604 | self.set_r8(s.r8); 605 | self.set_r9(s.r9); 606 | self.set_r10(s.r10); 607 | self.set_r11(s.r11); 608 | self.set_r12(s.r12); 609 | self.set_r13(s.r13); 610 | self.set_r14(s.r14); 611 | self.set_r15(s.r15); 612 | self.set_rflags(s.rflags); 613 | self.set_ssp(s.ssp); 614 | 615 | self.set_es(s.es); 616 | let deferred_flush = self.set_cs_deferred(s.cs); 617 | self.set_ss(s.ss); 618 | self.set_ds(s.ds); 619 | self.set_fs(s.fs); 620 | self.set_gs(s.gs); 621 | 622 | self.set_ldtr(s.ldtr); 623 | self.set_tr(s.tr); 624 | self.set_gdtr(s.gdtr); 625 | self.set_idtr(s.idtr); 626 | 627 | self.set_dr0(s.dr0); 628 | self.set_dr1(s.dr1); 629 | self.set_dr2(s.dr2); 630 | self.set_dr3(s.dr3); 631 | self.set_dr6(s.dr6); 632 | self.set_dr7(s.dr7); 633 | 634 | self.set_cr0(s.cr0); 635 | self.set_cr2(s.cr2); 636 | self.set_cr3(s.cr3); 637 | self.set_cr4(s.cr4); 638 | self.set_cr8(s.cr8); 639 | self.set_xcr0(s.xcr0); 640 | 641 | self.set_kernel_gs_base(s.kernel_gs_base); 642 | self.set_sysenter_cs(s.sysenter_cs); 643 | self.set_sysenter_esp(s.sysenter_esp); 644 | self.set_sysenter_eip(s.sysenter_eip); 645 | self.set_efer(s.efer); 646 | self.set_star(s.star); 647 | self.set_lstar(s.lstar); 648 | self.set_cstar(s.cstar); 649 | self.set_sfmask(s.sfmask); 650 | self.set_tsc(s.tsc); 651 | self.set_apic_base(s.apic_base); 652 | self.set_pat(s.pat); 653 | self.set_tsc_aux(s.tsc_aux); 654 | 655 | self.set_cet_control_u(s.cet_control_u); 656 | self.set_cet_control_s(s.cet_control_s); 657 | self.set_pl0_ssp(s.pl0_ssp); 658 | self.set_pl1_ssp(s.pl1_ssp); 659 | self.set_pl2_ssp(s.pl2_ssp); 660 | self.set_pl3_ssp(s.pl3_ssp); 661 | self.set_interrupt_ssp_table(s.interrupt_ssp_table); 662 | 663 | for (ii, z) in (s.zmm).iter().enumerate() { 664 | self.set_zmm(ii, *z); 665 | } 666 | self.set_mxcsr(s.mxcsr); 667 | self.set_mxcsr_mask(s.mxcsr_mask); 668 | 669 | self.set_fp_cw(s.fpcw); 670 | self.set_fp_sw(s.fpsw); 671 | self.set_fp_tw(s.fptw); 672 | self.set_fp_op(s.fpop); 673 | 674 | for (ii, f) in (s.fpst).iter().enumerate() { 675 | self.set_fp_st(ii, *f); 676 | } 677 | 678 | if deferred_flush { 679 | self.set_mode(); 680 | } 681 | } 682 | } 683 | 684 | pub unsafe fn set_state(&self, s: &State) { 685 | unsafe { 686 | self.set_state_no_flush(s); 687 | self.set_mode(); 688 | } 689 | } 690 | 691 | pub unsafe fn set_exception(&self, vector: u32, error: Option) { 692 | unsafe { 693 | set_hook_event(self.handle, Some(HookEvent::Exception(vector, error))); 694 | } 695 | } 696 | 697 | // 698 | // regs below here 699 | // 700 | 701 | // gp regs 702 | 703 | pub unsafe fn rip(&self) -> u64 { 704 | unsafe { cpu_get_pc(self.handle) } 705 | } 706 | 707 | pub unsafe fn set_rip(&self, v: u64) { 708 | unsafe { 709 | cpu_set_pc(self.handle, v); 710 | 711 | set_hook_event(self.handle, Some(HookEvent::SetPc)); 712 | } 713 | } 714 | 715 | pub unsafe fn rax(&self) -> u64 { 716 | unsafe { cpu_get_reg64(self.handle, GpRegs::Rax as _) } 717 | } 718 | 719 | pub unsafe fn set_rax(&self, v: u64) { 720 | unsafe { cpu_set_reg64(self.handle, GpRegs::Rax as _, v) } 721 | } 722 | 723 | pub unsafe fn rcx(&self) -> u64 { 724 | unsafe { cpu_get_reg64(self.handle, GpRegs::Rcx as _) } 725 | } 726 | 727 | pub unsafe fn set_rcx(&self, v: u64) { 728 | unsafe { cpu_set_reg64(self.handle, GpRegs::Rcx as _, v) } 729 | } 730 | 731 | pub unsafe fn rdx(&self) -> u64 { 732 | unsafe { cpu_get_reg64(self.handle, GpRegs::Rdx as _) } 733 | } 734 | 735 | pub unsafe fn set_rdx(&self, v: u64) { 736 | unsafe { cpu_set_reg64(self.handle, GpRegs::Rdx as _, v) } 737 | } 738 | 739 | pub unsafe fn rbx(&self) -> u64 { 740 | unsafe { cpu_get_reg64(self.handle, GpRegs::Rbx as _) } 741 | } 742 | 743 | pub unsafe fn set_rbx(&self, v: u64) { 744 | unsafe { cpu_set_reg64(self.handle, GpRegs::Rbx as _, v) } 745 | } 746 | 747 | pub unsafe fn rsp(&self) -> u64 { 748 | unsafe { cpu_get_reg64(self.handle, GpRegs::Rsp as _) } 749 | } 750 | 751 | pub unsafe fn set_rsp(&self, v: u64) { 752 | unsafe { cpu_set_sp(self.handle, v) } 753 | } 754 | 755 | pub unsafe fn ssp(&self) -> u64 { 756 | unsafe { cpu_get_ssp(self.handle) } 757 | } 758 | 759 | pub unsafe fn set_ssp(&self, v: u64) { 760 | unsafe { cpu_set_ssp(self.handle, v) } 761 | } 762 | 763 | pub unsafe fn rbp(&self) -> u64 { 764 | unsafe { cpu_get_reg64(self.handle, GpRegs::Rbp as _) } 765 | } 766 | 767 | pub unsafe fn set_rbp(&self, v: u64) { 768 | unsafe { cpu_set_reg64(self.handle, GpRegs::Rbp as _, v) } 769 | } 770 | 771 | pub unsafe fn rsi(&self) -> u64 { 772 | unsafe { cpu_get_reg64(self.handle, GpRegs::Rsi as _) } 773 | } 774 | 775 | pub unsafe fn set_rsi(&self, v: u64) { 776 | unsafe { cpu_set_reg64(self.handle, GpRegs::Rsi as _, v) } 777 | } 778 | 779 | pub unsafe fn rdi(&self) -> u64 { 780 | unsafe { cpu_get_reg64(self.handle, GpRegs::Rdi as _) } 781 | } 782 | 783 | pub unsafe fn set_rdi(&self, v: u64) { 784 | unsafe { cpu_set_reg64(self.handle, GpRegs::Rdi as _, v) } 785 | } 786 | 787 | pub unsafe fn r8(&self) -> u64 { 788 | unsafe { cpu_get_reg64(self.handle, GpRegs::R8 as _) } 789 | } 790 | 791 | pub unsafe fn set_r8(&self, v: u64) { 792 | unsafe { cpu_set_reg64(self.handle, GpRegs::R8 as _, v) } 793 | } 794 | 795 | pub unsafe fn r9(&self) -> u64 { 796 | unsafe { cpu_get_reg64(self.handle, GpRegs::R9 as _) } 797 | } 798 | 799 | pub unsafe fn set_r9(&self, v: u64) { 800 | unsafe { cpu_set_reg64(self.handle, GpRegs::R9 as _, v) } 801 | } 802 | 803 | pub unsafe fn r10(&self) -> u64 { 804 | unsafe { cpu_get_reg64(self.handle, GpRegs::R10 as _) } 805 | } 806 | 807 | pub unsafe fn set_r10(&self, v: u64) { 808 | unsafe { cpu_set_reg64(self.handle, GpRegs::R10 as _, v) } 809 | } 810 | 811 | pub unsafe fn r11(&self) -> u64 { 812 | unsafe { cpu_get_reg64(self.handle, GpRegs::R11 as _) } 813 | } 814 | 815 | pub unsafe fn set_r11(&self, v: u64) { 816 | unsafe { cpu_set_reg64(self.handle, GpRegs::R11 as _, v) } 817 | } 818 | 819 | pub unsafe fn r12(&self) -> u64 { 820 | unsafe { cpu_get_reg64(self.handle, GpRegs::R12 as _) } 821 | } 822 | 823 | pub unsafe fn set_r12(&self, v: u64) { 824 | unsafe { cpu_set_reg64(self.handle, GpRegs::R12 as _, v) } 825 | } 826 | 827 | pub unsafe fn r13(&self) -> u64 { 828 | unsafe { cpu_get_reg64(self.handle, GpRegs::R13 as _) } 829 | } 830 | 831 | pub unsafe fn set_r13(&self, v: u64) { 832 | unsafe { cpu_set_reg64(self.handle, GpRegs::R13 as _, v) } 833 | } 834 | 835 | pub unsafe fn r14(&self) -> u64 { 836 | unsafe { cpu_get_reg64(self.handle, GpRegs::R14 as _) } 837 | } 838 | 839 | pub unsafe fn set_r14(&self, v: u64) { 840 | unsafe { cpu_set_reg64(self.handle, GpRegs::R14 as _, v) } 841 | } 842 | 843 | pub unsafe fn r15(&self) -> u64 { 844 | unsafe { cpu_get_reg64(self.handle, GpRegs::R15 as _) } 845 | } 846 | 847 | pub unsafe fn set_r15(&self, v: u64) { 848 | unsafe { cpu_set_reg64(self.handle, GpRegs::R15 as _, v) } 849 | } 850 | 851 | pub unsafe fn rflags(&self) -> u64 { 852 | unsafe { cpu_get_eflags(self.handle) as _ } 853 | } 854 | 855 | pub unsafe fn set_rflags(&self, v: u64) { 856 | unsafe { cpu_set_eflags(self.handle, v as _) } 857 | } 858 | 859 | // segment registers 860 | 861 | unsafe fn seg(&self, s: SegRegs) -> Seg { 862 | unsafe { 863 | let mut present = 0; 864 | let mut selector = 0; 865 | let mut base = 0; 866 | let mut limit = 0; 867 | let mut attr = 0; 868 | 869 | cpu_get_seg( 870 | self.handle, 871 | s as _, 872 | &mut present, 873 | &mut selector, 874 | &mut base, 875 | &mut limit, 876 | &mut attr, 877 | ); 878 | 879 | Seg { 880 | present: present != 0, 881 | selector, 882 | base, 883 | limit, 884 | attr, 885 | } 886 | } 887 | } 888 | 889 | unsafe fn set_seg(&self, s: SegRegs, v: Seg) { 890 | unsafe { 891 | cpu_set_seg( 892 | self.handle, 893 | s as _, 894 | v.present as _, 895 | v.selector, 896 | v.base, 897 | v.limit, 898 | v.attr, 899 | ) 900 | } 901 | } 902 | 903 | pub unsafe fn es(&self) -> Seg { 904 | unsafe { self.seg(SegRegs::Es) } 905 | } 906 | 907 | pub unsafe fn set_es(&self, v: Seg) { 908 | unsafe { 909 | self.set_seg(SegRegs::Es, v); 910 | } 911 | } 912 | 913 | pub unsafe fn cs(&self) -> Seg { 914 | unsafe { self.seg(SegRegs::Cs) } 915 | } 916 | 917 | pub unsafe fn set_cs(&self, v: Seg) { 918 | unsafe { 919 | if self.cs() != v { 920 | self.set_seg(SegRegs::Cs, v); 921 | self.set_mode(); 922 | } 923 | } 924 | } 925 | 926 | /// This function does not update the cpu mode after setting CS. This is 927 | /// needed as during cpu init, if efer isn't yet populated the cpu will not 928 | /// know that long mode might be active and change the state. 929 | pub unsafe fn set_cs_deferred(&self, v: Seg) -> bool { 930 | unsafe { 931 | let old_cs = self.cs(); 932 | 933 | self.set_seg(SegRegs::Cs, v); 934 | 935 | old_cs != v 936 | } 937 | } 938 | 939 | pub unsafe fn ss(&self) -> Seg { 940 | unsafe { self.seg(SegRegs::Ss) } 941 | } 942 | 943 | pub unsafe fn set_ss(&self, v: Seg) { 944 | unsafe { 945 | self.set_seg(SegRegs::Ss, v); 946 | } 947 | } 948 | 949 | pub unsafe fn ds(&self) -> Seg { 950 | unsafe { self.seg(SegRegs::Ds) } 951 | } 952 | 953 | pub unsafe fn set_ds(&self, v: Seg) { 954 | unsafe { 955 | self.set_seg(SegRegs::Ds, v); 956 | } 957 | } 958 | 959 | pub unsafe fn fs(&self) -> Seg { 960 | unsafe { self.seg(SegRegs::Fs) } 961 | } 962 | 963 | pub unsafe fn set_fs(&self, v: Seg) { 964 | unsafe { 965 | self.set_seg(SegRegs::Fs, v); 966 | } 967 | } 968 | 969 | pub unsafe fn gs(&self) -> Seg { 970 | unsafe { self.seg(SegRegs::Gs) } 971 | } 972 | 973 | pub unsafe fn set_gs(&self, v: Seg) { 974 | unsafe { 975 | self.set_seg(SegRegs::Gs, v); 976 | } 977 | } 978 | 979 | pub unsafe fn ldtr(&self) -> Seg { 980 | unsafe { 981 | let mut present = 0; 982 | let mut selector = 0; 983 | let mut base = 0; 984 | let mut limit = 0; 985 | let mut attr = 0; 986 | 987 | cpu_get_ldtr( 988 | self.handle, 989 | &mut present, 990 | &mut selector, 991 | &mut base, 992 | &mut limit, 993 | &mut attr, 994 | ); 995 | 996 | Seg { 997 | present: present != 0, 998 | selector, 999 | base, 1000 | limit, 1001 | attr, 1002 | } 1003 | } 1004 | } 1005 | 1006 | pub unsafe fn set_ldtr(&self, v: Seg) { 1007 | unsafe { 1008 | cpu_set_ldtr( 1009 | self.handle, 1010 | v.present as _, 1011 | v.selector, 1012 | v.base, 1013 | v.limit, 1014 | v.attr, 1015 | ) 1016 | } 1017 | } 1018 | 1019 | pub unsafe fn tr(&self) -> Seg { 1020 | unsafe { 1021 | let mut present = 0; 1022 | let mut selector = 0; 1023 | let mut base = 0; 1024 | let mut limit = 0; 1025 | let mut attr = 0; 1026 | 1027 | cpu_get_tr( 1028 | self.handle, 1029 | &mut present, 1030 | &mut selector, 1031 | &mut base, 1032 | &mut limit, 1033 | &mut attr, 1034 | ); 1035 | 1036 | Seg { 1037 | present: present != 0, 1038 | selector, 1039 | base, 1040 | limit, 1041 | attr, 1042 | } 1043 | } 1044 | } 1045 | 1046 | pub unsafe fn set_tr(&self, v: Seg) { 1047 | unsafe { 1048 | cpu_set_tr( 1049 | self.handle, 1050 | v.present as _, 1051 | v.selector, 1052 | v.base, 1053 | v.limit, 1054 | v.attr, 1055 | ) 1056 | } 1057 | } 1058 | 1059 | pub unsafe fn gdtr(&self) -> GlobalSeg { 1060 | unsafe { 1061 | let mut base = 0; 1062 | let mut limit = 0; 1063 | 1064 | cpu_get_gdtr(self.handle, &mut base, &mut limit); 1065 | 1066 | GlobalSeg { base, limit } 1067 | } 1068 | } 1069 | 1070 | pub unsafe fn set_gdtr(&self, gdtr: GlobalSeg) { 1071 | unsafe { cpu_set_gdtr(self.handle, gdtr.base, gdtr.limit) } 1072 | } 1073 | 1074 | pub unsafe fn idtr(&self) -> GlobalSeg { 1075 | unsafe { 1076 | let mut base = 0; 1077 | let mut limit = 0; 1078 | 1079 | cpu_get_idtr(self.handle, &mut base, &mut limit); 1080 | 1081 | GlobalSeg { base, limit } 1082 | } 1083 | } 1084 | 1085 | pub unsafe fn set_idtr(&self, idtr: GlobalSeg) { 1086 | unsafe { cpu_set_idtr(self.handle, idtr.base, idtr.limit) } 1087 | } 1088 | 1089 | // debug registers 1090 | 1091 | pub unsafe fn dr0(&self) -> Address { 1092 | unsafe { cpu_get_dr(self.handle, DRegs::Dr0 as _) } 1093 | } 1094 | 1095 | pub unsafe fn set_dr0(&self, v: Address) { 1096 | unsafe { cpu_set_dr(self.handle, DRegs::Dr0 as _, v) } 1097 | } 1098 | 1099 | pub unsafe fn dr1(&self) -> Address { 1100 | unsafe { cpu_get_dr(self.handle, DRegs::Dr1 as _) } 1101 | } 1102 | 1103 | pub unsafe fn set_dr1(&self, v: Address) { 1104 | unsafe { cpu_set_dr(self.handle, DRegs::Dr1 as _, v) } 1105 | } 1106 | 1107 | pub unsafe fn dr2(&self) -> Address { 1108 | unsafe { cpu_get_dr(self.handle, DRegs::Dr2 as _) } 1109 | } 1110 | 1111 | pub unsafe fn set_dr2(&self, v: Address) { 1112 | unsafe { cpu_set_dr(self.handle, DRegs::Dr2 as _, v) } 1113 | } 1114 | 1115 | pub unsafe fn dr3(&self) -> Address { 1116 | unsafe { cpu_get_dr(self.handle, DRegs::Dr3 as _) } 1117 | } 1118 | 1119 | pub unsafe fn set_dr3(&self, v: Address) { 1120 | unsafe { cpu_set_dr(self.handle, DRegs::Dr3 as _, v) } 1121 | } 1122 | 1123 | pub unsafe fn dr6(&self) -> u32 { 1124 | unsafe { cpu_get_dr6(self.handle) } 1125 | } 1126 | 1127 | pub unsafe fn set_dr6(&self, v: u32) { 1128 | unsafe { cpu_set_dr6(self.handle, v) } 1129 | } 1130 | 1131 | pub unsafe fn dr7(&self) -> u32 { 1132 | unsafe { cpu_get_dr7(self.handle) } 1133 | } 1134 | 1135 | pub unsafe fn set_dr7(&self, v: u32) { 1136 | unsafe { cpu_set_dr7(self.handle, v) } 1137 | } 1138 | 1139 | // control registers 1140 | 1141 | pub unsafe fn cr0(&self) -> u32 { 1142 | unsafe { cpu_get_cr0(self.handle) } 1143 | } 1144 | 1145 | pub unsafe fn set_cr0(&self, v: u32) { 1146 | unsafe { 1147 | if self.cr0() != v { 1148 | cpu_set_cr0(self.handle, v); 1149 | self.set_mode(); 1150 | } 1151 | } 1152 | } 1153 | 1154 | pub unsafe fn cr2(&self) -> Address { 1155 | unsafe { cpu_get_cr2(self.handle) } 1156 | } 1157 | 1158 | pub unsafe fn set_cr2(&self, v: Address) { 1159 | unsafe { cpu_set_cr2(self.handle, v) } 1160 | } 1161 | 1162 | pub unsafe fn cr3(&self) -> Address { 1163 | unsafe { cpu_get_cr3(self.handle) } 1164 | } 1165 | 1166 | pub unsafe fn set_cr3(&self, v: Address) { 1167 | unsafe { cpu_set_cr3(self.handle, v) } 1168 | } 1169 | 1170 | pub unsafe fn cr4(&self) -> u32 { 1171 | unsafe { cpu_get_cr4(self.handle) } 1172 | } 1173 | 1174 | pub unsafe fn set_cr4(&self, v: u32) { 1175 | unsafe { cpu_set_cr4(self.handle, v) } 1176 | } 1177 | 1178 | pub unsafe fn cr8(&self) -> u64 { 1179 | unsafe { cpu_get_cr8(self.handle) as _ } 1180 | } 1181 | 1182 | pub unsafe fn set_cr8(&self, v: u64) { 1183 | unsafe { cpu_set_cr8(self.handle, v as _) } 1184 | } 1185 | 1186 | pub unsafe fn efer(&self) -> u32 { 1187 | unsafe { cpu_get_efer(self.handle) } 1188 | } 1189 | 1190 | pub unsafe fn set_efer(&self, v: u32) { 1191 | unsafe { 1192 | if self.efer() != v { 1193 | cpu_set_efer(self.handle, v); 1194 | self.set_mode(); 1195 | } 1196 | } 1197 | } 1198 | 1199 | /// Update the internal bochs cpu mode 1200 | /// 1201 | /// This corresponds to the bochs function `handleCpuModeChange()`, and is 1202 | /// implicitly called via `set_cs`, `set_cr0`, or `set_efer`. By my 1203 | /// understanding, these are the only functions which can result in a cpu 1204 | /// mode change, but the function is exposed in case I've missed some. If 1205 | /// you find some context where you need to call it, please file a bug. 1206 | pub unsafe fn set_mode(&self) { 1207 | unsafe { cpu_set_mode(self.handle) } 1208 | } 1209 | 1210 | pub unsafe fn xcr0(&self) -> u32 { 1211 | unsafe { cpu_get_xcr0(self.handle) } 1212 | } 1213 | 1214 | pub unsafe fn set_xcr0(&self, v: u32) { 1215 | unsafe { cpu_set_xcr0(self.handle, v) } 1216 | } 1217 | 1218 | // msrs 1219 | 1220 | pub unsafe fn kernel_gs_base(&self) -> u64 { 1221 | unsafe { cpu_get_kernel_gs_base(self.handle) } 1222 | } 1223 | 1224 | pub unsafe fn set_kernel_gs_base(&self, v: u64) { 1225 | unsafe { cpu_set_kernel_gs_base(self.handle, v) } 1226 | } 1227 | 1228 | pub unsafe fn sysenter_cs(&self) -> u64 { 1229 | unsafe { cpu_get_sysenter_cs(self.handle) as _ } 1230 | } 1231 | 1232 | pub unsafe fn set_sysenter_cs(&self, v: u64) { 1233 | unsafe { cpu_set_sysenter_cs(self.handle, v as _) } 1234 | } 1235 | 1236 | pub unsafe fn sysenter_eip(&self) -> Address { 1237 | unsafe { cpu_get_sysenter_eip(self.handle) } 1238 | } 1239 | 1240 | pub unsafe fn set_sysenter_eip(&self, v: Address) { 1241 | unsafe { cpu_set_sysenter_eip(self.handle, v) } 1242 | } 1243 | 1244 | pub unsafe fn sysenter_esp(&self) -> Address { 1245 | unsafe { cpu_get_sysenter_esp(self.handle) } 1246 | } 1247 | 1248 | pub unsafe fn set_sysenter_esp(&self, v: Address) { 1249 | unsafe { cpu_set_sysenter_esp(self.handle, v) } 1250 | } 1251 | 1252 | pub unsafe fn star(&self) -> u64 { 1253 | unsafe { cpu_get_star(self.handle) } 1254 | } 1255 | 1256 | pub unsafe fn set_star(&self, v: u64) { 1257 | unsafe { cpu_set_star(self.handle, v) } 1258 | } 1259 | 1260 | pub unsafe fn lstar(&self) -> u64 { 1261 | unsafe { cpu_get_lstar(self.handle) } 1262 | } 1263 | 1264 | pub unsafe fn set_lstar(&self, v: u64) { 1265 | unsafe { cpu_set_lstar(self.handle, v) } 1266 | } 1267 | 1268 | pub unsafe fn cstar(&self) -> u64 { 1269 | unsafe { cpu_get_cstar(self.handle) } 1270 | } 1271 | 1272 | pub unsafe fn set_cstar(&self, v: u64) { 1273 | unsafe { cpu_set_cstar(self.handle, v) } 1274 | } 1275 | 1276 | pub unsafe fn sfmask(&self) -> u64 { 1277 | unsafe { cpu_get_fmask(self.handle) as _ } 1278 | } 1279 | 1280 | pub unsafe fn set_sfmask(&self, v: u64) { 1281 | unsafe { cpu_set_fmask(self.handle, v as _) } 1282 | } 1283 | 1284 | pub unsafe fn tsc(&self) -> u64 { 1285 | unsafe { cpu_get_tsc(self.handle) } 1286 | } 1287 | 1288 | pub unsafe fn set_tsc(&self, v: u64) { 1289 | unsafe { cpu_set_tsc(self.handle, v) } 1290 | } 1291 | 1292 | pub unsafe fn apic_base(&self) -> PhyAddress { 1293 | unsafe { cpu_get_apicbase(self.handle) } 1294 | } 1295 | 1296 | pub unsafe fn set_apic_base(&self, v: PhyAddress) { 1297 | unsafe { cpu_set_apicbase(self.handle, v) } 1298 | } 1299 | 1300 | pub unsafe fn pat(&self) -> u64 { 1301 | unsafe { cpu_get_pat(self.handle) } 1302 | } 1303 | 1304 | pub unsafe fn set_pat(&self, v: u64) { 1305 | unsafe { cpu_set_pat(self.handle, v) } 1306 | } 1307 | 1308 | pub unsafe fn tsc_aux(&self) -> u64 { 1309 | unsafe { cpu_get_tsc_aux(self.handle) as _ } 1310 | } 1311 | 1312 | pub unsafe fn set_tsc_aux(&self, v: u64) { 1313 | unsafe { cpu_set_tsc_aux(self.handle, v as _) } 1314 | } 1315 | 1316 | pub unsafe fn cet_control_u(&self) -> u64 { 1317 | unsafe { cpu_get_cet_control_u(self.handle) } 1318 | } 1319 | 1320 | pub unsafe fn set_cet_control_u(&self, v: u64) { 1321 | unsafe { cpu_set_cet_control_u(self.handle, v) } 1322 | } 1323 | 1324 | pub unsafe fn cet_control_s(&self) -> u64 { 1325 | unsafe { cpu_get_cet_control_s(self.handle) } 1326 | } 1327 | 1328 | pub unsafe fn set_cet_control_s(&self, v: u64) { 1329 | unsafe { cpu_set_cet_control_s(self.handle, v) } 1330 | } 1331 | 1332 | pub unsafe fn pl0_ssp(&self) -> u64 { 1333 | unsafe { cpu_get_pl0_ssp(self.handle) } 1334 | } 1335 | 1336 | pub unsafe fn set_pl0_ssp(&self, v: u64) { 1337 | unsafe { cpu_set_pl0_ssp(self.handle, v) } 1338 | } 1339 | 1340 | pub unsafe fn pl1_ssp(&self) -> u64 { 1341 | unsafe { cpu_get_pl1_ssp(self.handle) } 1342 | } 1343 | 1344 | pub unsafe fn set_pl1_ssp(&self, v: u64) { 1345 | unsafe { cpu_set_pl1_ssp(self.handle, v) } 1346 | } 1347 | 1348 | pub unsafe fn pl2_ssp(&self) -> u64 { 1349 | unsafe { cpu_get_pl2_ssp(self.handle) } 1350 | } 1351 | 1352 | pub unsafe fn set_pl2_ssp(&self, v: u64) { 1353 | unsafe { cpu_set_pl2_ssp(self.handle, v) } 1354 | } 1355 | 1356 | pub unsafe fn pl3_ssp(&self) -> u64 { 1357 | unsafe { cpu_get_pl3_ssp(self.handle) } 1358 | } 1359 | 1360 | pub unsafe fn set_pl3_ssp(&self, v: u64) { 1361 | unsafe { cpu_set_pl3_ssp(self.handle, v) } 1362 | } 1363 | 1364 | pub unsafe fn interrupt_ssp_table(&self) -> u64 { 1365 | unsafe { cpu_get_interrupt_ssp_table(self.handle) } 1366 | } 1367 | 1368 | pub unsafe fn set_interrupt_ssp_table(&self, v: u64) { 1369 | unsafe { cpu_set_interrupt_ssp_table(self.handle, v) } 1370 | } 1371 | 1372 | // TODO mtrrphys? 1373 | 1374 | // zmm 1375 | 1376 | pub unsafe fn zmm(&self, idx: usize) -> Zmm { 1377 | unsafe { 1378 | assert!(idx < 32); 1379 | let mut v = Zmm { q: [0; 8] }; 1380 | cpu_get_zmm(self.handle, idx as _, &mut v.q as *mut _ as *mut u64); 1381 | 1382 | v 1383 | } 1384 | } 1385 | 1386 | pub unsafe fn set_zmm(&self, idx: usize, v: Zmm) { 1387 | unsafe { 1388 | assert!(idx < 32); 1389 | cpu_set_zmm(self.handle, idx as _, &v.q as *const _ as *const u64) 1390 | } 1391 | } 1392 | 1393 | pub unsafe fn mxcsr(&self) -> u32 { 1394 | unsafe { cpu_get_mxcsr(self.handle) } 1395 | } 1396 | 1397 | pub unsafe fn set_mxcsr(&self, v: u32) { 1398 | unsafe { cpu_set_mxcsr(self.handle, v) } 1399 | } 1400 | 1401 | pub unsafe fn mxcsr_mask(&self) -> u32 { 1402 | unsafe { cpu_get_mxcsr_mask(self.handle) } 1403 | } 1404 | 1405 | pub unsafe fn set_mxcsr_mask(&self, v: u32) { 1406 | unsafe { cpu_set_mxcsr_mask(self.handle, v) } 1407 | } 1408 | 1409 | // FP 1410 | 1411 | pub unsafe fn fp_cw(&self) -> u16 { 1412 | unsafe { cpu_get_fp_cw(self.handle) } 1413 | } 1414 | 1415 | pub unsafe fn set_fp_cw(&self, v: u16) { 1416 | unsafe { cpu_set_fp_cw(self.handle, v) } 1417 | } 1418 | 1419 | pub unsafe fn fp_sw(&self) -> u16 { 1420 | unsafe { cpu_get_fp_sw(self.handle) } 1421 | } 1422 | 1423 | pub unsafe fn set_fp_sw(&self, v: u16) { 1424 | unsafe { cpu_set_fp_sw(self.handle, v) } 1425 | } 1426 | 1427 | pub unsafe fn fp_tw(&self) -> u16 { 1428 | unsafe { cpu_get_fp_tw(self.handle) } 1429 | } 1430 | 1431 | pub unsafe fn set_fp_tw(&self, v: u16) { 1432 | unsafe { cpu_set_fp_tw(self.handle, v) } 1433 | } 1434 | 1435 | pub unsafe fn fp_op(&self) -> u16 { 1436 | unsafe { cpu_get_fp_op(self.handle) } 1437 | } 1438 | 1439 | pub unsafe fn set_fp_op(&self, v: u16) { 1440 | unsafe { cpu_set_fp_op(self.handle, v) } 1441 | } 1442 | 1443 | pub unsafe fn fp_st(&self, idx: usize) -> Float80 { 1444 | unsafe { 1445 | assert!(idx < 8); 1446 | let mut v = Float80::default(); 1447 | cpu_get_fp_st(self.handle, idx as _, &mut v.fraction, &mut v.exp); 1448 | 1449 | v 1450 | } 1451 | } 1452 | 1453 | pub unsafe fn set_fp_st(&self, idx: usize, v: Float80) { 1454 | unsafe { 1455 | assert!(idx < 8); 1456 | cpu_set_fp_st(self.handle, idx as _, v.fraction, v.exp); 1457 | } 1458 | } 1459 | } 1460 | --------------------------------------------------------------------------------