diff --git a/tlbrefill/Makefile b/tlbrefill/Makefile new file mode 100755 index 0000000..2cb7aed --- /dev/null +++ b/tlbrefill/Makefile @@ -0,0 +1,25 @@ +EE_BIN= tlbrefill.elf +EE_OBJS = tlbrefill.o tlbrefillhandler.o + +EE_CFLAGS = -Wall -O3 + +all: $(EE_BIN) + +clean: + rm -f $(EE_OBJS) $(EE_BIN) + +run: $(EE_BIN) + ps2client execee host:$(EE_BIN) + +wsl: $(EE_BIN) + $(PCSX2) -elf "$(shell wslpath -w $(shell pwd))/$(EE_BIN)" + +emu: $(EE_BIN) + $(PCSX2) -elf "$(shell pwd)/$(EE_BIN)" + +reset: + ps2client reset + ps2client netdump + +include $(PS2SDK)/samples/Makefile.pref +include $(PS2SDK)/samples/Makefile.eeglobal diff --git a/tlbrefill/README.md b/tlbrefill/README.md new file mode 100755 index 0000000..044ae3e --- /dev/null +++ b/tlbrefill/README.md @@ -0,0 +1,27 @@ +# TLBREFILL + +## Description +Creates a TLB store refill handler and causes a miss. Logging the EPC and BadVAddr COP0 registers. + +In the future, it might be better to log the entire COP0 register states. + +## PCSX2 Behaviour +The recompiler does not call the refill handlers and will continue emulation until a TLB exception messages threshold was met. + +The interpreter will call the proper refill handler. + +## Related PR(s) or Issue(s) +n/a + +## Expected Results +``` +TLB Refill handler test running + +TLB handler test completed + Expected EPC: +-0x119ad0 + Returned EPC: 0x119ad0 + Expected BadVAddr: 0x123 + Returned BadVAddr: 0x123 + +TLB Refill handler test completed +``` diff --git a/tlbrefill/tlbrefill.c b/tlbrefill/tlbrefill.c new file mode 100755 index 0000000..26ec9fe --- /dev/null +++ b/tlbrefill/tlbrefill.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +// Network based logging does not work for me +// So I'll provide both network and ee-sio logs +void dbgmsg(const char* fmt, ...) +{ + char buf[256]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, 256, fmt, ap); + vprintf(buf,ap); + va_end(ap); + sio_puts(buf); +} + +void tlbRefillHandler(); +void* tlbRefillEPC = 0; +void* tlbRefillBadVAddr = 0; + +__attribute__ ((__noinline__)) +void * get_pc () { return __builtin_return_address(0); } + +int main(void) +{ + dbgmsg("TLB Refill handler test running\n"); + // Disable interrupts, don't risk having our handler called unintentionally + DIntr(); + + // Replace the existing TLB refill handler + // (3) -> Store + // (2) -> Load + void* prevVTLBRefillHandler = GetExceptionHandler(3); + SetVTLBRefillHandler(3, (void*)tlbRefillHandler); + + // Cause a TLB store miss + asm("nop":::"memory"); + volatile u8* badAddress = (volatile u8*)0x123; + void* exceptionPC = get_pc() + 8; + *badAddress = ~1; + asm("nop":::"memory"); + + // Restore the previous TLB refill handler + SetVTLBRefillHandler(3, prevVTLBRefillHandler); + + EIntr(); + + dbgmsg( + "TLB handler test completed\n" + " Expected EPC: +-%p\n" + " Returned EPC: %p\n" + " Expected BadVAddr: %p\n" + " Returned BadVAddr: %p\n", + exceptionPC, tlbRefillEPC, + (void*)badAddress, tlbRefillBadVAddr + ); + + dbgmsg("TLB Refill handler test completed\n"); + SleepThread(); +} diff --git a/tlbrefill/tlbrefill.elf b/tlbrefill/tlbrefill.elf new file mode 100755 index 0000000..c8fb80f Binary files /dev/null and b/tlbrefill/tlbrefill.elf differ diff --git a/tlbrefill/tlbrefillhandler.S b/tlbrefill/tlbrefillhandler.S new file mode 100755 index 0000000..be6b868 --- /dev/null +++ b/tlbrefill/tlbrefillhandler.S @@ -0,0 +1,24 @@ + +.text +.set noreorder + +.global tlbRefillHandler +.global tlbRefillEPC +.global tlbRefillBadVAddr + +.ent tlbRefillHandler +tlbRefillHandler: + mfc0 $k0, $8 # Fetch BadVAddr + sync.p + sw $k0, tlbRefillBadVAddr + + mfc0 $k0, $14 # Fetch EPC + sync.p + sw $k0, tlbRefillEPC + + addi $k0, $k0, 4 # Skip to the instruction after our bad store + mtc0 $k0, $14 # Set EPC + sync.p + eret # Exit this handler + nop +.end tlbRefillHandler