1 use armv4t_emu::{reg, Cpu, ExampleMem, Memory, Mode}; 2 3 use crate::mem_sniffer::{AccessKind, MemSniffer}; 4 use crate::DynResult; 5 6 const HLE_RETURN_ADDR: u32 = 0x12345678; 7 8 #[derive(Debug, Copy, Clone, PartialEq, Eq)] 9 pub enum Event { 10 Halted, 11 Break, 12 WatchWrite(u32), 13 WatchRead(u32), 14 } 15 16 /// incredibly barebones armv4t-based emulator 17 pub struct Emu { 18 start_addr: u32, 19 20 pub(crate) cpu: Cpu, 21 pub(crate) mem: ExampleMem, 22 23 pub(crate) watchpoints: Vec<u32>, 24 pub(crate) breakpoints: Vec<u32>, 25 } 26 27 impl Emu { new(program_elf: &[u8]) -> DynResult<Emu>28 pub fn new(program_elf: &[u8]) -> DynResult<Emu> { 29 // set up emulated system 30 let mut cpu = Cpu::new(); 31 let mut mem = ExampleMem::new(); 32 33 // load ELF 34 let elf_header = goblin::elf::Elf::parse(program_elf)?; 35 36 // copy all in-memory sections from the ELF file into system RAM 37 let sections = elf_header 38 .section_headers 39 .iter() 40 .filter(|h| h.is_alloc() && h.sh_type != goblin::elf::section_header::SHT_NOBITS); 41 42 for h in sections { 43 eprintln!( 44 "loading section {:?} into memory from [{:#010x?}..{:#010x?}]", 45 elf_header.shdr_strtab.get(h.sh_name).unwrap().unwrap(), 46 h.sh_addr, 47 h.sh_addr + h.sh_size, 48 ); 49 50 for (i, b) in program_elf[h.file_range()].iter().enumerate() { 51 mem.w8(h.sh_addr as u32 + i as u32, *b); 52 } 53 } 54 55 // setup execution state 56 eprintln!("Setting PC to {:#010x?}", elf_header.entry); 57 cpu.reg_set(Mode::User, reg::SP, 0x10000000); 58 cpu.reg_set(Mode::User, reg::LR, HLE_RETURN_ADDR); 59 cpu.reg_set(Mode::User, reg::PC, elf_header.entry as u32); 60 cpu.reg_set(Mode::User, reg::CPSR, 0x10); // user mode 61 62 Ok(Emu { 63 start_addr: elf_header.entry as u32, 64 cpu, 65 mem, 66 67 watchpoints: Vec::new(), 68 breakpoints: Vec::new(), 69 }) 70 } 71 reset(&mut self)72 pub(crate) fn reset(&mut self) { 73 self.cpu.reg_set(Mode::User, reg::SP, 0x10000000); 74 self.cpu.reg_set(Mode::User, reg::LR, HLE_RETURN_ADDR); 75 self.cpu.reg_set(Mode::User, reg::PC, self.start_addr); 76 self.cpu.reg_set(Mode::User, reg::CPSR, 0x10); 77 } 78 step(&mut self) -> Option<Event>79 pub fn step(&mut self) -> Option<Event> { 80 let mut hit_watchpoint = None; 81 82 let mut sniffer = MemSniffer::new(&mut self.mem, &self.watchpoints, |access| { 83 hit_watchpoint = Some(access) 84 }); 85 86 self.cpu.step(&mut sniffer); 87 let pc = self.cpu.reg_get(Mode::User, reg::PC); 88 89 if let Some(access) = hit_watchpoint { 90 let fixup = if self.cpu.thumb_mode() { 2 } else { 4 }; 91 self.cpu.reg_set(Mode::User, reg::PC, pc - fixup); 92 93 return Some(match access.kind { 94 AccessKind::Read => Event::WatchRead(access.addr), 95 AccessKind::Write => Event::WatchWrite(access.addr), 96 }); 97 } 98 99 if self.breakpoints.contains(&pc) { 100 return Some(Event::Break); 101 } 102 103 if pc == HLE_RETURN_ADDR { 104 return Some(Event::Halted); 105 } 106 107 None 108 } 109 } 110