mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-18 19:23:56 +00:00
629 lines
20 KiB
Rust
629 lines
20 KiB
Rust
use icicle_cpu::ExceptionCode;
|
|
use icicle_cpu::ValueSource;
|
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
|
|
|
use crate::registers;
|
|
|
|
fn create_x64_vm() -> icicle_vm::Vm {
|
|
let mut cpu_config = icicle_vm::cpu::Config::from_target_triple("x86_64-none");
|
|
cpu_config.enable_jit = true;
|
|
cpu_config.enable_jit_mem = true;
|
|
cpu_config.enable_shadow_stack = false;
|
|
cpu_config.enable_recompilation = true;
|
|
cpu_config.track_uninitialized = false;
|
|
cpu_config.optimize_instructions = true;
|
|
cpu_config.optimize_block = false;
|
|
|
|
return icicle_vm::build(&cpu_config).unwrap();
|
|
}
|
|
|
|
const FOREIGN_READ: u8 = 1 << 0;
|
|
const FOREIGN_WRITE: u8 = 1 << 1;
|
|
const FOREIGN_EXEC: u8 = 1 << 2;
|
|
|
|
fn map_permissions(foreign_permissions: u8) -> u8 {
|
|
let mut permissions: u8 = 0;
|
|
|
|
if (foreign_permissions & FOREIGN_READ) != 0 {
|
|
permissions |= icicle_vm::cpu::mem::perm::READ;
|
|
}
|
|
|
|
if (foreign_permissions & FOREIGN_WRITE) != 0 {
|
|
permissions |= icicle_vm::cpu::mem::perm::WRITE;
|
|
}
|
|
|
|
if (foreign_permissions & FOREIGN_EXEC) != 0 {
|
|
permissions |= icicle_vm::cpu::mem::perm::EXEC;
|
|
}
|
|
|
|
return permissions;
|
|
}
|
|
|
|
#[repr(u8)]
|
|
#[allow(dead_code)]
|
|
#[derive(PartialEq)]
|
|
enum HookType {
|
|
Syscall = 1,
|
|
Read,
|
|
Write,
|
|
ExecuteGeneric,
|
|
ExecuteSpecific,
|
|
Violation,
|
|
Unknown,
|
|
}
|
|
|
|
fn u8_to_hook_type_unsafe(value: u8) -> HookType {
|
|
unsafe { std::mem::transmute(value) }
|
|
}
|
|
|
|
fn split_hook_id(id: u32) -> (u32, HookType) {
|
|
let hook_id = id & 0xFFFFFF;
|
|
let hook_type = u8_to_hook_type_unsafe((id >> 24) as u8);
|
|
|
|
return (hook_id, hook_type);
|
|
}
|
|
|
|
fn qualify_hook_id(hook_id: u32, hook_type: HookType) -> u32 {
|
|
let hook_type: u32 = (hook_type as u8).into();
|
|
let hook_type_mask: u32 = hook_type << 24;
|
|
return (hook_id | hook_type_mask).into();
|
|
}
|
|
|
|
pub struct HookContainer<Func: ?Sized> {
|
|
hook_id: u32,
|
|
hooks: HashMap<u32, Box<Func>>,
|
|
}
|
|
|
|
impl<Func: ?Sized> HookContainer<Func> {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
hook_id: 0,
|
|
hooks: HashMap::new(),
|
|
}
|
|
}
|
|
|
|
pub fn add_hook(&mut self, callback: Box<Func>) -> u32 {
|
|
self.hook_id += 1;
|
|
let id = self.hook_id;
|
|
self.hooks.insert(id, callback);
|
|
|
|
return id;
|
|
}
|
|
|
|
pub fn get_hooks(&self) -> &HashMap<u32, Box<Func>> {
|
|
return &self.hooks;
|
|
}
|
|
|
|
pub fn remove_hook(&mut self, id: u32) {
|
|
self.hooks.remove(&id);
|
|
}
|
|
}
|
|
|
|
struct InstructionHookInjector {
|
|
hook: pcode::HookId,
|
|
}
|
|
|
|
impl icicle_vm::CodeInjector for InstructionHookInjector {
|
|
fn inject(
|
|
&mut self,
|
|
_cpu: &mut icicle_vm::cpu::Cpu,
|
|
group: &icicle_vm::cpu::BlockGroup,
|
|
code: &mut icicle_vm::BlockTable,
|
|
) {
|
|
for id in group.range() {
|
|
let block = &mut code.blocks[id];
|
|
|
|
let mut tmp_block = pcode::Block::new();
|
|
tmp_block.next_tmp = block.pcode.next_tmp;
|
|
|
|
for stmt in block.pcode.instructions.drain(..) {
|
|
tmp_block.push(stmt);
|
|
if let pcode::Op::InstructionMarker = stmt.op {
|
|
tmp_block.push(pcode::Op::Hook(self.hook));
|
|
code.modified.insert(id);
|
|
}
|
|
}
|
|
|
|
std::mem::swap(&mut tmp_block.instructions, &mut block.pcode.instructions);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct ExecutionHooks {
|
|
vm_ptr: *mut icicle_vm::Vm,
|
|
skip_ip: Option<u64>,
|
|
stop: Rc<RefCell<bool>>,
|
|
generic_hooks: HookContainer<dyn Fn(u64)>,
|
|
specific_hooks: HookContainer<dyn Fn(u64)>,
|
|
address_mapping: HashMap<u64, Vec<u32>>,
|
|
}
|
|
|
|
impl ExecutionHooks {
|
|
pub fn new(stop_value: Rc<RefCell<bool>>, vm: &mut icicle_vm::Vm) -> Self {
|
|
Self {
|
|
vm_ptr: vm as *mut icicle_vm::Vm,
|
|
skip_ip: None,
|
|
stop: stop_value,
|
|
generic_hooks: HookContainer::new(),
|
|
specific_hooks: HookContainer::new(),
|
|
address_mapping: HashMap::new(),
|
|
}
|
|
}
|
|
|
|
fn run_hooks(&self, address: u64) {
|
|
for (_key, func) in self.generic_hooks.get_hooks() {
|
|
func(address);
|
|
}
|
|
|
|
let mapping = self.address_mapping.get(&address);
|
|
if mapping.is_none(){
|
|
return;
|
|
}
|
|
|
|
for id in mapping.unwrap() {
|
|
let func = self.specific_hooks.get_hooks().get(&id);
|
|
if func.is_some() {
|
|
func.unwrap()(address);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn execute(&mut self,cpu: &mut icicle_cpu::Cpu, address: u64) {
|
|
let mut skip = false;
|
|
if self.skip_ip.is_some() {
|
|
skip = self.skip_ip.unwrap() == address;
|
|
self.skip_ip = None;
|
|
|
|
// TODO: Get rid of that
|
|
unsafe {
|
|
let vm = &mut *self.vm_ptr;
|
|
vm.icount_limit = vm.icount_limit.saturating_sub(1);
|
|
vm.next_timer = vm.next_timer.saturating_sub(1);
|
|
}
|
|
}
|
|
|
|
if !skip {
|
|
self.run_hooks(address);
|
|
}
|
|
|
|
if *self.stop.borrow() {
|
|
self.skip_ip = Some(address);
|
|
cpu.exception.code = ExceptionCode::InstructionLimit as u32;
|
|
cpu.exception.value = address;
|
|
}
|
|
}
|
|
|
|
pub fn add_generic_hook(&mut self, callback: Box<dyn Fn(u64)>) -> u32 {
|
|
self.generic_hooks.add_hook(callback)
|
|
}
|
|
|
|
pub fn add_specific_hook(&mut self, address: u64, callback: Box<dyn Fn(u64)>) -> u32 {
|
|
let id = self.specific_hooks.add_hook(callback);
|
|
|
|
let mapping = self.address_mapping.entry(address).or_insert_with(Vec::new);
|
|
mapping.push(id);
|
|
|
|
return id;
|
|
}
|
|
|
|
pub fn remove_generic_hook(&mut self, id: u32) {
|
|
self.generic_hooks.remove_hook(id);
|
|
}
|
|
|
|
pub fn remove_specific_hook(&mut self, id: u32) {
|
|
self.address_mapping.retain(|_, vec| {
|
|
vec.retain(|&x| x != id);
|
|
!vec.is_empty()
|
|
});
|
|
|
|
self.specific_hooks.remove_hook(id);
|
|
}
|
|
}
|
|
|
|
pub struct IcicleEmulator {
|
|
executing_thread: std::thread::ThreadId,
|
|
vm: Box<icicle_vm::Vm>,
|
|
reg: registers::X64RegisterNodes,
|
|
syscall_hooks: HookContainer<dyn Fn()>,
|
|
violation_hooks: HookContainer<dyn Fn(u64, u8, bool) -> bool>,
|
|
execution_hooks: Rc<RefCell<ExecutionHooks>>,
|
|
stop: Rc<RefCell<bool>>,
|
|
}
|
|
|
|
struct MemoryHook {
|
|
callback: Box<dyn Fn(u64, &[u8])>,
|
|
}
|
|
|
|
impl icicle_cpu::mem::WriteHook for MemoryHook {
|
|
fn write(&mut self, _mem: &mut icicle_cpu::Mmu, addr: u64, value: &[u8]) {
|
|
(self.callback)(addr, value);
|
|
}
|
|
}
|
|
|
|
impl icicle_cpu::mem::ReadAfterHook for MemoryHook {
|
|
fn read(&mut self, _mem: &mut icicle_cpu::Mmu, addr: u64, value: &[u8]) {
|
|
(self.callback)(addr, value);
|
|
}
|
|
}
|
|
|
|
pub struct MmioHandler {
|
|
read_handler: Box<dyn Fn(u64, &mut [u8])>,
|
|
write_handler: Box<dyn Fn(u64, &[u8])>,
|
|
}
|
|
|
|
impl MmioHandler {
|
|
pub fn new(
|
|
read_function: Box<dyn Fn(u64, &mut [u8])>,
|
|
write_function: Box<dyn Fn(u64, &[u8])>,
|
|
) -> Self {
|
|
Self {
|
|
read_handler: read_function,
|
|
write_handler: write_function,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl icicle_cpu::mem::IoMemory for MmioHandler {
|
|
fn read(&mut self, addr: u64, buf: &mut [u8]) -> icicle_cpu::mem::MemResult<()> {
|
|
(self.read_handler)(addr, buf);
|
|
return Ok(());
|
|
}
|
|
|
|
fn write(&mut self, addr: u64, value: &[u8]) -> icicle_cpu::mem::MemResult<()> {
|
|
(self.write_handler)(addr, value);
|
|
return Ok(());
|
|
}
|
|
}
|
|
|
|
impl IcicleEmulator {
|
|
pub fn new() -> Self {
|
|
let mut virtual_machine = Box::new(create_x64_vm());
|
|
let stop_value = Rc::new(RefCell::new(false));
|
|
let exec_hooks = Rc::new(RefCell::new(ExecutionHooks::new(stop_value.clone(), &mut virtual_machine)));
|
|
|
|
let exec_hooks_clone = Rc::clone(&exec_hooks);
|
|
|
|
let hook = icicle_cpu::InstHook::new(move |cpu: &mut icicle_cpu::Cpu, addr: u64| {
|
|
exec_hooks_clone.borrow_mut().execute(cpu, addr);
|
|
});
|
|
|
|
let hook = virtual_machine.cpu.add_hook(hook);
|
|
virtual_machine.add_injector(InstructionHookInjector { hook });
|
|
|
|
Self {
|
|
stop: stop_value,
|
|
executing_thread: std::thread::current().id(),
|
|
reg: registers::X64RegisterNodes::new(&virtual_machine.cpu.arch),
|
|
vm: virtual_machine,
|
|
syscall_hooks: HookContainer::new(),
|
|
violation_hooks: HookContainer::new(),
|
|
execution_hooks: exec_hooks,
|
|
}
|
|
}
|
|
|
|
fn get_mem(&mut self) -> &mut icicle_vm::cpu::Mmu {
|
|
return &mut self.vm.cpu.mem;
|
|
}
|
|
|
|
pub fn start(&mut self, count: u64) {
|
|
self.executing_thread = std::thread::current().id();
|
|
*self.stop.borrow_mut() = false;
|
|
|
|
self.vm.icount_limit = match count {
|
|
0 => u64::MAX,
|
|
_ => self.vm.cpu.icount.saturating_add(count),
|
|
};
|
|
|
|
loop {
|
|
let reason = self.vm.run();
|
|
|
|
match reason {
|
|
icicle_vm::VmExit::InstructionLimit => break,
|
|
icicle_vm::VmExit::UnhandledException((code, value)) => {
|
|
let continue_execution = self.handle_exception(code, value);
|
|
if !continue_execution {
|
|
break;
|
|
}
|
|
}
|
|
_ => break,
|
|
};
|
|
}
|
|
}
|
|
|
|
fn handle_exception(&mut self, code: ExceptionCode, value: u64) -> bool {
|
|
let continue_execution = match code {
|
|
ExceptionCode::Syscall => self.handle_syscall(),
|
|
ExceptionCode::ReadPerm => self.handle_violation(value, FOREIGN_READ, false),
|
|
ExceptionCode::WritePerm => self.handle_violation(value, FOREIGN_WRITE, false),
|
|
ExceptionCode::ReadUnmapped => self.handle_violation(value, FOREIGN_READ, true),
|
|
ExceptionCode::WriteUnmapped => self.handle_violation(value, FOREIGN_WRITE, true),
|
|
ExceptionCode::ExecViolation => self.handle_violation(value, FOREIGN_EXEC, true),
|
|
_ => false,
|
|
};
|
|
|
|
return continue_execution;
|
|
}
|
|
|
|
fn handle_violation(&mut self, address: u64, permission: u8, unmapped: bool) -> bool {
|
|
let hooks = &self.violation_hooks.get_hooks();
|
|
if hooks.is_empty() {
|
|
return false;
|
|
}
|
|
|
|
let mut continue_execution = true;
|
|
|
|
for (_key, func) in self.violation_hooks.get_hooks() {
|
|
continue_execution &= func(address, permission, unmapped);
|
|
}
|
|
|
|
return continue_execution;
|
|
}
|
|
|
|
fn handle_syscall(&mut self) -> bool {
|
|
for (_key, func) in self.syscall_hooks.get_hooks() {
|
|
func();
|
|
}
|
|
|
|
self.vm.cpu.write_pc(self.vm.cpu.read_pc() + 2);
|
|
return true;
|
|
}
|
|
|
|
pub fn stop(&mut self) {
|
|
self.vm.icount_limit = 0;
|
|
|
|
if self.executing_thread == std::thread::current().id() {
|
|
*self.stop.borrow_mut() = true;
|
|
}
|
|
}
|
|
|
|
pub fn add_violation_hook(&mut self, callback: Box<dyn Fn(u64, u8, bool) -> bool>) -> u32 {
|
|
let hook_id = self.violation_hooks.add_hook(callback);
|
|
return qualify_hook_id(hook_id, HookType::Violation);
|
|
}
|
|
|
|
pub fn add_execution_hook(&mut self, address:u64, callback: Box<dyn Fn(u64)>) -> u32 {
|
|
let hook_id = self.execution_hooks.borrow_mut().add_specific_hook(address, callback);
|
|
return qualify_hook_id(hook_id, HookType::ExecuteSpecific);
|
|
}
|
|
|
|
pub fn add_generic_execution_hook(&mut self, callback: Box<dyn Fn(u64)>) -> u32 {
|
|
let hook_id = self.execution_hooks.borrow_mut().add_generic_hook(callback);
|
|
return qualify_hook_id(hook_id, HookType::ExecuteGeneric);
|
|
}
|
|
|
|
pub fn add_syscall_hook(&mut self, callback: Box<dyn Fn()>) -> u32 {
|
|
let hook_id = self.syscall_hooks.add_hook(callback);
|
|
return qualify_hook_id(hook_id, HookType::Syscall);
|
|
}
|
|
|
|
pub fn add_read_hook(
|
|
&mut self,
|
|
start: u64,
|
|
end: u64,
|
|
callback: Box<dyn Fn(u64, &[u8])>,
|
|
) -> u32 {
|
|
let id = self.get_mem().add_read_after_hook(start, end, Box::new(MemoryHook { callback }));
|
|
if id.is_none() {
|
|
return 0;
|
|
}
|
|
|
|
return qualify_hook_id(id.unwrap(), HookType::Read);
|
|
}
|
|
|
|
pub fn add_write_hook(
|
|
&mut self,
|
|
start: u64,
|
|
end: u64,
|
|
callback: Box<dyn Fn(u64, &[u8])>,
|
|
) -> u32 {
|
|
let id = self.get_mem().add_write_hook(start, end, Box::new(MemoryHook { callback }));
|
|
if id.is_none() {
|
|
return 0;
|
|
}
|
|
|
|
return qualify_hook_id(id.unwrap(), HookType::Write);
|
|
}
|
|
|
|
pub fn remove_hook(&mut self, id: u32) {
|
|
let (hook_id, hook_type) = split_hook_id(id);
|
|
|
|
match hook_type {
|
|
HookType::Syscall => self.syscall_hooks.remove_hook(hook_id),
|
|
HookType::Violation => self.violation_hooks.remove_hook(hook_id),
|
|
HookType::ExecuteGeneric => self.execution_hooks.borrow_mut().remove_generic_hook(hook_id),
|
|
HookType::ExecuteSpecific => self.execution_hooks.borrow_mut().remove_specific_hook(hook_id),
|
|
HookType::Read => {self.get_mem().remove_read_after_hook(hook_id);()},
|
|
HookType::Write => {self.get_mem().remove_write_hook(hook_id);()},
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
pub fn map_memory(&mut self, address: u64, length: u64, permissions: u8) -> bool {
|
|
const MAPPING_PERMISSIONS: u8 = icicle_vm::cpu::mem::perm::MAP
|
|
| icicle_vm::cpu::mem::perm::INIT
|
|
| icicle_vm::cpu::mem::perm::IN_CODE_CACHE;
|
|
|
|
let native_permissions = map_permissions(permissions);
|
|
|
|
let mapping = icicle_vm::cpu::mem::Mapping {
|
|
perm: native_permissions | MAPPING_PERMISSIONS,
|
|
value: 0x0,
|
|
};
|
|
|
|
let layout = icicle_vm::cpu::mem::AllocLayout {
|
|
addr: Some(address),
|
|
size: length,
|
|
align: 0x1000,
|
|
};
|
|
|
|
let res = self.get_mem().alloc_memory(layout, mapping);
|
|
return res.is_ok();
|
|
}
|
|
|
|
pub fn map_mmio(
|
|
&mut self,
|
|
address: u64,
|
|
length: u64,
|
|
read_function: Box<dyn Fn(u64, &mut [u8])>,
|
|
write_function: Box<dyn Fn(u64, &[u8])>,
|
|
) -> bool {
|
|
let mem = self.get_mem();
|
|
|
|
let handler = MmioHandler::new(read_function, write_function);
|
|
let handler_id = mem.register_io_handler(handler);
|
|
|
|
let layout = icicle_vm::cpu::mem::AllocLayout {
|
|
addr: Some(address),
|
|
size: length,
|
|
align: 0x1000,
|
|
};
|
|
|
|
let res = mem.alloc_memory(layout, handler_id);
|
|
return res.is_ok();
|
|
}
|
|
|
|
pub fn unmap_memory(&mut self, address: u64, length: u64) -> bool {
|
|
return self.get_mem().unmap_memory_len(address, length);
|
|
}
|
|
|
|
pub fn protect_memory(&mut self, address: u64, length: u64, permissions: u8) -> bool {
|
|
let native_permissions = map_permissions(permissions);
|
|
let res = self
|
|
.get_mem()
|
|
.update_perm(address, length, native_permissions);
|
|
return res.is_ok();
|
|
}
|
|
|
|
pub fn write_memory(&mut self, address: u64, data: &[u8]) -> bool {
|
|
let res = self
|
|
.get_mem()
|
|
.write_bytes(address, data, icicle_vm::cpu::mem::perm::NONE);
|
|
return res.is_ok();
|
|
}
|
|
|
|
pub fn read_memory(&mut self, address: u64, data: &mut [u8]) -> bool {
|
|
let res = self
|
|
.get_mem()
|
|
.read_bytes(address, data, icicle_vm::cpu::mem::perm::NONE);
|
|
return res.is_ok();
|
|
}
|
|
|
|
pub fn save_registers(&self) -> Vec<u8> {
|
|
const REG_SIZE: usize = std::mem::size_of::<icicle_cpu::Regs>();
|
|
unsafe {
|
|
let data: [u8; REG_SIZE] = self.vm.cpu.regs.read_at(0);
|
|
return data.to_vec();
|
|
}
|
|
}
|
|
|
|
pub fn restore_registers(&mut self, data: &[u8]) {
|
|
const REG_SIZE: usize = std::mem::size_of::<icicle_cpu::Regs>();
|
|
|
|
let mut buffer: [u8; REG_SIZE] = [0; REG_SIZE];
|
|
let size = std::cmp::min(REG_SIZE, data.len());
|
|
buffer.copy_from_slice(&data[..size]);
|
|
|
|
unsafe {
|
|
self.vm.cpu.regs.write_at(0, buffer);
|
|
};
|
|
}
|
|
|
|
fn read_generic_register(&mut self, reg: registers::X64Register, buffer: &mut [u8]) -> usize {
|
|
let reg_node = self.reg.get_node(reg);
|
|
|
|
let res = self.vm.cpu.read_dynamic(pcode::Value::Var(reg_node));
|
|
let bytes: [u8; 32] = res.zxt();
|
|
|
|
let len = std::cmp::min(bytes.len(), buffer.len());
|
|
buffer[..len].copy_from_slice(&bytes[..len]);
|
|
|
|
return reg_node.size.into();
|
|
}
|
|
|
|
|
|
fn read_flags<T>(&mut self, data: &mut [u8]) -> usize
|
|
{
|
|
const REAL_SIZE: usize = std::mem::size_of::<u64>();
|
|
let limit: usize = std::mem::size_of::<T>();
|
|
let size = std::cmp::min(REAL_SIZE, limit);
|
|
|
|
let flags: u64 = self.reg.get_flags(&mut self.vm.cpu);
|
|
|
|
let copy_size = std::cmp::min(data.len(), size);
|
|
data[..copy_size].copy_from_slice(&flags.to_ne_bytes()[..copy_size]);
|
|
|
|
return limit;
|
|
}
|
|
|
|
pub fn read_register(&mut self, reg: registers::X64Register, data: &mut [u8]) -> usize {
|
|
match reg {
|
|
registers::X64Register::Rflags => self.read_flags::<u64>(data),
|
|
registers::X64Register::Eflags => self.read_flags::<u32>(data),
|
|
registers::X64Register::Flags => self.read_flags::<u16>(data),
|
|
_ => self.read_generic_register(reg, data),
|
|
}
|
|
}
|
|
|
|
fn write_flags<T>(&mut self, data: &[u8]) -> usize
|
|
{
|
|
const REAL_SIZE: usize = std::mem::size_of::<u64>();
|
|
let limit: usize = std::mem::size_of::<T>();
|
|
let size = std::cmp::min(REAL_SIZE, limit);
|
|
let copy_size = std::cmp::min(data.len(), size);
|
|
|
|
let mut buffer = [0u8; REAL_SIZE];
|
|
self.read_flags::<u64>(&mut buffer);
|
|
|
|
buffer[..copy_size].copy_from_slice(&data[..copy_size]);
|
|
|
|
let flags = u64::from_ne_bytes(buffer);
|
|
self.reg.set_flags(&mut self.vm.cpu, flags);
|
|
|
|
return limit;
|
|
}
|
|
|
|
pub fn write_register(&mut self, reg: registers::X64Register, data: &[u8]) -> usize {
|
|
match reg {
|
|
registers::X64Register::Rflags => self.write_flags::<u64>(data),
|
|
registers::X64Register::Eflags => self.write_flags::<u32>(data),
|
|
registers::X64Register::Flags => self.write_flags::<u16>(data),
|
|
_ => self.write_generic_register(reg, data),
|
|
}
|
|
}
|
|
|
|
fn write_generic_register(&mut self, reg: registers::X64Register, data: &[u8]) -> usize {
|
|
let reg_node = self.reg.get_node(reg);
|
|
|
|
let mut buffer = [0u8; 32];
|
|
let len = std::cmp::min(data.len(), buffer.len());
|
|
buffer[..len].copy_from_slice(&data[..len]);
|
|
|
|
//let value = icicle_cpu::regs::DynamicValue::new(buffer, reg_node.size.into());
|
|
//self.vm.cpu.write_trunc(reg_node, value);
|
|
|
|
let cpu = &mut self.vm.cpu;
|
|
|
|
match reg_node.size {
|
|
1 => cpu.write_var::<[u8; 1]>(reg_node, buffer[..1].try_into().unwrap()),
|
|
2 => cpu.write_var::<[u8; 2]>(reg_node, buffer[..2].try_into().unwrap()),
|
|
3 => cpu.write_var::<[u8; 3]>(reg_node, buffer[..3].try_into().unwrap()),
|
|
4 => cpu.write_var::<[u8; 4]>(reg_node, buffer[..4].try_into().unwrap()),
|
|
5 => cpu.write_var::<[u8; 5]>(reg_node, buffer[..5].try_into().unwrap()),
|
|
6 => cpu.write_var::<[u8; 6]>(reg_node, buffer[..6].try_into().unwrap()),
|
|
7 => cpu.write_var::<[u8; 7]>(reg_node, buffer[..7].try_into().unwrap()),
|
|
8 => cpu.write_var::<[u8; 8]>(reg_node, buffer[..8].try_into().unwrap()),
|
|
9 => cpu.write_var::<[u8; 9]>(reg_node, buffer[..9].try_into().unwrap()),
|
|
10 => cpu.write_var::<[u8; 10]>(reg_node, buffer[..10].try_into().unwrap()),
|
|
11 => cpu.write_var::<[u8; 11]>(reg_node, buffer[..11].try_into().unwrap()),
|
|
12 => cpu.write_var::<[u8; 12]>(reg_node, buffer[..12].try_into().unwrap()),
|
|
13 => cpu.write_var::<[u8; 13]>(reg_node, buffer[..13].try_into().unwrap()),
|
|
14 => cpu.write_var::<[u8; 14]>(reg_node, buffer[..14].try_into().unwrap()),
|
|
15 => cpu.write_var::<[u8; 15]>(reg_node, buffer[..15].try_into().unwrap()),
|
|
16 => cpu.write_var::<[u8; 16]>(reg_node, buffer[..16].try_into().unwrap()),
|
|
_ => panic!("invalid dynamic value size"),
|
|
}
|
|
|
|
return reg_node.size.into();
|
|
}
|
|
}
|