Skip to content

Commit

Permalink
Improved support for GBA emulators (#55)
Browse files Browse the repository at this point in the history
Added sigscans in order to support newer versions of mGBA and VisualBoyAdvance, as well as added support for NO$GBA and Retroarch.

Moreover, `gba` struct added so it can be used the same way seen in other systems' emulators. See #26 and #33 for details.
  • Loading branch information
Jujstme committed Oct 18, 2023
1 parent ca1fd91 commit 1ae3c32
Show file tree
Hide file tree
Showing 9 changed files with 712 additions and 81 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ wasi-no-std = ["libm"]
unity = ["signature", "asr-derive?/unity"]

# Emulators
gba = []
gba = ["flags", "signature"]
gcn = ["flags"]
genesis = ["flags", "signature"]
ps1 = ["flags", "signature"]
Expand Down
80 changes: 0 additions & 80 deletions src/emulator/gba.rs

This file was deleted.

36 changes: 36 additions & 0 deletions src/emulator/gba/emuhawk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use crate::{Address, MemoryRangeFlags, Process};

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct State {
base_addr: Address,
}

impl State {
pub fn find_ram(&mut self, game: &Process) -> Option<[Address; 2]> {
self.base_addr = game.get_module_address("mgba.dll").ok()?;

let addr = game
.memory_ranges()
.find(|range| {
range.size().is_ok_and(|size| size == 0x48000)
&& range.flags().is_ok_and(|flag| {
flag.contains(MemoryRangeFlags::WRITE | MemoryRangeFlags::READ)
})
})?
.address()
.ok()?;

Some([addr, addr + 0x40000])
}

pub fn keep_alive(&self, game: &Process, ram_base: &Option<[Address; 2]>) -> bool {
ram_base.is_some_and(|[ewram, _]| game.read::<u8>(ewram).is_ok())
&& game.read::<u8>(self.base_addr).is_ok()
}

pub const fn new() -> Self {
Self {
base_addr: Address::NULL,
}
}
}
106 changes: 106 additions & 0 deletions src/emulator/gba/mednafen.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Error, Process};

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct State {
cached_ewram_pointer: Address,
cached_iwram_pointer: Address,
is_64_bit: bool,
}

impl State {
pub fn find_ram(&mut self, game: &Process) -> Option<[Address; 2]> {
let main_module_range = super::PROCESS_NAMES
.iter()
.filter(|(_, state)| matches!(state, super::State::Mednafen(_)))
.find_map(|(name, _)| game.get_module_range(name).ok())?;

self.is_64_bit =
pe::MachineType::read(game, main_module_range.0) == Some(pe::MachineType::X86_64);

if self.is_64_bit {
self.cached_ewram_pointer = {
const SIG: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF FF 03 00");
let ptr: Address = SIG.scan_process_range(game, main_module_range)? + 3;
let mut addr: Address = ptr + 0x4 + game.read::<i32>(ptr).ok()?;

if game.read::<u8>(ptr + 10).ok()? == 0x48 {
addr = game.read::<Address64>(addr).ok()?.into();
if addr.is_null() {
return None;
}
}

addr

Check failure on line 33 in src/emulator/gba/mednafen.rs

View workflow job for this annotation

GitHub Actions / Check formatting

Diff in /home/runner/work/asr/asr/src/emulator/gba/mednafen.rs
};


self.cached_iwram_pointer = {
const SIG2: Signature<13> = Signature::new("48 8B 05 ?? ?? ?? ?? 81 E1 FF 7F 00 00");
let ptr: Address = SIG2.scan_process_range(game, main_module_range)? + 3;
let mut addr: Address = ptr + 0x4 + game.read::<i32>(ptr).ok()?;

if game.read::<u8>(ptr + 10).ok()? == 0x48 {
addr = game.read::<Address64>(addr).ok()?.into();
if addr.is_null() {
return None;

Check failure on line 45 in src/emulator/gba/mednafen.rs

View workflow job for this annotation

GitHub Actions / Check formatting

Diff in /home/runner/work/asr/asr/src/emulator/gba/mednafen.rs
}
}

addr
};

let ewram = game.read::<Address64>(self.cached_ewram_pointer).ok()?;
let iwram = game.read::<Address64>(self.cached_iwram_pointer).ok()?;

Some([ewram.into(), iwram.into()])
} else {
self.cached_ewram_pointer = {
const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF FF 03 00");
let ptr = SIG.scan_process_range(game, main_module_range)?;
game.read::<Address32>(ptr + 1).ok()?.into()

Check failure on line 60 in src/emulator/gba/mednafen.rs

View workflow job for this annotation

GitHub Actions / Check formatting

Diff in /home/runner/work/asr/asr/src/emulator/gba/mednafen.rs
};


self.cached_iwram_pointer = {
const SIG2: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 ?? FF 7F 00 00");
let ptr = SIG2.scan_process_range(game, main_module_range)?;
game.read::<Address32>(ptr + 1).ok()?.into()

Check failure on line 67 in src/emulator/gba/mednafen.rs

View workflow job for this annotation

GitHub Actions / Check formatting

Diff in /home/runner/work/asr/asr/src/emulator/gba/mednafen.rs
};

let ewram = game.read::<Address32>(self.cached_ewram_pointer).ok()?;
let iwram = game.read::<Address32>(self.cached_iwram_pointer).ok()?;

Some([ewram.into(), iwram.into()])
}
}

fn read_pointer(&self, game: &Process, address: Address) -> Result<Address, Error> {
Ok(match self.is_64_bit {
true => game.read::<Address64>(address)?.into(),
false => game.read::<Address32>(address)?.into(),
})
}

pub fn keep_alive(&self, game: &Process, ram: &mut Option<[Address; 2]>) -> bool {
let ewram = match self.read_pointer(game, self.cached_ewram_pointer) {
Ok(x) => x,
_ => return false,
};

let iwram = match self.read_pointer(game, self.cached_iwram_pointer) {
Ok(x) => x,
_ => return false,
};

*ram = Some([ewram, iwram]);
true
}

pub const fn new() -> Self {
Self {
cached_ewram_pointer: Address::NULL,
cached_iwram_pointer: Address::NULL,
is_64_bit: false,
}
}
}
25 changes: 25 additions & 0 deletions src/emulator/gba/mgba.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crate::{Address, MemoryRangeFlags, Process};

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct State;

impl State {
pub fn find_ram(&self, game: &Process) -> Option<[Address; 2]> {
// Latest version tested: 0.10.2 (September 2023)
let addr = game
.memory_ranges()
.find(|range| {
range.size().is_ok_and(|size| size == 0x48000)
&& range.flags().is_ok_and(|flag| {
flag.contains(MemoryRangeFlags::WRITE | MemoryRangeFlags::READ)
})
})?
.address()
.ok()?;
Some([addr, addr + 0x40000])
}

pub fn keep_alive(&self, game: &Process, ram_base: &Option<[Address; 2]>) -> bool {
ram_base.is_some_and(|[ewram, _]| game.read::<u8>(ewram).is_ok())
}
}
Loading

0 comments on commit 1ae3c32

Please sign in to comment.