mirror of
https://github.com/kinnay/Wii-U-Firmware-Emulator.git
synced 2025-04-02 10:41:41 -04:00
130 lines
4 KiB
Python
130 lines
4 KiB
Python
|
|
from Crypto.Cipher import AES
|
|
|
|
import pyemu
|
|
import struct
|
|
import sys
|
|
|
|
import armemu
|
|
import ppcemu
|
|
import hardware
|
|
import debug
|
|
|
|
|
|
class Scheduler:
|
|
def __init__(self):
|
|
self.scheduler = pyemu.Scheduler()
|
|
self.scheduler.add_alarm(1, self.check_interrupts)
|
|
self.emulators = []
|
|
|
|
def add(self, emulator, steps):
|
|
self.emulators.append(emulator)
|
|
self.scheduler.add(emulator.interpreter, steps)
|
|
|
|
def resume(self, emulator):
|
|
self.scheduler.resume(self.emulators.index(emulator))
|
|
|
|
def run(self): self.scheduler.run()
|
|
def add_alarm(self, interval, callback):
|
|
self.scheduler.add_alarm(interval, callback)
|
|
|
|
def current(self): return self.emulators[self.scheduler.index]
|
|
def pc(self): return self.current().debugger.pc()
|
|
|
|
def check_interrupts(self):
|
|
for emulator in self.emulators:
|
|
emulator.check_interrupts()
|
|
|
|
|
|
class Emulator:
|
|
def __init__(self, filename):
|
|
self.scheduler = Scheduler()
|
|
self.shell = debug.DebugShell(self.scheduler)
|
|
|
|
self.init_physmem()
|
|
self.init_hardware()
|
|
self.init_cpu()
|
|
self.init_elffile(filename)
|
|
|
|
self.armemu.breakpoints.add(0x5015E70, lambda addr: self.armemu.core.setreg(0, 0))
|
|
self.armemu.breakpoints.add(0x503409C, lambda addr: self.reset_ppc())
|
|
|
|
def init_physmem(self):
|
|
self.physmem = pyemu.PhysicalMemory()
|
|
self.physmem.add_range(0x10000000, 0x28000000) #IOSU processes and ram disk
|
|
self.physmem.add_range(0x08000000, 0x082E0000) #MEM0
|
|
self.physmem.add_range(0xFFF00000, 0xFFFFF000) #Kernel stuff
|
|
self.physmem.add_range(0x28000000, 0x34000000) #MEM2
|
|
self.physmem.add_range(0x00000000, 0x02000000) #MEM1
|
|
|
|
def init_hardware(self):
|
|
self.hw = hardware.HardwareController(self.scheduler, self.physmem)
|
|
self.physmem.add_special(0xD000000, 0xD1A0000, self.hw.read, self.hw.write)
|
|
self.physmem.add_special(0xD800000, 0xD9A0000, self.hw.read, self.hw.write)
|
|
self.physmem.add_special(0xC000000, 0xC400000, self.hw.read, self.hw.write)
|
|
self.physmem.add_special(0xD0000000, 0xD0000004, self.hw.read, self.hw.write) #Used by tcl.rpl
|
|
|
|
def init_cpu(self):
|
|
reservation = pyemu.PPCLockMgr()
|
|
|
|
self.armemu = armemu.ARMEmulator(self, self.physmem, self.hw)
|
|
self.ppcemu = [ppcemu.PPCEmulator(self, self.physmem, self.hw, reservation, core) for core in range(3)]
|
|
|
|
self.scheduler.add(self.armemu, 1000)
|
|
self.scheduler.add(self.ppcemu[0], 500)
|
|
self.scheduler.add(self.ppcemu[1], 2000)
|
|
self.scheduler.add(self.ppcemu[2], 500)
|
|
self.scheduler.resume(self.armemu)
|
|
|
|
def init_elffile(self, filename):
|
|
with open(filename, "rb") as f:
|
|
data = f.read()
|
|
elf = pyemu.ELFFile(data)
|
|
|
|
for program in elf.programs:
|
|
if program.type == pyemu.ELFProgram.PT_LOAD:
|
|
if program.filesize:
|
|
self.physmem.write(program.physaddr, data[program.fileoffs : program.fileoffs + program.filesize])
|
|
|
|
self.armemu.core.setreg(pyemu.ARMCore.PC, elf.entry_point)
|
|
|
|
def reset_ppc(self):
|
|
size = struct.unpack(">I", self.physmem.read(0x080000AC, 4))[0]
|
|
data = self.physmem.read(0x08000100, size)
|
|
|
|
with open("espresso_key.txt") as f:
|
|
key = bytes.fromhex(f.read())
|
|
cipher = AES.new(key, AES.MODE_CBC, bytes(16))
|
|
self.physmem.write(0x08000100, cipher.decrypt(data))
|
|
|
|
for emu in self.ppcemu:
|
|
emu.core.setpc(0xFFF00100)
|
|
self.scheduler.resume(emu)
|
|
|
|
def print_traceback(self):
|
|
import traceback
|
|
traceback.print_exc()
|
|
|
|
print("An error occurred:")
|
|
print("\tARM: PC=%08X LR=%08X%s" %(self.armemu.core.reg(15), self.armemu.core.reg(14), " (current)" if self.scheduler.current == self.armemu else ""))
|
|
for i in range(3):
|
|
emu = self.ppcemu[i]
|
|
current = " (current)" if emu == self.scheduler.current else ""
|
|
print("\tPPC%i: PC=%08X LR=%08X%s" %(i, emu.core.pc(), emu.core.spr(pyemu.PPCCore.LR), current))
|
|
|
|
def run(self):
|
|
try:
|
|
if "break" in sys.argv: self.shell.show(False)
|
|
else: self.scheduler.run()
|
|
except:
|
|
self.print_traceback()
|
|
|
|
self.armemu.cleanup()
|
|
for e in self.ppcemu: e.cleanup()
|
|
self.hw.nand.close()
|
|
self.hw.sdio1.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
emulator = Emulator("C:/Users/Yannik/Downloads/openssl/fwdec.elf")
|
|
emulator.run()
|