Rename vm.c to vminit.c, tlb.s to vm.s and annotate vm.s
This commit is contained in:
parent
b4355ab55f
commit
4017d5cba5
|
@ -8,7 +8,7 @@ The decomp project wraps all decompiled piracy checks in `#if PIRACYCHECKS` stat
|
|||
|
||||
## List of Piracy Checks
|
||||
|
||||
### bootPhase1
|
||||
### boot
|
||||
|
||||
**When Called:** On power-on before the legal screen appears.
|
||||
|
||||
|
@ -20,7 +20,7 @@ The decomp project wraps all decompiled piracy checks in `#if PIRACYCHECKS` stat
|
|||
|
||||
**When Called:** On every frame.
|
||||
|
||||
**What It Checks:** Checksums `bootPhase1` to make sure it hasn't been modified.
|
||||
**What It Checks:** Checksums `boot` to make sure it hasn't been modified.
|
||||
|
||||
**Payload:** Writes 40 bytes of 0xff to 0x80095210. This appears to be related to sound effects but has no obvious effect.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#define LIBFILES(section) \
|
||||
build/ROMID/lib/tlb.o (section); \
|
||||
build/ROMID/lib/vm.o (section); \
|
||||
build/ROMID/lib/segments.o (section); \
|
||||
build/ROMID/lib/boot.o (section); \
|
||||
build/ROMID/lib/sched.o (section); \
|
||||
|
@ -26,7 +26,7 @@
|
|||
build/ROMID/lib/ultra/io/conteeplongwrite.o (section); \
|
||||
build/ROMID/lib/ultra/io/pfsresizefile.o (section); \
|
||||
build/ROMID/lib/ultra/io/pfsinitpak.o (section); \
|
||||
build/ROMID/lib/vm.o (section); \
|
||||
build/ROMID/lib/vminit.o (section); \
|
||||
build/ROMID/lib/rzip.o (section); \
|
||||
build/ROMID/lib/audiomgr.o (section); \
|
||||
build/ROMID/lib/audiodma.o (section); \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#define LIBFILES(section) \
|
||||
build/ROMID/lib/tlb.o (section); \
|
||||
build/ROMID/lib/vm.o (section); \
|
||||
build/ROMID/lib/segments.o (section); \
|
||||
build/ROMID/lib/boot.o (section); \
|
||||
build/ROMID/lib/sched.o (section); \
|
||||
|
@ -27,7 +27,7 @@
|
|||
build/ROMID/lib/ultra/io/conteeplongwrite.o (section); \
|
||||
build/ROMID/lib/ultra/io/pfsresizefile.o (section); \
|
||||
build/ROMID/lib/ultra/io/pfsinitpak.o (section); \
|
||||
build/ROMID/lib/vm.o (section); \
|
||||
build/ROMID/lib/vminit.o (section); \
|
||||
build/ROMID/lib/rzip.o (section); \
|
||||
build/ROMID/lib/audiomgr.o (section); \
|
||||
build/ROMID/lib/audiodma.o (section); \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#define LIBFILES(section) \
|
||||
build/ROMID/lib/tlb.o (section); \
|
||||
build/ROMID/lib/vm.o (section); \
|
||||
build/ROMID/lib/segments.o (section); \
|
||||
build/ROMID/lib/boot.o (section); \
|
||||
build/ROMID/lib/sched.o (section); \
|
||||
|
@ -26,7 +26,7 @@
|
|||
build/ROMID/lib/ultra/io/conteeplongwrite.o (section); \
|
||||
build/ROMID/lib/ultra/io/pfsresizefile.o (section); \
|
||||
build/ROMID/lib/ultra/io/pfsinitpak.o (section); \
|
||||
build/ROMID/lib/vm.o (section); \
|
||||
build/ROMID/lib/vminit.o (section); \
|
||||
build/ROMID/lib/rzip.o (section); \
|
||||
build/ROMID/lib/audiomgr.o (section); \
|
||||
build/ROMID/lib/audiodma.o (section); \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#define LIBFILES(section) \
|
||||
build/ROMID/lib/tlb.o (section); \
|
||||
build/ROMID/lib/vm.o (section); \
|
||||
build/ROMID/lib/segments.o (section); \
|
||||
build/ROMID/lib/boot.o (section); \
|
||||
build/ROMID/lib/sched.o (section); \
|
||||
|
@ -26,7 +26,7 @@
|
|||
build/ROMID/lib/ultra/io/conteeplongwrite.o (section); \
|
||||
build/ROMID/lib/ultra/io/pfsresizefile.o (section); \
|
||||
build/ROMID/lib/ultra/io/pfsinitpak.o (section); \
|
||||
build/ROMID/lib/vm.o (section); \
|
||||
build/ROMID/lib/vminit.o (section); \
|
||||
build/ROMID/lib/rzip.o (section); \
|
||||
build/ROMID/lib/audiomgr.o (section); \
|
||||
build/ROMID/lib/audiodma.o (section); \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#define LIBFILES(section) \
|
||||
build/ROMID/lib/tlb.o (section); \
|
||||
build/ROMID/lib/vm.o (section); \
|
||||
build/ROMID/lib/segments.o (section); \
|
||||
build/ROMID/lib/boot.o (section); \
|
||||
build/ROMID/lib/sched.o (section); \
|
||||
|
@ -26,7 +26,7 @@
|
|||
build/ROMID/lib/ultra/io/conteeplongwrite.o (section); \
|
||||
build/ROMID/lib/ultra/io/pfsresizefile.o (section); \
|
||||
build/ROMID/lib/ultra/io/pfsinitpak.o (section); \
|
||||
build/ROMID/lib/vm.o (section); \
|
||||
build/ROMID/lib/vminit.o (section); \
|
||||
build/ROMID/lib/rzip.o (section); \
|
||||
build/ROMID/lib/audiomgr.o (section); \
|
||||
build/ROMID/lib/audiodma.o (section); \
|
||||
|
|
4
ld/pd.ld
4
ld/pd.ld
|
@ -145,11 +145,11 @@ SECTIONS
|
|||
END_SEG(preamble)
|
||||
|
||||
/**
|
||||
/* tlbInit()'s address is 0x70001050, but preamble calls it by 0x80001050
|
||||
/* vmBoot()'s address is 0x70001050, but preamble calls it by 0x80001050
|
||||
* due to it not being TLB mapped yet. So we set up this variable to allow
|
||||
* this to happen.
|
||||
*/
|
||||
tlbInitFromPreamble = tlbInit + 0x10000000;
|
||||
vmBootFromPreamble = vmBoot + 0x10000000;
|
||||
|
||||
/***************************************************************************
|
||||
* lib
|
||||
|
|
|
@ -25,7 +25,7 @@ extern u32 g_VmNumPageMisses;
|
|||
extern u32 g_VmNumPageReplaces;
|
||||
extern u8 *g_VmMarker;
|
||||
extern u32 g_VmRamEnd;
|
||||
extern u32 g_VmStateTableEnd;
|
||||
extern u32 g_VmVirtualToPhysicalTableEnd;
|
||||
extern AMAudioMgr g_AudioManager;
|
||||
extern Mtx *var80092870;
|
||||
extern s32 g_SndMaxFxBusses;
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
#define _IN_LIB_BOOT_H
|
||||
#include <ultra64.h>
|
||||
|
||||
void bootPhase1(void);
|
||||
void boot(void);
|
||||
s32 bootGetMemSize(void);
|
||||
void *bootAllocateStack(s32 threadid, s32 size);
|
||||
void bootPhase2(void *arg);
|
||||
void bootCreateThreads(void *arg);
|
||||
void bootCheckStackOverflow(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
#define _IN_LIB_TLB_H
|
||||
#include <ultra64.h>
|
||||
|
||||
void tlbInit(void);
|
||||
void tlb000010a4(void);
|
||||
void tlb0000113c(void);
|
||||
void tlbHandleMiss(void);
|
||||
void tlbUnmapRange(u32 first, u32 last);
|
||||
void vmBoot(void);
|
||||
void vmInitVars(void);
|
||||
void vmInitVacant(void);
|
||||
void vmHandleMiss(void);
|
||||
void vmUnmapRange(u32 first, u32 last);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,11 +1,29 @@
|
|||
#ifndef _IN_LIB_VM_H
|
||||
#define _IN_LIB_VM_H
|
||||
|
||||
#ifdef _LANGUAGE_C
|
||||
#include <ultra64.h>
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
|
||||
extern u8 g_VmShowStats;
|
||||
|
||||
u32 vmInit(void);
|
||||
void vmInit(void);
|
||||
#endif
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
#define VM_NUM_SLOTS 268
|
||||
#else
|
||||
#define VM_NUM_SLOTS 266
|
||||
#endif
|
||||
|
||||
#define VM_PAGE_SIZE_SHIFT 12
|
||||
#define VM_PAGE_SIZE (1 << VM_PAGE_SIZE_SHIFT)
|
||||
|
||||
#define VM_BIGGEST_ZIP 0x1c80
|
||||
|
||||
#define VM_VACANTBITS_LEN ((VM_NUM_SLOTS + 7) / 8)
|
||||
|
||||
#define VM_VIRTUAL_ADDR 0x7f000000
|
||||
|
||||
#endif
|
||||
|
|
|
@ -72,7 +72,7 @@ u32 __osSetFpcCsr(u32 arg0);
|
|||
* in RAM thanks to this but need to be relocated, and .data and lib need to be
|
||||
* unzipped too.
|
||||
*/
|
||||
void bootPhase1(void)
|
||||
void boot(void)
|
||||
{
|
||||
s32 datacomplen;
|
||||
s32 inflatelen;
|
||||
|
@ -135,7 +135,7 @@ void bootPhase1(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
tlbUnmapRange(1, NTLBENTRIES);
|
||||
vmUnmapRange(1, NTLBENTRIES);
|
||||
|
||||
// Clear the stack allocation pointers
|
||||
for (i = 0; i < ARRAYCOUNT(g_StackLeftAddrs); i++) {
|
||||
|
@ -168,7 +168,7 @@ void bootPhase1(void)
|
|||
#endif
|
||||
|
||||
// Create and start the main thread
|
||||
osCreateThread(&g_MainThread, THREAD_MAIN, bootPhase2, NULL, bootAllocateStack(THREAD_MAIN, STACKSIZE_MAIN), THREADPRI_MAIN);
|
||||
osCreateThread(&g_MainThread, THREAD_MAIN, bootCreateThreads, NULL, bootAllocateStack(THREAD_MAIN, STACKSIZE_MAIN), THREADPRI_MAIN);
|
||||
osStartThread(&g_MainThread);
|
||||
}
|
||||
|
||||
|
@ -266,7 +266,7 @@ void bootCreateSchedThread(void)
|
|||
g_SchedCmdQ = osScGetCmdQ(&g_Sched);
|
||||
}
|
||||
|
||||
void bootPhase2(void *arg)
|
||||
void bootCreateThreads(void *arg)
|
||||
{
|
||||
bootCreateIdleThread();
|
||||
videbugCreate();
|
||||
|
|
|
@ -355,7 +355,7 @@ u32 crashGetParentStackFrame(u32 *origptr, u32 *minaddr, u32 origsp, u32 *regs)
|
|||
bool crashIsReturnAddress(u32 *instruction)
|
||||
{
|
||||
if (((uintptr_t)instruction % 4) == 0
|
||||
&& (uintptr_t)instruction >= (uintptr_t)tlbInit
|
||||
&& (uintptr_t)instruction >= (uintptr_t)vmBoot
|
||||
&& (uintptr_t)instruction <= (uintptr_t)&_libSegmentEnd) {
|
||||
// This condition can never pass because 9 is masked out
|
||||
if ((instruction[-2] & 0xfc00003c) == 9) {
|
||||
|
|
|
@ -412,9 +412,9 @@ void mainInit(void)
|
|||
addr -= STACKSIZE_AUDIO;
|
||||
addr -= 8; // markers for stack overflow detection
|
||||
addr -= g_VmNumPages * 8; // vm state table
|
||||
addr -= 268 * 4096; // vm loaded pages buffer
|
||||
addr -= VM_NUM_SLOTS * VM_PAGE_SIZE; // vm loaded pages buffer
|
||||
addr -= addr % 0x2000; // align down to a multiple of 0x2000
|
||||
addr -= 0x1c80; // buffer for single biggest game zip
|
||||
addr -= VM_BIGGEST_ZIP; // buffer for single biggest game zip
|
||||
} else {
|
||||
addr = K0BASE + 8 * 1024 * 1024;
|
||||
}
|
||||
|
@ -557,9 +557,9 @@ void mainInit(void)
|
|||
addr -= STACKSIZE_SCHED;
|
||||
addr -= STACKSIZE_AUDIO;
|
||||
addr -= g_VmNumPages * 8; // vm state table
|
||||
addr -= 266 * 4096; // vm loaded pages buffer
|
||||
addr -= VM_NUM_SLOTS * VM_PAGE_SIZE; // vm loaded pages buffer
|
||||
addr -= addr % 0x2000; // align down to a multiple of 0x2000
|
||||
addr -= 0x1c80; // buffer for single biggest game zip
|
||||
addr -= VM_BIGGEST_ZIP; // buffer for single biggest game zip
|
||||
} else {
|
||||
addr = K0BASE + 8 * 1024 * 1024;
|
||||
}
|
||||
|
|
|
@ -402,7 +402,7 @@ void __scHandleTasks(OSSched *sc)
|
|||
{
|
||||
u32 checksum = 0;
|
||||
s32 *end = (s32 *)&bootAllocateStack;
|
||||
s32 *ptr = (s32 *)&bootPhase1;
|
||||
s32 *ptr = (s32 *)&boot;
|
||||
s32 i;
|
||||
|
||||
while (ptr < end) {
|
||||
|
|
527
src/lib/tlb.s
527
src/lib/tlb.s
|
@ -1,527 +0,0 @@
|
|||
#include "os_tlb.h"
|
||||
#include "asm_helper.h"
|
||||
#include "macros.inc"
|
||||
#include "versions.h"
|
||||
.set noat
|
||||
.set noreorder
|
||||
|
||||
.bss
|
||||
.balign 4
|
||||
|
||||
glabel var8008ae20
|
||||
.space 4
|
||||
|
||||
glabel g_VmStateTable
|
||||
.space 4
|
||||
|
||||
glabel g_VmInitialised
|
||||
.space 4
|
||||
|
||||
glabel g_VmZipBuffer
|
||||
.space 4
|
||||
|
||||
glabel g_VmZipTable
|
||||
.space 8
|
||||
|
||||
glabel var8008ae38
|
||||
.space 0x1000
|
||||
|
||||
glabel var8008be38
|
||||
.space 0x1400
|
||||
|
||||
glabel var8008d238
|
||||
.space 0x20
|
||||
|
||||
glabel var8008d258
|
||||
.space 4
|
||||
|
||||
glabel var8008d25c
|
||||
.space 4
|
||||
|
||||
glabel var8008d260
|
||||
.space 4
|
||||
|
||||
glabel var8008d264
|
||||
.space 4
|
||||
|
||||
glabel var8008d268
|
||||
.space 4
|
||||
|
||||
.text
|
||||
|
||||
/**
|
||||
* Sets up TLB index 0 (0x70000000), then calls bootPhase1.
|
||||
*/
|
||||
glabel tlbInit
|
||||
li $t0, OS_PM_4M
|
||||
mtc0 $t0, C0_PAGEMASK
|
||||
lui $t0, 0x7000
|
||||
mtc0 $t0, C0_ENTRYHI
|
||||
li $t0, 0x1f
|
||||
mtc0 $t0, C0_ENTRYLO0
|
||||
lui $t0, 0x1
|
||||
ori $t0, $t0, 0x1f
|
||||
mtc0 $t0, C0_ENTRYLO1
|
||||
li $t0, 0
|
||||
mtc0 $t0, C0_INX
|
||||
nop
|
||||
tlbwi
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
lui $t0, %hi(bootPhase1)
|
||||
addiu $t0, $t0, %lo(bootPhase1)
|
||||
jr $t0
|
||||
nop
|
||||
|
||||
glabel tlb000010a4
|
||||
addiu $sp, $sp, -8
|
||||
sw $ra, 0x0($sp)
|
||||
mtc0 $zero, C0_CONTEXT
|
||||
li $t0, 0x2
|
||||
mtc0 $t0, C0_WIRED
|
||||
li $t1, 0x1ff
|
||||
lui $at, %hi(var8008d264+0x2)
|
||||
sh $t1, %lo(var8008d264+0x2)($at)
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
li $a0, 268
|
||||
#else
|
||||
li $a0, 266
|
||||
#endif
|
||||
lui $at, %hi(g_VmInitialised+0x2)
|
||||
sh $a0, %lo(g_VmInitialised+0x2)($at)
|
||||
lui $at, %hi(var8008d258+0x2)
|
||||
sh $a0, %lo(var8008d258+0x2)($at)
|
||||
sll $a0, $a0, 0xc
|
||||
lui $v0, %hi(var8008ae20)
|
||||
lw $v0, %lo(var8008ae20)($v0)
|
||||
lui $t1, %hi(_gameSegmentEnd)
|
||||
addiu $t1, $t1, %lo(_gameSegmentEnd)
|
||||
lui $t2, %hi(_gameSegmentStart)
|
||||
addiu $t2, $t2, %lo(_gameSegmentStart)
|
||||
subu $t1, $t1, $t2
|
||||
lui $t0, 0xfff
|
||||
ori $t0, $t0, 0xffff
|
||||
and $v0, $v0, $t0
|
||||
lui $at, %hi(var8008d268)
|
||||
sw $v0, %lo(var8008d268)($at)
|
||||
lui $v0, %hi(var8008d238)
|
||||
addiu $v0, $v0, %lo(var8008d238)
|
||||
li $a0, 0x21
|
||||
lui $at, %hi(var8008d25c)
|
||||
sw $v0, %lo(var8008d25c)($at)
|
||||
addu $v1, $v0, $a0
|
||||
lui $at, %hi(var8008d260)
|
||||
sw $v1, %lo(var8008d260)($at)
|
||||
lw $ra, 0x0($sp)
|
||||
addiu $sp, $sp, 0x8
|
||||
jr $ra
|
||||
nop
|
||||
|
||||
glabel tlb0000113c
|
||||
li $t0, 0xff
|
||||
lui $v0, %hi(var8008d25c)
|
||||
lw $v0, %lo(var8008d25c)($v0)
|
||||
lui $v1, %hi(var8008d260)
|
||||
lw $v1, %lo(var8008d260)($v1)
|
||||
.L00001150:
|
||||
sb $t0, 0x0($v0)
|
||||
bne $v0, $v1, .L00001150
|
||||
addiu $v0, $v0, 1
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
li $a0, 4
|
||||
#else
|
||||
li $a0, 2
|
||||
#endif
|
||||
beqz $a0, .L00001178
|
||||
addiu $a0, $a0, -1
|
||||
li $t0, 2
|
||||
sllv $t0, $t0, $a0
|
||||
addiu $t0, $t0, -1
|
||||
sb $t0, 0x0($v1)
|
||||
.L00001178:
|
||||
jr $ra
|
||||
nop
|
||||
|
||||
glabel tlbHandleMiss
|
||||
mfc0 $t0, C0_CONTEXT
|
||||
sll $s5, $t0, 0x9
|
||||
lui $t1, 0x7f00
|
||||
sub $t0, $s5, $t1
|
||||
srl $t0, $t0, 0xc
|
||||
sll $t0, $t0, 0x3
|
||||
lui $t1, %hi(g_VmStateTable)
|
||||
lw $t1, %lo(g_VmStateTable)($t1)
|
||||
addu $s0, $t0, $t1
|
||||
lui $s8, 0x7f00
|
||||
slt $at, $s5, $s8
|
||||
bnez $at, .L0000162c
|
||||
nop
|
||||
lui $t1, %hi(g_VmRamEnd)
|
||||
lw $t1, %lo(g_VmRamEnd)($t1)
|
||||
slt $at, $s5, $t1
|
||||
beqz $at, .L0000162c
|
||||
nop
|
||||
#if VERSION < VERSION_NTSC_1_0
|
||||
lui $t2, %hi(g_VmNumTlbMisses)
|
||||
addiu $t2, $t2, %lo(g_VmNumTlbMisses)
|
||||
lw $t6, 0($t2)
|
||||
addiu $t6, $t6, 1
|
||||
sw $t6, 0($t2)
|
||||
#endif
|
||||
mfc0 $t9, C0_BADVADDR
|
||||
srl $t9, $t9, 0xc
|
||||
andi $t9, $t9, 0x1
|
||||
beqzl $t9, .L000011e0
|
||||
lw $s1, 0x0($s0)
|
||||
lw $s1, 0x8($s0)
|
||||
.L000011e0:
|
||||
bnezl $s1, .L000014c4
|
||||
li $t5, 0x1
|
||||
li $t5, 0x0
|
||||
lui $t1, %hi(var8008d25c)
|
||||
lw $t1, %lo(var8008d25c)($t1)
|
||||
lui $t2, %hi(var8008d260)
|
||||
lw $t2, %lo(var8008d260)($t2)
|
||||
.L000011fc:
|
||||
lbu $t0, 0x0($t1)
|
||||
beqz $t0, .L0000122c
|
||||
nop
|
||||
li $t6, 0x0
|
||||
li $t7, 0x1
|
||||
.L00001210:
|
||||
and $t8, $t0, $t7
|
||||
bnez $t8, .L0000123c
|
||||
nop
|
||||
addiu $t6, $t6, 0x1
|
||||
li $at, 0x8
|
||||
bne $t6, $at, .L00001210
|
||||
sll $t7, $t7, 0x1
|
||||
.L0000122c:
|
||||
bne $t1, $t2, .L000011fc
|
||||
addiu $t1, $t1, 0x1
|
||||
j .L00001570
|
||||
nop
|
||||
.L0000123c:
|
||||
xor $t0, $t0, $t7
|
||||
sb $t0, 0x0($t1)
|
||||
lui $t2, %hi(var8008d25c)
|
||||
lw $t2, %lo(var8008d25c)($t2)
|
||||
lui $s1, %hi(var8008d268)
|
||||
lw $s1, %lo(var8008d268)($s1)
|
||||
subu $t1, $t1, $t2
|
||||
sll $t1, $t1, 0x3
|
||||
addu $t0, $t6, $t1
|
||||
sll $t0, $t0, 0xc
|
||||
addu $s1, $s1, $t0
|
||||
.L00001268:
|
||||
#if VERSION < VERSION_NTSC_1_0
|
||||
lui $t2, %hi(g_VmNumPageMisses)
|
||||
addiu $t2, $t2, %lo(g_VmNumPageMisses)
|
||||
lw $t0, 0($t2)
|
||||
addiu $t0, $t0, 1
|
||||
sw $t0, 0($t2)
|
||||
#endif
|
||||
mfc0 $t2, C0_BADVADDR
|
||||
lui $t0, 0xff
|
||||
ori $t0, $t0, 0xf000
|
||||
and $t2, $t2, $t0
|
||||
srl $t2, $t2, 0xa
|
||||
lui $t0, %hi(g_VmZipTable)
|
||||
lw $t0, %lo(g_VmZipTable)($t0)
|
||||
addu $t0, $t0, $t2
|
||||
lw $t2, 0x0($t0)
|
||||
lw $t0, 0x4($t0)
|
||||
subu $t0, $t0, $t2
|
||||
li $t1, -16
|
||||
addiu $t0, $t0, 0xf
|
||||
and $t6, $t0, $t1
|
||||
lui $t0, 0xa460
|
||||
ori $t0, $t0, 0x10
|
||||
.L000012a8:
|
||||
lw $t1, 0x0($t0)
|
||||
andi $t1, $t1, 0x3
|
||||
bnez $t1, .L000012a8
|
||||
nop
|
||||
lui $s6, 0xa430
|
||||
lw $s6, 0x8($s6)
|
||||
andi $s6, $s6, 0x10
|
||||
lui $t0, 0xa460
|
||||
lui $t1, %hi(g_VmZipBuffer)
|
||||
lw $t1, %lo(g_VmZipBuffer)($t1)
|
||||
lui $t7, 0xfff
|
||||
ori $t7, $t7, 0xffff
|
||||
and $t1, $t1, $t7
|
||||
sw $t1, 0x0($t0)
|
||||
lui $t0, 0xa460
|
||||
ori $t0, $t0, 0x4
|
||||
lui $t1, 0x8000
|
||||
lw $t1, 0x308($t1)
|
||||
or $t1, $t1, $t2
|
||||
lui $t2, 0x1fff
|
||||
ori $t2, $t2, 0xffff
|
||||
and $t1, $t1, $t2
|
||||
sw $t1, 0x0($t0)
|
||||
lui $t0, 0xa460
|
||||
ori $t0, $t0, 0xc
|
||||
addiu $t6, $t6, -1
|
||||
sw $t6, 0x0($t0)
|
||||
beqzl $t9, .L00001324
|
||||
nop
|
||||
beqzl $zero, .L00001328
|
||||
sw $s1, 0x8($s0)
|
||||
.L00001324:
|
||||
sw $s1, 0x0($s0)
|
||||
.L00001328:
|
||||
lui $t0, 0xa460
|
||||
ori $t0, $t0, 0x10
|
||||
.L00001330:
|
||||
lw $t1, 0x0($t0)
|
||||
andi $t1, $t1, 0x3
|
||||
bnez $t1, .L00001330
|
||||
nop
|
||||
lui $t0, %hi(g_VmZipBuffer)
|
||||
lw $t0, %lo(g_VmZipBuffer)($t0)
|
||||
addiu $t1, $t0, 0x1000
|
||||
.L0000134c:
|
||||
cache 0x15, 0x0($t0)
|
||||
sltu $at, $t0, $t1
|
||||
bnez $at, .L0000134c
|
||||
addiu $t0, $t0, 16
|
||||
bnez $s6, .L00001370
|
||||
nop
|
||||
li $t0, 0x2
|
||||
lui $at, 0xa460
|
||||
sw $t0, 0x10($at)
|
||||
.L00001370:
|
||||
lui $a0, %hi(var8008ae38)
|
||||
addiu $a0, $a0, %lo(var8008ae38)
|
||||
addiu $a0, $a0, 0xff8
|
||||
sw $sp, 0x0($a0)
|
||||
addiu $sp, $a0, 0x0
|
||||
lui $a0, %hi(g_VmZipBuffer)
|
||||
lw $a0, %lo(g_VmZipBuffer)($a0)
|
||||
addiu $a0, $a0, 0x2
|
||||
lui $t0, 0x8000
|
||||
or $a1, $s1, $t0
|
||||
lui $a2, %hi(var8008be38)
|
||||
addiu $a2, $a2, %lo(var8008be38)
|
||||
addiu $sp, $sp, -128
|
||||
sw $ra, 0x0($sp)
|
||||
sw $at, 0x4($sp)
|
||||
sw $v0, 0x8($sp)
|
||||
sw $v1, 0xc($sp)
|
||||
sw $a0, 0x10($sp)
|
||||
sw $a1, 0x14($sp)
|
||||
sw $a2, 0x18($sp)
|
||||
sw $a3, 0x1c($sp)
|
||||
sw $t0, 0x20($sp)
|
||||
sw $t1, 0x24($sp)
|
||||
sw $t2, 0x28($sp)
|
||||
sw $t3, 0x2c($sp)
|
||||
sw $t4, 0x30($sp)
|
||||
sw $t5, 0x34($sp)
|
||||
sw $t6, 0x38($sp)
|
||||
sw $t7, 0x3c($sp)
|
||||
sw $s0, 0x40($sp)
|
||||
sw $s1, 0x44($sp)
|
||||
sw $s2, 0x48($sp)
|
||||
sw $s3, 0x4c($sp)
|
||||
sw $s4, 0x50($sp)
|
||||
sw $s5, 0x54($sp)
|
||||
sw $s6, 0x58($sp)
|
||||
sw $s7, 0x5c($sp)
|
||||
sw $t8, 0x60($sp)
|
||||
sw $t9, 0x64($sp)
|
||||
sw $gp, 0x70($sp)
|
||||
sw $sp, 0x74($sp)
|
||||
sw $s8, 0x78($sp)
|
||||
jal rzipInflate
|
||||
nop
|
||||
lw $ra, 0x0($sp)
|
||||
lw $at, 0x4($sp)
|
||||
lw $v0, 0x8($sp)
|
||||
lw $v1, 0xc($sp)
|
||||
lw $a0, 0x10($sp)
|
||||
lw $a1, 0x14($sp)
|
||||
lw $a2, 0x18($sp)
|
||||
lw $a3, 0x1c($sp)
|
||||
lw $t0, 0x20($sp)
|
||||
lw $t1, 0x24($sp)
|
||||
lw $t2, 0x28($sp)
|
||||
lw $t3, 0x2c($sp)
|
||||
lw $t4, 0x30($sp)
|
||||
lw $t5, 0x34($sp)
|
||||
lw $t6, 0x38($sp)
|
||||
lw $t7, 0x3c($sp)
|
||||
lw $s0, 0x40($sp)
|
||||
lw $s1, 0x44($sp)
|
||||
lw $s2, 0x48($sp)
|
||||
lw $s3, 0x4c($sp)
|
||||
lw $s4, 0x50($sp)
|
||||
lw $s5, 0x54($sp)
|
||||
lw $s6, 0x58($sp)
|
||||
lw $s7, 0x5c($sp)
|
||||
lw $t8, 0x60($sp)
|
||||
lw $t9, 0x64($sp)
|
||||
lw $gp, 0x70($sp)
|
||||
lw $sp, 0x74($sp)
|
||||
lw $s8, 0x78($sp)
|
||||
addiu $sp, $sp, 0x80
|
||||
lui $a0, %hi(var8008ae38)
|
||||
addiu $a0, $a0, %lo(var8008ae38)
|
||||
addiu $a0, $a0, 4088
|
||||
lw $sp, 0x0($a0)
|
||||
lui $t0, 0x8000
|
||||
or $t0, $s1, $t0
|
||||
addiu $t1, $t0, 0xff0
|
||||
.L000014b4:
|
||||
cache 0x19, 0x0($t0)
|
||||
sltu $at, $t0, $t1
|
||||
bnez $at, .L000014b4
|
||||
addiu $t0, $t0, 0x10
|
||||
.L000014c4:
|
||||
li $t0, OS_PM_4K
|
||||
mtc0 $t0, C0_PAGEMASK
|
||||
mtc0 $s5, C0_ENTRYHI
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
tlbp
|
||||
nop
|
||||
nop
|
||||
mfc0 $t1, C0_INX
|
||||
mtc0 $t0, C0_PAGEMASK
|
||||
mtc0 $s5, C0_ENTRYHI
|
||||
lw $t0, 0x0($s0)
|
||||
srl $t0, $t0, 0xc
|
||||
sll $t0, $t0, 0x6
|
||||
bnezl $t0, .L00001508
|
||||
ori $t0, $t0, 0x1e
|
||||
.L00001508:
|
||||
mtc0 $t0, C0_ENTRYLO0
|
||||
lw $t0, 0x8($s0)
|
||||
srl $t0, $t0, 0xc
|
||||
sll $t0, $t0, 0x6
|
||||
bnezl $t0, .L00001520
|
||||
ori $t0, $t0, 0x1e
|
||||
.L00001520:
|
||||
mtc0 $t0, C0_ENTRYLO1
|
||||
bltzl $t1, .L00001534
|
||||
nop
|
||||
b .L00001538
|
||||
tlbwi
|
||||
.L00001534:
|
||||
tlbwr
|
||||
.L00001538:
|
||||
bnez $t5, .L00001568
|
||||
nop
|
||||
move $t0, $s5
|
||||
bnezl $t9, .L0000154c
|
||||
addiu $t0, $t0, 0x1000
|
||||
.L0000154c:
|
||||
addiu $t1, $t0, 0xfe0
|
||||
andi $t2, $t0, 0x1f
|
||||
subu $t0, $t0, $t2
|
||||
.L00001558:
|
||||
cache 0x10, 0x0($t0)
|
||||
sltu $at, $t0, $t1
|
||||
bnez $at, .L00001558
|
||||
addiu $t0, $t0, 0x20
|
||||
.L00001568:
|
||||
jr $ra
|
||||
nop
|
||||
.L00001570:
|
||||
#if VERSION < VERSION_NTSC_1_0
|
||||
lui $t0, %hi(g_VmNumPageReplaces)
|
||||
addiu $t0, $t0, %lo(g_VmNumPageReplaces)
|
||||
lw $t1, 0($t0)
|
||||
addiu $t1, $t1, 1
|
||||
sw $t1, 0($t0)
|
||||
#endif
|
||||
.L00001570_2:
|
||||
lui $s4, %hi(g_VmStateTable)
|
||||
lw $s4, %lo(g_VmStateTable)($s4)
|
||||
lui $gp, %hi(g_VmStateTableEnd)
|
||||
lw $gp, %lo(g_VmStateTableEnd)($gp)
|
||||
mfc0 $t0, C0_COUNT
|
||||
lui $t1, %hi(var8008d264+0x2)
|
||||
lhu $t1, %lo(var8008d264+0x2)($t1)
|
||||
lui $t2, %hi(g_VmNumPages)
|
||||
lw $t2, %lo(g_VmNumPages)($t2)
|
||||
and $t0, $t0, $t1
|
||||
slt $at, $t0, $t2
|
||||
beqzl $at, .L000015a4
|
||||
subu $t0, $t0, $t2
|
||||
.L000015a4:
|
||||
sll $t1, $t0, 0x3
|
||||
addu $t1, $t1, $s4
|
||||
.L000015ac:
|
||||
lw $s1, 0x0($t1)
|
||||
bnez $s1, .L000015cc
|
||||
nop
|
||||
addiu $t1, $t1, 8
|
||||
bne $t1, $gp, .L000015ac
|
||||
nop
|
||||
j .L000015ac
|
||||
move $t1, $s4
|
||||
.L000015cc:
|
||||
subu $t0, $t1, $s4
|
||||
srl $t0, $t0, 0x3
|
||||
sll $t0, $t0, 0xc
|
||||
addu $t0, $t0, $s8
|
||||
li $t2, -4096
|
||||
and $t0, $t0, $t2
|
||||
mtc0 $t0, C0_ENTRYHI
|
||||
li $t0, 0x0
|
||||
mtc0 $t0, C0_PAGEMASK
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
tlbp
|
||||
nop
|
||||
nop
|
||||
mfc0 $t2, C0_INX
|
||||
mfc0 $t0, C0_ENTRYHI
|
||||
bltz $t2, .L00001620
|
||||
nop
|
||||
j .L00001570_2
|
||||
nop
|
||||
.L00001620:
|
||||
sw $zero, 0x0($t1)
|
||||
j .L00001268
|
||||
nop
|
||||
.L0000162c:
|
||||
j handle_fault
|
||||
nop
|
||||
|
||||
glabel tlbUnmapRange
|
||||
mfc0 $t0, C0_ENTRYHI
|
||||
lui $t2, 0x8000
|
||||
mtc0 $t2, C0_ENTRYHI
|
||||
mtc0 $zero, C0_ENTRYLO0
|
||||
mtc0 $zero, C0_ENTRYLO1
|
||||
.L00001648:
|
||||
mtc0 $a1, C0_INX
|
||||
nop
|
||||
tlbwi
|
||||
nop
|
||||
nop
|
||||
bne $a1, $a0, .L00001648
|
||||
addi $a1, $a1, -1
|
||||
mtc0 $t0, C0_ENTRYHI
|
||||
jr $ra
|
||||
nop
|
||||
|
||||
#if VERSION < VERSION_NTSC_1_0
|
||||
glabel tlb000016acnb
|
||||
lui $t0, 0x8000
|
||||
addiu $t1, $t0, 0x1ff0
|
||||
.L000016b4:
|
||||
cache 0x1, 0x0($t0)
|
||||
sltu $at, $t0, $t1
|
||||
bnez $at, .L000016b4
|
||||
addiu $t0, $t0, 0x10
|
||||
jr $ra
|
||||
nop
|
||||
#endif
|
|
@ -436,7 +436,7 @@ glabel __osException
|
|||
and $s0, $s0, $at
|
||||
|
||||
.handle_rmiss:
|
||||
jal tlbHandleMiss
|
||||
jal vmHandleMiss
|
||||
nop
|
||||
b .dispatch_thread
|
||||
nop
|
||||
|
|
|
@ -0,0 +1,631 @@
|
|||
#include "os_tlb.h"
|
||||
#include "asm_helper.h"
|
||||
#include "macros.inc"
|
||||
#include "versions.h"
|
||||
#include "lib/vm.h"
|
||||
.set noat
|
||||
.set noreorder
|
||||
|
||||
.bss
|
||||
.balign 4
|
||||
|
||||
/**
|
||||
* Quick figures (correct for ntsc-final):
|
||||
* 443 pages
|
||||
* Page size is 4096 (ie. 4KB each)
|
||||
* Virtual range is 0x7f000000 to 0x7f1bb000 (0x7f000000 + 443 * 4096)
|
||||
*
|
||||
* There are 268 physical slots, meaning 268 pages can be loaded at a time.
|
||||
* There are 30-ish entries in the TLB, so only 30-ish can be mapped at a time.
|
||||
* Physical slots are in physical memory at 0x80220000 to 0x8032c000.
|
||||
*/
|
||||
|
||||
# Pointer to the physical slots where pages can be loaded (ie. 0x80220000).
|
||||
# Size = 268 * 4096
|
||||
glabel g_VmPhysicalSlots
|
||||
.space 4
|
||||
|
||||
# Pointer to the virtual-to-physical (V2P) table.
|
||||
# Each entry is 8 bytes and there is one entry for each virtual page.
|
||||
# The first word is the physical address where the page is loaded, or 0 if not loaded.
|
||||
# The second word is unused.
|
||||
# An example physical address is 0x00220000.
|
||||
# Size = 443 * 8
|
||||
glabel g_VmVirtualToPhysicalTable
|
||||
.space 4
|
||||
|
||||
# Set but never read
|
||||
glabel g_VmInitialised
|
||||
.space 1
|
||||
.align 1
|
||||
|
||||
# The number of pages that can be loaded at any one time (268).
|
||||
# Written but never read.
|
||||
glabel g_VmNumSlots
|
||||
.space 2
|
||||
|
||||
# Pointer to a buffer that's big enough to hold the biggest zip file.
|
||||
glabel g_VmZipBuffer
|
||||
.space 4
|
||||
|
||||
# Pointer to an array of ROM offsets where each zip can be found.
|
||||
# Size = 443 * sizeof(void *)
|
||||
glabel g_VmZipTable
|
||||
.space 4
|
||||
|
||||
# Temporary stack space. Used when unzipping a page.
|
||||
.align 3
|
||||
glabel g_VmTempStack
|
||||
.space 0x1000
|
||||
|
||||
# A scratch area that can be used by rzipInflate.
|
||||
glabel g_VmScratch
|
||||
.space 0x1400
|
||||
|
||||
# Array where each bit represents a physical slot (268 bits).
|
||||
# Bits are 1 if the slot is vacant.
|
||||
glabel g_VmVacantBits
|
||||
.space VM_VACANTBITS_LEN
|
||||
|
||||
# The number of pages that can be loaded at any one time (268).
|
||||
# Written but never read.
|
||||
# Duplicate of g_VmNumSlots.
|
||||
glabel g_VmNumSlots2
|
||||
.space 2
|
||||
|
||||
# Pointer to the first byte in the g_VmVacantBits array. Never changed once set.
|
||||
glabel g_VmVacantFirstByte
|
||||
.space 4
|
||||
|
||||
# Pointer to the last byte in the g_VmVacantBits array. Never changed once set.
|
||||
glabel g_VmVacantLastByte
|
||||
.space 4
|
||||
|
||||
# Unused.
|
||||
glabel var8008d264
|
||||
.space 2
|
||||
|
||||
# Masked with C0_COUNT to choose which page to replace.
|
||||
# Initialised with the value 0x1ff then never changed.
|
||||
glabel g_VmEvictMask
|
||||
.space 2
|
||||
|
||||
# The physical address of the slots (0x00220000).
|
||||
glabel g_VmSlotsPhysicalAddr
|
||||
.space 4
|
||||
|
||||
.text
|
||||
|
||||
/**
|
||||
* Sets up TLB index 0 (0x70000000), then calls boot.
|
||||
*/
|
||||
glabel vmBoot
|
||||
li $t0, OS_PM_4M
|
||||
mtc0 $t0, C0_PAGEMASK
|
||||
li $t0, 0x70000000
|
||||
mtc0 $t0, C0_ENTRYHI
|
||||
li $t0, 0x1f
|
||||
mtc0 $t0, C0_ENTRYLO0
|
||||
li $t0, 0x1001f
|
||||
mtc0 $t0, C0_ENTRYLO1
|
||||
li $t0, 0
|
||||
mtc0 $t0, C0_INX
|
||||
nop
|
||||
tlbwi
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
la $t0, boot
|
||||
jr $t0
|
||||
nop
|
||||
|
||||
glabel vmInitVars
|
||||
addiu $sp, $sp, -8
|
||||
sw $ra, 0x0($sp)
|
||||
|
||||
mtc0 $zero, C0_CONTEXT
|
||||
|
||||
li $t0, 2
|
||||
mtc0 $t0, C0_WIRED
|
||||
|
||||
li $t1, 0x1ff
|
||||
lui $at, %hi(g_VmEvictMask)
|
||||
sh $t1, %lo(g_VmEvictMask)($at)
|
||||
|
||||
li $a0, VM_NUM_SLOTS
|
||||
lui $at, %hi(g_VmNumSlots)
|
||||
sh $a0, %lo(g_VmNumSlots)($at)
|
||||
|
||||
lui $at, %hi(g_VmNumSlots2)
|
||||
sh $a0, %lo(g_VmNumSlots2)($at)
|
||||
|
||||
sll $a0, $a0, VM_PAGE_SIZE_SHIFT
|
||||
|
||||
lw $v0, g_VmPhysicalSlots
|
||||
la $t1, _gameSegmentEnd # unused
|
||||
la $t2, _gameSegmentStart # unused
|
||||
subu $t1, $t1, $t2 # unused
|
||||
li $t0, 0x0fffffff
|
||||
and $v0, $v0, $t0
|
||||
lui $at, %hi(g_VmSlotsPhysicalAddr)
|
||||
sw $v0, %lo(g_VmSlotsPhysicalAddr)($at)
|
||||
|
||||
la $v0, g_VmVacantBits
|
||||
li $a0, VM_VACANTBITS_LEN - 1
|
||||
lui $at, %hi(g_VmVacantFirstByte)
|
||||
sw $v0, %lo(g_VmVacantFirstByte)($at)
|
||||
|
||||
addu $v1, $v0, $a0
|
||||
lui $at, %hi(g_VmVacantLastByte)
|
||||
sw $v1, %lo(g_VmVacantLastByte)($at)
|
||||
|
||||
lw $ra, 0x0($sp)
|
||||
addiu $sp, $sp, 8
|
||||
jr $ra
|
||||
nop
|
||||
|
||||
glabel vmInitVacant
|
||||
# Fill array with 0xff (ie. all vacant)
|
||||
li $t0, 0xff
|
||||
lw $v0, g_VmVacantFirstByte
|
||||
lw $v1, g_VmVacantLastByte
|
||||
.fill_loop:
|
||||
sb $t0, 0x0($v0)
|
||||
bne $v0, $v1, .fill_loop
|
||||
addiu $v0, $v0, 1
|
||||
|
||||
# Set the last byte with a partial bitmask based on the number of page slots
|
||||
li $a0, VM_NUM_SLOTS % 8
|
||||
beqz $a0, .after_remainder
|
||||
addiu $a0, $a0, -1
|
||||
li $t0, 2
|
||||
sllv $t0, $t0, $a0
|
||||
addiu $t0, $t0, -1
|
||||
sb $t0, 0x0($v1)
|
||||
.after_remainder:
|
||||
jr $ra
|
||||
nop
|
||||
|
||||
/**
|
||||
* vmHandleMiss is called from the exception handler when a request is made to
|
||||
* access a virtual memory address that isn't currently mapped in the TLB.
|
||||
* vmHandleMiss must load the page from ROM if not already loaded, then map it
|
||||
* in the TLB.
|
||||
*
|
||||
* In NTSC Final, there are 443 virtual pages, 268 slots where these can be loaded,
|
||||
* and 30 of these can be mapped in the TLB at the same time.
|
||||
*/
|
||||
glabel vmHandleMiss
|
||||
# C0_CONTEXT must be the 512-byte chunk index that was requested?
|
||||
# Convert it to a virtual address
|
||||
mfc0 $t0, C0_CONTEXT
|
||||
sll $s5, $t0, 9
|
||||
li $t1, VM_VIRTUAL_ADDR
|
||||
sub $t0, $s5, $t1
|
||||
srl $t0, $t0, VM_PAGE_SIZE_SHIFT # t0 = virtual page index
|
||||
|
||||
# Multiply t0 by 8 to get the V2P table offset
|
||||
sll $t0, $t0, 3
|
||||
lw $t1, g_VmVirtualToPhysicalTable
|
||||
addu $s0, $t0, $t1 # s0 = pointer to V2P entry
|
||||
|
||||
# Check that the requested address is within the virtual range
|
||||
li $s8, VM_VIRTUAL_ADDR
|
||||
slt $at, $s5, $s8
|
||||
bnez $at, .out_of_range
|
||||
nop
|
||||
lw $t1, g_VmRamEnd
|
||||
slt $at, $s5, $t1
|
||||
beqz $at, .out_of_range
|
||||
nop
|
||||
|
||||
#if VERSION < VERSION_NTSC_1_0
|
||||
# Increment g_VmNumTlbMisses
|
||||
la $t2, g_VmNumTlbMisses
|
||||
lw $t6, 0($t2)
|
||||
addiu $t6, $t6, 1
|
||||
sw $t6, 0($t2)
|
||||
#endif
|
||||
|
||||
# If the page index is even then read the current slot's unk00.
|
||||
# If the page index is odd then read from the next slot's unk00.
|
||||
mfc0 $t9, C0_BADVADDR
|
||||
srl $t9, $t9, VM_PAGE_SIZE_SHIFT
|
||||
andi $t9, $t9, 1
|
||||
beqzl $t9, .after_odd_even_check1
|
||||
lw $s1, 0x0($s0)
|
||||
lw $s1, 0x8($s0)
|
||||
.after_odd_even_check1:
|
||||
bnezl $s1, .map_tlb # Page is already loaded, so just map it
|
||||
li $t5, 1
|
||||
li $t5, 0
|
||||
lw $t1, g_VmVacantFirstByte
|
||||
lw $t2, g_VmVacantLastByte
|
||||
|
||||
# Find any bit that is set in the byte array
|
||||
.find_byte_loop:
|
||||
lbu $t0, 0x0($t1)
|
||||
beqz $t0, .after_bit_loop
|
||||
nop
|
||||
li $t6, 0
|
||||
li $t7, 1
|
||||
.find_bit_loop:
|
||||
and $t8, $t0, $t7
|
||||
bnez $t8, .use_empty_slot
|
||||
nop
|
||||
addiu $t6, $t6, 1
|
||||
li $at, 8
|
||||
bne $t6, $at, .find_bit_loop
|
||||
sll $t7, $t7, 1
|
||||
.after_bit_loop:
|
||||
bne $t1, $t2, .find_byte_loop
|
||||
addiu $t1, $t1, 1
|
||||
|
||||
# All slots are allocated
|
||||
j .choose_page_to_replace
|
||||
nop
|
||||
|
||||
.use_empty_slot:
|
||||
# t0 is the available byte's value
|
||||
# t1 is a pointer to the available byte
|
||||
# t6 is the bit index (0-7) of the available bit
|
||||
# t7 is the bit power (1, 2, 4.. 128) of the available bit
|
||||
xor $t0, $t0, $t7
|
||||
sb $t0, 0x0($t1)
|
||||
lw $t2, g_VmVacantFirstByte
|
||||
lw $s1, g_VmSlotsPhysicalAddr
|
||||
subu $t1, $t1, $t2 # t1 = byte index
|
||||
sll $t1, $t1, 3 # t1 now a V2P table byte offset
|
||||
addu $t0, $t6, $t1 # t0 = offset to V2P table entry
|
||||
sll $t0, $t0, VM_PAGE_SIZE_SHIFT # t0 now the virtual page index of the empty slot
|
||||
addu $s1, $s1, $t0
|
||||
|
||||
.load_page:
|
||||
#if VERSION < VERSION_NTSC_1_0
|
||||
# Increment g_VmNumPageMisses
|
||||
la $t2, g_VmNumPageMisses
|
||||
lw $t0, 0($t2)
|
||||
addiu $t0, $t0, 1
|
||||
sw $t0, 0($t2)
|
||||
#endif
|
||||
|
||||
# Calculate the offset of the entry in the zip table.
|
||||
# The zip table is an array of ROM offsets where each zip can be found.
|
||||
mfc0 $t2, C0_BADVADDR
|
||||
li $t0, 0x01000000 - VM_PAGE_SIZE
|
||||
and $t2, $t2, $t0
|
||||
srl $t2, $t2, 10
|
||||
lw $t0, g_VmZipTable
|
||||
addu $t0, $t0, $t2
|
||||
|
||||
lw $t2, 0x0($t0) # t2 = zip ROM start address
|
||||
lw $t0, 0x4($t0) # t0 = zip ROM end address
|
||||
subu $t0, $t0, $t2 # t0 = zip length (compressed)
|
||||
|
||||
# Align the zip length to 0x10
|
||||
li $t1, 0xfffffff0
|
||||
addiu $t0, $t0, 15
|
||||
and $t6, $t0, $t1
|
||||
|
||||
# Wait for the PI to be available
|
||||
li $t0, PHYS_TO_K1(PI_STATUS_REG)
|
||||
.wait_for_pi_ready_loop:
|
||||
lw $t1, 0x0($t0)
|
||||
andi $t1, $t1, PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY
|
||||
bnez $t1, .wait_for_pi_ready_loop
|
||||
nop
|
||||
|
||||
# Check if the PI has a pending interrupt - this will be used after the DMA
|
||||
lw $s6, PHYS_TO_K1(MI_INTR_REG)
|
||||
andi $s6, $s6, MI_INTR_PI
|
||||
|
||||
# Set PI_DRAM_ADDR_REG to g_VmZipBuffer (where the zip will be loaded to)
|
||||
li $t0, PHYS_TO_K1(PI_DRAM_ADDR_REG)
|
||||
lw $t1, g_VmZipBuffer
|
||||
li $t7, 0x0fffffff
|
||||
and $t1, $t1, $t7
|
||||
sw $t1, 0x0($t0)
|
||||
|
||||
# Set PI_CART_ADDR_REG to the ROM address of the zip
|
||||
li $t0, PHYS_TO_K1(PI_CART_ADDR_REG)
|
||||
lw $t1, osRomBase
|
||||
or $t1, $t1, $t2
|
||||
li $t2, 0x1fffffff
|
||||
and $t1, $t1, $t2
|
||||
sw $t1, 0x0($t0)
|
||||
|
||||
# Set PI_WR_LEN_REG to the aligned size of the zip
|
||||
li $t0, PHYS_TO_K1(PI_WR_LEN_REG)
|
||||
addiu $t6, $t6, -1
|
||||
sw $t6, 0x0($t0)
|
||||
|
||||
beqzl $t9, .after_odd_even_check2
|
||||
nop
|
||||
beqzl $zero, .pointless_branch
|
||||
sw $s1, 0x8($s0)
|
||||
.after_odd_even_check2:
|
||||
sw $s1, 0x0($s0)
|
||||
|
||||
.pointless_branch:
|
||||
li $t0, PHYS_TO_K1(PI_STATUS_REG)
|
||||
.wait_for_pi_dma_completed_loop:
|
||||
lw $t1, 0x0($t0)
|
||||
andi $t1, $t1, PI_STATUS_DMA_BUSY | PI_STATUS_IO_BUSY
|
||||
bnez $t1, .wait_for_pi_dma_completed_loop
|
||||
nop
|
||||
|
||||
# Invalidate cache in the zip buffer area
|
||||
lw $t0, g_VmZipBuffer
|
||||
addiu $t1, $t0, VM_PAGE_SIZE
|
||||
.invalidate_dcache_loop:
|
||||
cache 0x15, 0x0($t0)
|
||||
sltu $at, $t0, $t1
|
||||
bnez $at, .invalidate_dcache_loop
|
||||
addiu $t0, $t0, 16
|
||||
|
||||
# If the PI didn't previously have a pending interrupt,
|
||||
# make sure the above work hasn't triggered one
|
||||
bnez $s6, .after_clear_pi_interrupt
|
||||
nop
|
||||
li $t0, PI_CLR_INTR
|
||||
lui $at, %hi(PHYS_TO_K1(PI_STATUS_REG))
|
||||
sw $t0, %lo(PHYS_TO_K1(PI_STATUS_REG))($at)
|
||||
|
||||
.after_clear_pi_interrupt:
|
||||
# Set stack pointer to g_VmTempStack
|
||||
la $a0, g_VmTempStack
|
||||
addiu $a0, $a0, 0xff8
|
||||
sw $sp, 0x0($a0)
|
||||
addiu $sp, $a0, 0
|
||||
|
||||
# Prepare arguments for rzipInflate
|
||||
lw $a0, g_VmZipBuffer
|
||||
addiu $a0, $a0, 2 # Move past the 2-byte checksum
|
||||
li $t0, K0BASE
|
||||
or $a1, $s1, $t0
|
||||
la $a2, g_VmScratch
|
||||
|
||||
# Save registers to the stack
|
||||
addiu $sp, $sp, -0x80
|
||||
sw $ra, 0x0($sp)
|
||||
sw $at, 0x4($sp)
|
||||
sw $v0, 0x8($sp)
|
||||
sw $v1, 0xc($sp)
|
||||
sw $a0, 0x10($sp)
|
||||
sw $a1, 0x14($sp)
|
||||
sw $a2, 0x18($sp)
|
||||
sw $a3, 0x1c($sp)
|
||||
sw $t0, 0x20($sp)
|
||||
sw $t1, 0x24($sp)
|
||||
sw $t2, 0x28($sp)
|
||||
sw $t3, 0x2c($sp)
|
||||
sw $t4, 0x30($sp)
|
||||
sw $t5, 0x34($sp)
|
||||
sw $t6, 0x38($sp)
|
||||
sw $t7, 0x3c($sp)
|
||||
sw $s0, 0x40($sp)
|
||||
sw $s1, 0x44($sp)
|
||||
sw $s2, 0x48($sp)
|
||||
sw $s3, 0x4c($sp)
|
||||
sw $s4, 0x50($sp)
|
||||
sw $s5, 0x54($sp)
|
||||
sw $s6, 0x58($sp)
|
||||
sw $s7, 0x5c($sp)
|
||||
sw $t8, 0x60($sp)
|
||||
sw $t9, 0x64($sp)
|
||||
sw $gp, 0x70($sp)
|
||||
sw $sp, 0x74($sp)
|
||||
sw $s8, 0x78($sp)
|
||||
|
||||
# Unzip the zip
|
||||
jal rzipInflate
|
||||
nop
|
||||
|
||||
# Reload registers from the stack
|
||||
lw $ra, 0x0($sp)
|
||||
lw $at, 0x4($sp)
|
||||
lw $v0, 0x8($sp)
|
||||
lw $v1, 0xc($sp)
|
||||
lw $a0, 0x10($sp)
|
||||
lw $a1, 0x14($sp)
|
||||
lw $a2, 0x18($sp)
|
||||
lw $a3, 0x1c($sp)
|
||||
lw $t0, 0x20($sp)
|
||||
lw $t1, 0x24($sp)
|
||||
lw $t2, 0x28($sp)
|
||||
lw $t3, 0x2c($sp)
|
||||
lw $t4, 0x30($sp)
|
||||
lw $t5, 0x34($sp)
|
||||
lw $t6, 0x38($sp)
|
||||
lw $t7, 0x3c($sp)
|
||||
lw $s0, 0x40($sp)
|
||||
lw $s1, 0x44($sp)
|
||||
lw $s2, 0x48($sp)
|
||||
lw $s3, 0x4c($sp)
|
||||
lw $s4, 0x50($sp)
|
||||
lw $s5, 0x54($sp)
|
||||
lw $s6, 0x58($sp)
|
||||
lw $s7, 0x5c($sp)
|
||||
lw $t8, 0x60($sp)
|
||||
lw $t9, 0x64($sp)
|
||||
lw $gp, 0x70($sp)
|
||||
lw $sp, 0x74($sp)
|
||||
lw $s8, 0x78($sp)
|
||||
addiu $sp, $sp, 0x80
|
||||
|
||||
# Restore the stack pointer
|
||||
la $a0, g_VmTempStack
|
||||
addiu $a0, $a0, 0xff8
|
||||
lw $sp, 0x0($a0)
|
||||
|
||||
# Invalidate the cache
|
||||
li $t0, K0BASE
|
||||
or $t0, $s1, $t0
|
||||
addiu $t1, $t0, VM_PAGE_SIZE - 0x10
|
||||
.invalidate_dcache_loop2:
|
||||
cache 0x19, 0x0($t0)
|
||||
sltu $at, $t0, $t1
|
||||
bnez $at, .invalidate_dcache_loop2
|
||||
addiu $t0, $t0, 0x10
|
||||
|
||||
.map_tlb:
|
||||
li $t0, OS_PM_4K
|
||||
mtc0 $t0, C0_PAGEMASK
|
||||
mtc0 $s5, C0_ENTRYHI
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
tlbp
|
||||
nop
|
||||
nop
|
||||
mfc0 $t1, C0_INX
|
||||
mtc0 $t0, C0_PAGEMASK
|
||||
mtc0 $s5, C0_ENTRYHI
|
||||
lw $t0, 0x0($s0)
|
||||
srl $t0, $t0, VM_PAGE_SIZE_SHIFT
|
||||
sll $t0, $t0, 6
|
||||
bnezl $t0, .set_entrylo0
|
||||
ori $t0, $t0, 0x1e
|
||||
.set_entrylo0:
|
||||
mtc0 $t0, C0_ENTRYLO0
|
||||
lw $t0, 0x8($s0)
|
||||
srl $t0, $t0, VM_PAGE_SIZE_SHIFT
|
||||
sll $t0, $t0, 6
|
||||
bnezl $t0, .set_entrylo1
|
||||
ori $t0, $t0, 0x1e
|
||||
.set_entrylo1:
|
||||
mtc0 $t0, C0_ENTRYLO1
|
||||
bltzl $t1, .write_random_tlb_entry
|
||||
nop
|
||||
b .after_write_tlb
|
||||
tlbwi # Replace TLB entry at index C0_INX
|
||||
.write_random_tlb_entry:
|
||||
tlbwr # Replace a random TLB entry
|
||||
.after_write_tlb:
|
||||
bnez $t5, .after_invalidate_cache
|
||||
nop
|
||||
move $t0, $s5
|
||||
bnezl $t9, .after_odd_even_check3
|
||||
addiu $t0, $t0, VM_PAGE_SIZE
|
||||
.after_odd_even_check3:
|
||||
addiu $t1, $t0, VM_PAGE_SIZE - 0x20
|
||||
andi $t2, $t0, 0x1f
|
||||
subu $t0, $t0, $t2
|
||||
.invalidate_dcache_loop3:
|
||||
cache 0x10, 0x0($t0)
|
||||
sltu $at, $t0, $t1
|
||||
bnez $at, .invalidate_dcache_loop3
|
||||
addiu $t0, $t0, 0x20
|
||||
|
||||
.after_invalidate_cache:
|
||||
jr $ra
|
||||
nop
|
||||
|
||||
.choose_page_to_replace:
|
||||
# This part of the function chooses a loaded-but-unmapped slot to be replaced.
|
||||
# The physical address of the page is stored to s1, then it jumps to load_page.
|
||||
#if VERSION < VERSION_NTSC_1_0
|
||||
# Increment g_VmNumPageReplaces
|
||||
la $t0, g_VmNumPageReplaces
|
||||
lw $t1, 0($t0)
|
||||
addiu $t1, $t1, 1
|
||||
sw $t1, 0($t0)
|
||||
#endif
|
||||
|
||||
.evict_loop:
|
||||
# Choose a slot to evict. This is done by taking C0_COUNT & 0x1ff.
|
||||
# If this is still bigger than the number of pages then the number of pages
|
||||
# is subtracted from the value.
|
||||
lw $s4, g_VmVirtualToPhysicalTable
|
||||
lw $gp, g_VmVirtualToPhysicalTableEnd
|
||||
mfc0 $t0, C0_COUNT
|
||||
lhu $t1, g_VmEvictMask
|
||||
lw $t2, g_VmNumPages
|
||||
and $t0, $t0, $t1
|
||||
slt $at, $t0, $t2
|
||||
beqzl $at, .after_subtract
|
||||
subu $t0, $t0, $t2
|
||||
|
||||
.after_subtract:
|
||||
# Convert it to a V2P table offset
|
||||
sll $t1, $t0, 3
|
||||
addu $t1, $t1, $s4
|
||||
|
||||
# Move forward through the table until a loaded slot is found.
|
||||
# If the end is reached, wrap back to the start.
|
||||
.slot_loop:
|
||||
lw $s1, 0x0($t1)
|
||||
bnez $s1, .check_tlb_entry
|
||||
nop
|
||||
addiu $t1, $t1, 8
|
||||
bne $t1, $gp, .slot_loop
|
||||
nop
|
||||
j .slot_loop
|
||||
move $t1, $s4
|
||||
|
||||
.check_tlb_entry:
|
||||
# Query the TLB to make sure this page isn't currently mapped.
|
||||
# If it is then it must have been used recently, so find another page to replace.
|
||||
subu $t0, $t1, $s4 # t0 is now an offset in the V2P table
|
||||
srl $t0, $t0, 3 # t0 is now an index in the V2P table
|
||||
sll $t0, $t0, VM_PAGE_SIZE_SHIFT # t0 is now the byte offset in the physical slots
|
||||
addu $t0, $t0, $s8 # t0 += 0x7f000000
|
||||
li $t2, 0x100000000 - VM_PAGE_SIZE
|
||||
and $t0, $t0, $t2 # t0 is now aligned to a page
|
||||
mtc0 $t0, C0_ENTRYHI
|
||||
li $t0, OS_PM_4K
|
||||
mtc0 $t0, C0_PAGEMASK
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
# tlbp sets C0_INX to to the index of the TLB entry which has the given ENTRYHI
|
||||
tlbp
|
||||
nop
|
||||
nop
|
||||
mfc0 $t2, C0_INX
|
||||
mfc0 $t0, C0_ENTRYHI
|
||||
bltz $t2, .not_mapped
|
||||
nop
|
||||
j .evict_loop
|
||||
nop
|
||||
|
||||
.not_mapped:
|
||||
# The page is not mapped in the TLB, so it's okay to replace it.
|
||||
sw $zero, 0x0($t1)
|
||||
j .load_page
|
||||
nop
|
||||
|
||||
.out_of_range:
|
||||
j handle_fault
|
||||
nop
|
||||
|
||||
glabel vmUnmapRange
|
||||
mfc0 $t0, C0_ENTRYHI
|
||||
li $t2, K0BASE
|
||||
mtc0 $t2, C0_ENTRYHI
|
||||
mtc0 $zero, C0_ENTRYLO0
|
||||
mtc0 $zero, C0_ENTRYLO1
|
||||
.unmap_loop:
|
||||
mtc0 $a1, C0_INX
|
||||
nop
|
||||
tlbwi
|
||||
nop
|
||||
nop
|
||||
bne $a1, $a0, .unmap_loop
|
||||
addi $a1, $a1, -1
|
||||
mtc0 $t0, C0_ENTRYHI
|
||||
jr $ra
|
||||
nop
|
||||
|
||||
#if VERSION < VERSION_NTSC_1_0
|
||||
glabel vmInvalidateFirst8Kb
|
||||
li $t0, K0BASE
|
||||
addiu $t1, $t0, 0x1ff0
|
||||
.invalidate_dcache_loop4:
|
||||
cache 0x1, 0x0($t0)
|
||||
sltu $at, $t0, $t1
|
||||
bnez $at, .invalidate_dcache_loop4
|
||||
addiu $t0, $t0, 0x10
|
||||
jr $ra
|
||||
nop
|
||||
#endif
|
|
@ -7,6 +7,7 @@
|
|||
#include "lib/rzip.h"
|
||||
#include "lib/dma.h"
|
||||
#include "lib/lib_48150.h"
|
||||
#include "lib/vm.h"
|
||||
#include "data.h"
|
||||
#include "types.h"
|
||||
|
||||
|
@ -74,7 +75,7 @@ u32 g_VmNumPageMisses;
|
|||
u32 g_VmNumPageReplaces;
|
||||
u8 *g_VmMarker;
|
||||
u32 g_VmRamEnd;
|
||||
u32 g_VmStateTableEnd;
|
||||
u32 g_VmVirtualToPhysicalTableEnd;
|
||||
|
||||
#ifdef DEBUG
|
||||
u8 g_VmShowStats = false;
|
||||
|
@ -98,20 +99,12 @@ extern u8 _gameSegmentStart;
|
|||
extern u8 _gameSegmentEnd;
|
||||
extern u8 _gamezipSegmentRomStart;
|
||||
|
||||
extern u32 var8008ae20;
|
||||
extern u32 *g_VmStateTable;
|
||||
extern u32 g_VmPhysicalSlots;
|
||||
extern u32 *g_VmVirtualToPhysicalTable;
|
||||
extern u8 g_VmInitialised;
|
||||
extern u32 g_VmZipBuffer;
|
||||
extern u32 *g_VmZipTable;
|
||||
|
||||
#define PAGE_SIZE (1024 * 4)
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
#define MAX_LOADED_PAGES 268
|
||||
#else
|
||||
#define MAX_LOADED_PAGES 266
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialise the virtual memory.
|
||||
*
|
||||
|
@ -152,7 +145,7 @@ extern u32 *g_VmZipTable;
|
|||
* Addresses: 0x??? 0x80220000 0x803f50b8 0x80400000
|
||||
* Lengths: 0x6ec 0x1b99e0 0xaf48 0
|
||||
*
|
||||
* zip buffer: is sized as PAGE_SIZE * 2, which guarantees it's big enough to
|
||||
* zip buffer: is sized as VM_PAGE_SIZE * 2, which guarantees it's big enough to
|
||||
* hold any zip.
|
||||
* zip table: is the ROM offset table where each zip can be found.
|
||||
* game seg: is where the entire game segment is unzipped to.
|
||||
|
@ -214,14 +207,14 @@ void vmInit(void)
|
|||
{
|
||||
g_Is4Mb = true;
|
||||
|
||||
g_VmNumPages = (s32)((&_gameSegmentEnd - &_gameSegmentStart) + (PAGE_SIZE - 1)) / PAGE_SIZE;
|
||||
g_VmNumPages = (s32)((&_gameSegmentEnd - &_gameSegmentStart) + (VM_PAGE_SIZE - 1)) / VM_PAGE_SIZE;
|
||||
|
||||
g_VmRamEnd = 0x7f000000 + PAGE_SIZE * g_VmNumPages;
|
||||
g_VmStateTableEnd = STACK_START;
|
||||
g_VmRamEnd = 0x7f000000 + VM_PAGE_SIZE * g_VmNumPages;
|
||||
g_VmVirtualToPhysicalTableEnd = STACK_START;
|
||||
gameseg = (u8 *) (STACK_START - g_VmNumPages * 8);
|
||||
g_VmStateTable = (u32 *) gameseg;
|
||||
g_VmVirtualToPhysicalTable = (u32 *) gameseg;
|
||||
|
||||
numpages = (u32) (((uintptr_t) &_gameSegmentEnd - (uintptr_t) &_gameSegmentStart) + (PAGE_SIZE - 1)) / PAGE_SIZE;
|
||||
numpages = (u32) (((uintptr_t) &_gameSegmentEnd - (uintptr_t) &_gameSegmentStart) + (VM_PAGE_SIZE - 1)) / VM_PAGE_SIZE;
|
||||
numentries = numpages + 1;
|
||||
|
||||
g_VmZipTable = (u32 *) ((uintptr_t) ((u32 *) gameseg - (numentries + 4)) & ~0xf);
|
||||
|
@ -249,27 +242,27 @@ void vmInit(void)
|
|||
s1 &= (u32) ~0xf;
|
||||
g_VmZipBuffer = (uintptr_t) g_VmZipTable - s1;
|
||||
g_VmZipBuffer &= ~0xf;
|
||||
gameseg = (u8 *) (g_VmZipBuffer - MAX_LOADED_PAGES * PAGE_SIZE);
|
||||
gameseg = (u8 *) (g_VmZipBuffer - VM_NUM_SLOTS * VM_PAGE_SIZE);
|
||||
gameseg -= (uintptr_t) gameseg & 0x1fff;
|
||||
var8008ae20 = (uintptr_t) gameseg;
|
||||
g_VmPhysicalSlots = (uintptr_t) gameseg;
|
||||
g_VmMarker = gameseg;
|
||||
|
||||
tlb000010a4();
|
||||
vmInitVars();
|
||||
|
||||
// Clear the state table
|
||||
ptr = g_VmStateTable;
|
||||
ptr = g_VmVirtualToPhysicalTable;
|
||||
statetablelen = (g_VmNumPages * 8) >> 2;
|
||||
|
||||
for (s1 = 0; s1 < statetablelen; s1++) {
|
||||
ptr[s1] = 0;
|
||||
}
|
||||
|
||||
tlb0000113c();
|
||||
vmInitVacant();
|
||||
} else {
|
||||
// Expansion pak is being used
|
||||
g_Is4Mb = numentries * false;
|
||||
|
||||
numpages = (u32)((&_gameSegmentEnd - &_gameSegmentStart) + (PAGE_SIZE - 1)) / PAGE_SIZE;
|
||||
numpages = (u32)((&_gameSegmentEnd - &_gameSegmentStart) + (VM_PAGE_SIZE - 1)) / VM_PAGE_SIZE;
|
||||
s7 = (u8 *) STACK_START;
|
||||
|
||||
#if VERSION >= VERSION_NTSC_1_0
|
||||
|
@ -302,7 +295,7 @@ void vmInit(void)
|
|||
|
||||
// Load each zip from the ROM and inflate them to the game segment
|
||||
s2 = gameseg;
|
||||
chunkbuffer = (u8 *) ((uintptr_t) romaddrs - PAGE_SIZE * 2);
|
||||
chunkbuffer = (u8 *) ((uintptr_t) romaddrs - VM_PAGE_SIZE * 2);
|
||||
zip = chunkbuffer + 2;
|
||||
|
||||
for (ITER = 0; ITER < numentries2 - 1;) {
|
|
@ -1,3 +1,4 @@
|
|||
#include "asm_helper.h"
|
||||
#include "macros.inc"
|
||||
.set noat
|
||||
.set noreorder
|
||||
|
@ -6,21 +7,22 @@
|
|||
|
||||
/**
|
||||
* This function is generated automatically by makerom. It clears the BSS
|
||||
* segment, sets the stack pointer to 0x80000f10 and then calls boot.
|
||||
* segment, sets the stack pointer to 0x80000f10 and then calls vmBoot.
|
||||
*/
|
||||
glabel preamble
|
||||
lui $t0, %hi(_bssSegmentStart)
|
||||
lui $t1, %hi(_bssSegmentLen)
|
||||
addiu $t0, $t0, %lo(_bssSegmentStart)
|
||||
ori $t1, $t1, %lo(_bssSegmentLen)
|
||||
.L00001010:
|
||||
.bss_loop:
|
||||
addi $t1, $t1, -8
|
||||
sw $zero, 0($t0)
|
||||
sw $zero, 4($t0)
|
||||
bnez $t1, .L00001010
|
||||
bnez $t1, .bss_loop
|
||||
addi $t0, $t0, 8
|
||||
lui $t2, %hi(tlbInitFromPreamble)
|
||||
lui $sp, 0x8000
|
||||
addiu $t2, $t2, %lo(tlbInitFromPreamble)
|
||||
|
||||
lui $t2, %hi(vmBootFromPreamble)
|
||||
li $sp, K0BASE
|
||||
addiu $t2, $t2, %lo(vmBootFromPreamble)
|
||||
jr $t2
|
||||
addiu $sp, $sp, 0xf10
|
||||
|
|
|
@ -163,7 +163,7 @@ static void patch(Algo algo, char *patchfunc, char *sumfunc)
|
|||
void piracy_patch_checksums(void)
|
||||
{
|
||||
// algorithm, patch function, sum function
|
||||
patch(algo01, "__scHandleTasks", "bootPhase1");
|
||||
patch(algo01, "__scHandleTasks", "boot");
|
||||
patch(algo02, "cheatMenuHandleDialog", "__scHandleTasks");
|
||||
patch(algo03, "botPickupProp", "doorFinishClose");
|
||||
patch(algo04, "chrUncloak", "botPickupProp");
|
||||
|
|
Loading…
Reference in New Issue