Overview
The CPU module provides ARM64 CPU emulation using the Unicorn Engine. It supports both single-core and multi-core configurations with shared memory.
UnicornCPU
Safe wrapper for the Unicorn CPU emulator that provides ARM64 emulation with thread-safe access.
Structure
pub struct UnicornCPU {
emu : Arc < Mutex < Unicorn <' static , ()>>>,
pub core_id : u32 ,
}
emu
Arc<Mutex<Unicorn<'static, ()>>>
Thread-safe reference to the Unicorn emulator instance
Unique identifier for this CPU core (0-7 in multi-core mode)
Constructor Methods
new()
Create a new Unicorn instance with 8MB of memory for legacy/test mode.
pub fn new () -> Option < Self >
Returns Some(UnicornCPU) on success, None if initialization fails
Example:
use oboromi_core :: cpu :: UnicornCPU ;
let cpu = UnicornCPU :: new () . expect ( "Failed to create CPU" );
cpu . set_pc ( 0x1000 );
cpu . set_x ( 0 , 42 );
new_with_shared_mem()
Create a new Unicorn instance with shared memory across multiple cores.
pub unsafe fn new_with_shared_mem (
core_id : u32 ,
memory_ptr : * mut u8 ,
memory_size : u64
) -> Option < Self >
Unique identifier for this core (used for stack allocation)
Pointer to shared memory region
Size of the memory region in bytes
Safety: The caller must ensure memory_ptr is valid for the lifetime of this CPU and has at least memory_size bytes.
Example:
use oboromi_core :: cpu :: UnicornCPU ;
let memory = vec! [ 0 u8 ; 12 * 1024 * 1024 * 1024 ] . into_boxed_slice ();
let memory_ptr = memory . as_ptr () as * mut u8 ;
unsafe {
let cpu = UnicornCPU :: new_with_shared_mem ( 0 , memory_ptr , memory . len () as u64 )
. expect ( "Failed to create CPU with shared memory" );
}
Execution Control
run()
Run the core until halt or breakpoint (BRK instruction).
Returns 1 on success (normal completion or BRK), 0 on emulation error
Example:
cpu . set_pc ( 0x1000 );
cpu . write_u32 ( 0x1000 , 0xD503201F ); // NOP
cpu . write_u32 ( 0x1004 , 0xD4200000 ); // BRK #0
let result = cpu . run ();
assert_eq! ( result , 1 ); // Success
step()
Execute a single instruction.
pub fn step ( & self ) -> u64
Returns 0 on success, 1 on error
halt()
Halt execution immediately.
Register Access
get_x() / set_x()
Read or write general-purpose registers X0-X30.
pub fn get_x ( & self , reg_index : u32 ) -> u64
pub fn set_x ( & self , reg_index : u32 , value : u64 )
Register index (0-30). Returns 0 if index is invalid.
Value to write to the register
Example:
cpu . set_x ( 0 , 100 );
cpu . set_x ( 1 , 50 );
// Execute: ADD X0, X0, X1
let result = cpu . get_x ( 0 ); // 150
get_sp() / set_sp()
Read or write the stack pointer.
pub fn get_sp ( & self ) -> u64
pub fn set_sp ( & self , value : u64 )
Example:
cpu . set_sp ( 0x8000 );
let sp = cpu . get_sp ();
get_pc() / set_pc()
Read or write the program counter.
pub fn get_pc ( & self ) -> u64
pub fn set_pc ( & self , value : u64 )
Example:
cpu . set_pc ( 0x1000 ); // Jump to address 0x1000
cpu . run ();
let final_pc = cpu . get_pc ();
Memory Access
write_u32() / read_u32()
Write or read 32-bit values from emulated memory.
pub fn write_u32 ( & self , vaddr : u64 , value : u32 )
pub fn read_u32 ( & self , vaddr : u64 ) -> u32
Virtual address to access
32-bit value to write (little-endian)
Example:
cpu . write_u32 ( 0x2000 , 0xDEADBEEF );
let value = cpu . read_u32 ( 0x2000 );
assert_eq! ( value , 0xDEADBEEF );
write_u64() / read_u64()
Write or read 64-bit values from emulated memory.
pub fn write_u64 ( & self , vaddr : u64 , value : u64 )
pub fn read_u64 ( & self , vaddr : u64 ) -> u64
Virtual address to access
64-bit value to write (little-endian)
Example:
cpu . write_u64 ( 0x3000 , 0xCAFEBABEDEADBEEF );
let value = cpu . read_u64 ( 0x3000 );
assert_eq! ( value , 0xCAFEBABEDEADBEEF );
CpuManager
Manages multiple CPU cores with shared memory for multi-core emulation.
Structure
pub struct CpuManager {
pub cores : Vec < UnicornCPU >,
pub shared_memory : Pin < Box <[ u8 ]>>,
}
Vector of 8 CPU cores sharing the same memory
Pinned 12GB shared memory region (prevents reallocation)
Constants
pub const CORE_COUNT : usize = 8 ;
pub const MEMORY_SIZE : u64 = 12 * 1024 * 1024 * 1024 ; // 12GB
pub const MEMORY_BASE : u64 = 0x0 ;
Methods
new()
Create a new CPU manager with 8 cores and 12GB of shared memory.
Memory is lazily allocated by modern operating systems using virtual memory, so physical RAM is only consumed when written to.
Example:
use oboromi_core :: cpu :: cpu_manager :: CpuManager ;
let manager = CpuManager :: new ();
assert_eq! ( manager . cores . len (), 8 );
get_core()
Get a reference to a specific CPU core.
pub fn get_core ( & self , id : usize ) -> Option < & UnicornCPU >
Example:
let manager = CpuManager :: new ();
let core0 = manager . get_core ( 0 ) . unwrap ();
let core1 = manager . get_core ( 1 ) . unwrap ();
// Write with core 0
core0 . write_u32 ( 0x1000 , 0xDEADBEEF );
// Read with core 1 (shared memory!)
let value = core1 . read_u32 ( 0x1000 );
assert_eq! ( value , 0xDEADBEEF );
run_all()
Execute one step on all cores sequentially (round-robin scheduling).
Currently runs cores sequentially. Future versions will support threaded execution.
Thread Safety
UnicornCPU implements Send and Sync, making it safe to share across threads:
unsafe impl Send for UnicornCPU {}
unsafe impl Sync for UnicornCPU {}
This allows multiple cores to be executed in parallel while sharing the same memory space.
Complete Example
Multi-core ARM64 Program Execution
use oboromi_core :: cpu :: cpu_manager :: CpuManager ;
fn main () {
// Initialize 8-core system with 12GB RAM
let manager = CpuManager :: new ();
// Get two cores
let core0 = manager . get_core ( 0 ) . unwrap ();
let core1 = manager . get_core ( 1 ) . unwrap ();
// ARM64 Instructions
let nop = 0xD503201F ; // NOP
let add = 0x91000400 ; // ADD X0, X0, #1
let brk = 0xD4200000 ; // BRK #0
// Program for Core 0
let mut addr = 0x1000 ;
core0 . write_u32 ( addr , add );
addr += 4 ;
core0 . write_u32 ( addr , add );
addr += 4 ;
core0 . write_u32 ( addr , brk );
// Set up Core 0
core0 . set_pc ( 0x1000 );
core0 . set_sp ( 0x8000 );
core0 . set_x ( 0 , 100 );
// Execute on Core 0
core0 . run ();
// Check result
let result = core0 . get_x ( 0 );
println! ( "Core 0: X0 = {}" , result ); // 102
// Core 1 can see memory written by Core 0
let shared_val = core1 . read_u32 ( 0x1000 );
println! ( "Core 1 sees instruction: {:#010x}" , shared_val );
}
See Also