1extern crate alloc;
2
3use crate::ffi::{DyHook, SFHook};
4use anyhow::anyhow;
5use log::{debug, error, warn};
6use std::cell::UnsafeCell;
7use std::ffi::c_void;
8use std::marker::PhantomData;
9use std::process::exit;
10use std::ptr::null_mut;
11use std::sync::Arc;
12
13mod ffi;
14
15pub type DynarmicContext = Arc<DynarmicContextInner>;
16
17#[derive(Clone)]
18pub struct DynarmicContextInner {
19 inner_context: *mut c_void,
20}
21
22impl DynarmicContextInner {
23 pub fn destroy(&self) {
24 unsafe {
25 ffi::dynarmic_context_free(self.inner_context);
26 }
27 }
28}
29
30impl Drop for DynarmicContextInner {
31 fn drop(&mut self) {
32 self.destroy();
33 }
34}
35
36unsafe impl Send for DynarmicContextInner {}
37unsafe impl Sync for DynarmicContextInner {}
38
39pub type DynarmicContext32 = Arc<DynarmicContext32Inner>;
40
41#[derive(Clone)]
42pub struct DynarmicContext32Inner {
43 inner_context: *mut c_void,
44}
45
46impl DynarmicContext32Inner {
47 pub fn destroy(&self) {
48 unsafe {
49 ffi::dynarmic_context32_free(self.inner_context);
50 }
51 }
52}
53
54impl Drop for DynarmicContext32Inner {
55 fn drop(&mut self) {
56 self.destroy();
57 }
58}
59
60unsafe impl Send for DynarmicContext32Inner {}
61unsafe impl Sync for DynarmicContext32Inner {}
62
63pub fn dynarmic_version() -> u32 {
65 unsafe { ffi::dynarmic_version() }
66}
67
68pub fn dynarmic_colorful_egg() -> String {
70 unsafe {
71 let c_str = ffi::dynarmic_colorful_egg();
72 if c_str.is_null() {
73 return String::new();
74 }
75 let c_str = std::ffi::CStr::from_ptr(c_str);
76 c_str.to_string_lossy().into_owned()
77 }
78}
79
80struct Metadata<'a> {
81 svc_callback: Option<Box<dyn SFHook + 'a>>,
82 unmapped_mem_callback: Option<Box<dyn SFHook + 'a>>,
83 until: u64,
84 _memory: *mut c_void,
85 _monitor: *mut c_void,
86 _page_table: *mut *mut c_void,
87 handle: *mut c_void,
88}
89
90impl Drop for Metadata<'_> {
91 fn drop(&mut self) {
92 log::info!("[dynarmic] Dropping Metadata");
93 unsafe {
94 ffi::dynarmic_destroy(self.handle);
95 }
96 }
97}
98
99unsafe impl Send for Metadata<'_> {}
100unsafe impl Sync for Metadata<'_> {}
101
102#[derive(Clone)]
107pub struct Dynarmic<'a, T: Clone + Send + Sync> {
108 cur_handle: *mut c_void,
109 metadata: Arc<UnsafeCell<Metadata<'a>>>,
110 pd: PhantomData<&'a T>,
111}
112
113unsafe impl<'a, T: Clone + Send + Sync> Send for Dynarmic<'a, T> {}
114unsafe impl<'a, T: Clone + Send + Sync> Sync for Dynarmic<'a, T> {}
115
116impl<'a, T: Clone + Send + Sync> Dynarmic<'a, T> {
117 pub fn new() -> Dynarmic<'static, T> {
122 let memory = unsafe { ffi::dynarmic_init_memory() };
123 if memory == null_mut() {
124 error!("Failed to initialize memory");
125 exit(0)
126 }
127
128 let mut jit_size = std::env::var("DYNARMIC_JIT_SIZE")
129 .ok()
130 .and_then(|s| s.parse::<u64>().ok())
131 .unwrap_or(64);
132
133 if jit_size < 8 {
134 warn!("JIT size {}MB is too small, setting to 8MB", jit_size);
135 jit_size = 8;
136 } else if jit_size > 512 {
137 warn!("JIT size {}MB is too large, setting to 512MB", jit_size);
138 jit_size = 512;
139 }
140
141 let monitor = unsafe { ffi::dynarmic_init_monitor(1) };
142 let page_table = unsafe { ffi::dynarmic_init_page_table() };
143 let handle = unsafe {
144 ffi::dynarmic_new(0, memory, monitor, page_table, jit_size * 1024 * 1024, true)
145 };
146
147 debug!(
148 "[Dynarmic] Created new Dynarmic instance: {:X} with {}MB JIT",
149 handle as usize, jit_size
150 );
151
152 Dynarmic {
153 cur_handle: handle,
154 metadata: Arc::new(UnsafeCell::new(Metadata {
155 svc_callback: None,
156 unmapped_mem_callback: None,
157 until: 0,
158 _memory: memory,
159 _monitor: monitor,
160 _page_table: page_table,
161 handle,
162 })),
163 pd: PhantomData,
164 }
165 }
166
167 pub fn new_a32() -> Dynarmic<'static, T> {
172 let memory = unsafe { ffi::dynarmic_init_memory() };
173 if memory == null_mut() {
174 error!("Failed to initialize memory");
175 exit(0)
176 }
177
178 let mut jit_size = std::env::var("DYNARMIC_JIT_SIZE")
179 .ok()
180 .and_then(|s| s.parse::<u64>().ok())
181 .unwrap_or(64);
182
183 if jit_size < 8 {
184 warn!("JIT size {}MB is too small, setting to 8MB", jit_size);
185 jit_size = 8;
186 } else if jit_size > 512 {
187 warn!("JIT size {}MB is too large, setting to 512MB", jit_size);
188 jit_size = 512;
189 }
190
191 let monitor = unsafe { ffi::dynarmic_init_monitor(1) };
192 let page_table = unsafe { ffi::dynarmic_init_page_table() };
193 let handle = unsafe {
194 ffi::dynarmic_new_a32(
195 0,
196 memory,
197 monitor,
198 page_table,
199 jit_size * 1024 * 1024,
200 true,
201 null_mut(),
202 )
203 };
204
205 debug!(
206 "[Dynarmic] Created new Dynarmic A32 instance: {:X} with {}MB JIT",
207 handle as usize, jit_size
208 );
209
210 Dynarmic {
211 cur_handle: handle,
212 metadata: Arc::new(UnsafeCell::new(Metadata {
213 svc_callback: None,
214 unmapped_mem_callback: None,
215 until: 0,
216 _memory: memory,
217 _monitor: monitor,
218 _page_table: page_table,
219 handle,
220 })),
221 pd: PhantomData,
222 }
223 }
224
225 pub fn emu_start(&self, pc: u64, until: u64) -> anyhow::Result<()> {
230 unsafe {
231 debug!("[Dynarmic] Starting emulator: pc=0x{:x}", pc);
232
233 (*self.metadata.get()).until = until.saturating_add(4);
236
237 let ret = ffi::dynarmic_emu_start(self.cur_handle, pc);
238 if ret != 0 {
239 return Err(anyhow!("Failed to start emulator: code={}", ret));
240 }
241 Ok(())
242 }
243 }
244
245 pub fn emu_stop(&self) -> anyhow::Result<()> {
247 unsafe {
248 debug!("[Dynarmic] Stopping emulator");
249 let ret = ffi::dynarmic_emu_stop(self.cur_handle);
250 if ret != 0 {
251 return Err(anyhow!("Failed to stop emulator: code={}", ret));
252 }
253 Ok(())
254 }
255 }
256
257 pub fn get_cache_size(&self) -> u64 {
259 unsafe { ffi::dynarmic_get_cache_size(self.cur_handle) }
260 }
261
262 pub fn context_alloc(&self) -> DynarmicContext {
264 unsafe {
265 let inner_context = ffi::dynarmic_context_alloc();
266 Arc::new(DynarmicContextInner { inner_context })
267 }
268 }
269
270 pub fn context_save(&self, context: &mut DynarmicContext) -> anyhow::Result<()> {
272 unsafe {
273 let ret = ffi::dynarmic_context_save(self.cur_handle, context.inner_context);
274 if ret != 0 {
275 return Err(anyhow!("Failed to save context: code={}", ret));
276 }
277 Ok(())
278 }
279 }
280
281 pub fn context_restore(&self, context: &DynarmicContext) -> anyhow::Result<()> {
283 unsafe {
284 let ret = ffi::dynarmic_context_restore(self.cur_handle, context.inner_context);
285 if ret != 0 {
286 return Err(anyhow!("Failed to restore context: code={}", ret));
287 }
288 Ok(())
289 }
290 }
291
292 pub fn context32_alloc(&self) -> DynarmicContext32 {
294 unsafe {
295 let inner_context = ffi::dynarmic_context32_alloc();
296 Arc::new(DynarmicContext32Inner { inner_context })
297 }
298 }
299
300 pub fn context32_save(&self, context: &mut DynarmicContext32) -> anyhow::Result<()> {
302 unsafe {
303 let ret = ffi::dynarmic_context32_save(self.cur_handle, context.inner_context);
304 if ret != 0 {
305 return Err(anyhow!("Failed to save A32 context: code={}", ret));
306 }
307 Ok(())
308 }
309 }
310
311 pub fn context32_restore(&self, context: &DynarmicContext32) -> anyhow::Result<()> {
313 unsafe {
314 let ret = ffi::dynarmic_context32_restore(self.cur_handle, context.inner_context);
315 if ret != 0 {
316 return Err(anyhow!("Failed to restore A32 context: code={}", ret));
317 }
318 Ok(())
319 }
320 }
321
322 pub fn mem_map(&self, addr: u64, size: usize, prot: u32) -> anyhow::Result<()> {
328 unsafe {
329 debug!(
330 "[Dynarmic] Mapping memory: addr=0x{:x}, size=0x{:x}, prot={}",
331 addr, size, prot
332 );
333 let ret =
334 ffi::dynarmic_mmap(self.cur_handle, addr, size as u64, u32::cast_signed(prot));
335 if ret == 4 {
336 warn!("Replace mmap?");
337 }
338 if ret != 0 {
339 return Err(anyhow!("Failed to map memory: code={}", ret));
340 }
341 debug!(
342 "[Dynarmic] Mapped memory: addr=0x{:x}, size=0x{:x}, prot={}",
343 addr, size, prot
344 );
345 Ok(())
346 }
347 }
348
349 pub fn mem_map_ptr(
351 &self,
352 addr: u64,
353 size: usize,
354 prot: u32,
355 ptr: *mut c_void,
356 ) -> anyhow::Result<()> {
357 unsafe {
358 debug!(
359 "[Dynarmic] Mapping memory ptr: addr=0x{:x}, size=0x{:x}, prot={}, ptr={:?}",
360 addr, size, prot, ptr
361 );
362 let ret = ffi::dynarmic_mem_map_ptr(
363 self.cur_handle,
364 addr,
365 size as u64,
366 u32::cast_signed(prot),
367 ptr,
368 );
369 if ret == 4 {
370 warn!("Replace mmap?");
371 }
372 if ret != 0 {
373 return Err(anyhow!("Failed to map memory ptr: code={}", ret));
374 }
375 debug!(
376 "[Dynarmic] Mapped memory ptr: addr=0x{:x}, size=0x{:x}, prot={}",
377 addr, size, prot
378 );
379 Ok(())
380 }
381 }
382
383 pub fn mem_unmap(&self, addr: u64, size: usize) -> anyhow::Result<()> {
385 unsafe {
386 debug!(
387 "[Dynarmic] Unmapping memory: addr=0x{:x}, size=0x{:x}",
388 addr, size
389 );
390 let ret = ffi::dynarmic_munmap(self.cur_handle, addr, size as u64);
391 if ret != 0 {
392 return Err(anyhow!("Failed to unmap memory: code={}", ret));
393 }
394 Ok(())
395 }
396 }
397
398 pub fn mem_protect(&self, addr: u64, size: usize, prot: u32) -> anyhow::Result<()> {
400 unsafe {
401 debug!(
402 "[Dynarmic] Protecting memory: addr=0x{:x}, size=0x{:x}, prot={}",
403 addr, size, prot
404 );
405 let ret = ffi::dynarmic_mem_protect(
406 self.cur_handle,
407 addr,
408 size as u64,
409 u32::cast_signed(prot),
410 );
411 if ret != 0 {
412 return Err(anyhow!("Failed to protect memory: code={}", ret));
413 }
414 Ok(())
415 }
416 }
417
418 pub fn reg_read(&self, index: usize) -> anyhow::Result<u64> {
420 unsafe { Ok(ffi::reg_read(self.cur_handle, index as u64)) }
421 }
422
423 pub fn reg_read_lr(&self) -> anyhow::Result<u64> {
425 unsafe { Ok(ffi::reg_read(self.cur_handle, 30)) }
426 }
427
428 pub fn reg_read_nzcv(&self) -> anyhow::Result<u64> {
430 unsafe { Ok(ffi::reg_read_nzcv(self.cur_handle)) }
431 }
432
433 pub fn reg_read_sp(&self) -> anyhow::Result<u64> {
435 unsafe { Ok(ffi::reg_read_sp(self.cur_handle)) }
436 }
437
438 pub fn reg_read_tpidr_el0(&self) -> anyhow::Result<u64> {
440 unsafe { Ok(ffi::reg_read_tpidr_el0(self.cur_handle)) }
441 }
442
443 pub fn reg_read_pc(&self) -> anyhow::Result<u64> {
445 unsafe { Ok(ffi::reg_read_pc(self.cur_handle)) }
446 }
447
448 pub fn reg_write_pc(&self, value: u64) -> anyhow::Result<()> {
450 unsafe {
451 debug!("[Dynarmic] Writing PC: value=0x{:x}", value);
452 let ret = ffi::reg_write_pc(self.cur_handle, value);
453 if ret != 0 {
454 return Err(anyhow!("Failed to write PC: code={}", ret));
455 }
456 Ok(())
457 }
458 }
459
460 pub fn reg_write_sp(&self, value: u64) -> anyhow::Result<()> {
462 unsafe {
463 debug!("[Dynarmic] Writing SP: value=0x{:x}", value);
464 let ret = ffi::reg_write_sp(self.cur_handle, value);
465 if ret != 0 {
466 return Err(anyhow!("Failed to write SP: code={}", ret));
467 }
468 Ok(())
469 }
470 }
471
472 pub fn reg_write_lr(&self, value: u64) -> anyhow::Result<()> {
474 unsafe {
475 debug!("[Dynarmic] Writing LR: value=0x{:x}", value);
476 let ret = ffi::reg_write(self.cur_handle, 30, value);
477 if ret != 0 {
478 return Err(anyhow!("Failed to write LR: code={}", ret));
479 }
480 Ok(())
481 }
482 }
483
484 pub fn reg_write_tpidr_el0(&self, value: u64) -> anyhow::Result<()> {
486 unsafe {
487 debug!("[Dynarmic] Writing TPIDR_EL0: value=0x{:x}", value);
488 let ret = ffi::reg_write_tpidr_el0(self.cur_handle, value);
489 if ret != 0 {
490 return Err(anyhow!("Failed to write TPIDR_EL0: code={}", ret));
491 }
492 Ok(())
493 }
494 }
495
496 pub fn reg_write_tpidrr0_el0(&self, value: u64) -> anyhow::Result<()> {
502 unsafe {
503 ffi::reg_write_tpidrr0_el0(self.cur_handle, value);
504 }
505 Ok(())
506 }
507
508 pub fn reg_read_tpidrr0_el0(&self) -> anyhow::Result<u64> {
511 unsafe { Ok(ffi::reg_read_tpidrr0_el0(self.cur_handle)) }
512 }
513
514 pub fn reg_write_nzcv(&self, value: u64) -> anyhow::Result<()> {
516 unsafe {
517 debug!("[Dynarmic] Writing NZCV: value=0x{:x}", value);
518 let ret = ffi::reg_write_nzcv(self.cur_handle, value);
519 if ret != 0 {
520 return Err(anyhow!("Failed to write NZCV: code={}", ret));
521 }
522 Ok(())
523 }
524 }
525
526 pub fn reg_write_raw(&self, index: usize, value: u64) -> anyhow::Result<()> {
528 unsafe {
529 debug!(
530 "[Dynarmic] Writing register: index={}, value=0x{:x}",
531 index, value
532 );
533 let ret = ffi::reg_write(self.cur_handle, index as u64, value);
534 if ret != 0 {
535 return Err(anyhow!("Failed to write register: code={}", ret));
536 }
537 Ok(())
538 }
539 }
540
541 pub fn reg_write_c13_c0_3(&self, value: u32) -> anyhow::Result<()> {
543 unsafe {
544 debug!("[Dynarmic] Writing CP15 c13 0 3: value=0x{:x}", value);
545 let ret = ffi::reg_write_c13_c0_3(self.cur_handle, value);
546 if ret != 0 {
547 return Err(anyhow!("Failed to write CP15 c13 0 3: code={}", ret));
548 }
549 Ok(())
550 }
551 }
552
553 pub fn reg_read_c13_c0_3(&self) -> anyhow::Result<u32> {
555 unsafe { Ok(ffi::reg_read_c13_c0_3(self.cur_handle)) }
556 }
557
558 pub fn reg_write_r(&self, index: u32, value: u32) -> anyhow::Result<()> {
560 unsafe {
561 let ret = ffi::reg_write_r(self.cur_handle, index, value);
562 if ret != 0 {
563 return Err(anyhow!("Failed to write R register: code={}", ret));
564 }
565 Ok(())
566 }
567 }
568
569 pub fn reg_read_r(&self, index: u32) -> anyhow::Result<u32> {
571 unsafe { Ok(ffi::reg_read_r(self.cur_handle, index)) }
572 }
573
574 pub fn reg_write_cpsr(&self, value: u32) -> anyhow::Result<()> {
576 unsafe {
577 let ret = ffi::reg_write_cpsr(self.cur_handle, value);
578 if ret != 0 {
579 return Err(anyhow!("Failed to write CPSR: code={}", ret));
580 }
581 Ok(())
582 }
583 }
584
585 pub fn reg_read_cpsr(&self) -> anyhow::Result<u32> {
587 unsafe { Ok(ffi::reg_read_cpsr(self.cur_handle)) }
588 }
589
590 pub fn mem_read_c_string(&self, mut addr: u64) -> anyhow::Result<String> {
592 let mut buf = Vec::new();
593 let mut byte = [0u8];
594 loop {
595 self.mem_read(addr, &mut byte)?;
596 if byte[0] == 0 {
597 break;
598 }
599 buf.push(byte[0]);
600 addr += 1;
601 }
602 unsafe { Ok(String::from_utf8_unchecked(buf)) }
603 }
604
605 pub fn mem_read(&self, addr: u64, dest: &mut [u8]) -> anyhow::Result<()> {
607 unsafe {
608 debug!(
609 "[Dynarmic] Reading memory: addr=0x{:x}, size=0x{:x}",
610 addr,
611 dest.len()
612 );
613 let ret = ffi::dynarmic_mem_read(
614 self.cur_handle,
615 addr,
616 dest.as_mut_ptr() as *mut _,
617 dest.len(),
618 );
619 if ret != 0 {
620 return Err(anyhow!("Failed to read memory: code={}", ret));
621 }
622 Ok(())
623 }
624 }
625
626 pub fn mem_read_as_vec(&self, addr: u64, size: usize) -> anyhow::Result<Vec<u8>> {
628 let mut buf = vec![0; size];
629 self.mem_read(addr, &mut buf)?;
630 Ok(buf)
631 }
632
633 pub fn mem_write(&self, addr: u64, value: &[u8]) -> anyhow::Result<()> {
635 unsafe {
636 debug!(
637 "[Dynarmic] Writing memory: addr=0x{:x}, size=0x{:x}",
638 addr,
639 value.len()
640 );
641 let ret = ffi::dynarmic_mem_write(
642 self.cur_handle,
643 addr,
644 value.as_ptr() as *const _,
645 value.len(),
646 );
647 if ret != 0 {
648 return Err(anyhow!("Failed to write memory: code={}", ret));
649 }
650 Ok(())
651 }
652 }
653
654 pub fn set_svc_callback<F: 'a>(&self, callback: F)
658 where
659 F: FnMut(&Dynarmic<T>, u32, u64, u64) + Send + Sync,
660 {
661 debug!("[Dynarmic] Setting SVC callback");
662 unsafe {
663 let mut cb = Box::new(DyHook {
664 callback,
665 dy: self.clone(),
666 });
667 let user_data = cb.as_mut() as *mut _ as *const c_void;
668
669 extern "C" fn svc_callback_wrapper<T: Clone + Send + Sync, F>(swi: u32, user_data: *const c_void)
670 where
671 F: FnMut(&Dynarmic<T>, u32, u64, u64) + Send + Sync,
672 {
673 if swi == 114514 {
674 return;
675 }
676 unsafe {
677 let cb = &mut *(user_data as *mut DyHook<T, F>);
678 let dynarmic = &cb.dy;
679 let pc = ffi::reg_read_pc(dynarmic.cur_handle);
680 let until = (*dynarmic.metadata.get()).until;
681 (cb.callback)(dynarmic, swi, until, pc);
682 }
683 }
684
685 ffi::dynarmic_set_svc_callback(
686 self.cur_handle,
687 svc_callback_wrapper::<T, F>,
688 user_data,
689 );
690 (*self.metadata.get()).svc_callback = Some(cb);
691 }
692 }
693
694 pub fn set_unmapped_mem_callback<F: 'a>(&self, callback: F)
698 where
699 F: FnMut(&Dynarmic<T>, u64, usize, u64) -> bool + Send + Sync,
700 {
701 debug!("[Dynarmic] Setting unmapped memory callback");
702 unsafe {
703 let mut cb = Box::new(DyHook {
704 callback,
705 dy: self.clone(),
706 });
707 let user_data = cb.as_mut() as *mut _ as *const c_void;
708
709 extern "C" fn unmapped_mem_callback_wrapper<T: Clone + Send + Sync, F>(
710 addr: u64,
711 size: usize,
712 value: u64,
713 user_data: *const c_void,
714 ) -> bool
715 where
716 F: FnMut(&Dynarmic<T>, u64, usize, u64) -> bool + Send + Sync,
717 {
718 unsafe {
719 let cb = &mut *(user_data as *mut DyHook<T, F>);
720 let dynarmic = &cb.dy;
721 (cb.callback)(dynarmic, addr, size, value)
722 }
723 }
724
725 ffi::dynarmic_set_unmapped_mem_callback(
726 self.cur_handle,
727 unmapped_mem_callback_wrapper::<T, F>,
728 user_data,
729 );
730 (*self.metadata.get()).unmapped_mem_callback = Some(cb);
731 }
732 }
733
734 pub fn destroy_callback(&self) {
736 unsafe {
737 extern "C" fn empty_svc_callback(_: u32, _: *const c_void) {}
738 extern "C" fn empty_unmapped_callback(
739 _: u64,
740 _: usize,
741 _: u64,
742 _: *const c_void,
743 ) -> bool {
744 false
745 }
746
747 ffi::dynarmic_set_svc_callback(self.cur_handle, empty_svc_callback, null_mut());
748 let callback = (*self.metadata.get()).svc_callback.take();
749 drop(callback);
750
751 ffi::dynarmic_set_unmapped_mem_callback(
752 self.cur_handle,
753 empty_unmapped_callback,
754 null_mut(),
755 );
756 let callback = (*self.metadata.get()).unmapped_mem_callback.take();
757 drop(callback);
758 }
759 }
760}