Update dsd to v0.12.0; dsprot OK (#135)

* `Actor::mType` field

* Remove fake symbol `data_027e0254`

* `dsd format`

* eur: Enable dsprot decomp

* jp: Enable dsprot decomp

* dsprot OK

* `dsd format`

* Use new `weak` attribute

* Add relocations for exception table link-time constants

* Add exception table symbols

* Bump dsd to v0.12.0

* `#define FALSE 1` ???
Why did I make it 1?

* Truncate `data_ov001_020c27a8`
That data belongs to dsprot
This commit is contained in:
Aetias
2026-08-15 01:07:14 +02:00
committed by GitHub
parent ce24ddfc4e
commit 521100caed
104 changed files with 4547 additions and 2014 deletions
+8
View File
@@ -0,0 +1,8 @@
CompileFlags:
Add:
- -Wno-int-to-pointer-cast
Diagnostics:
Suppress:
- sizeof_alignof_function_type
- bad_reinterpret_cast_small_int
- typecheck_pointer_arith_void_type
+1
View File
@@ -0,0 +1 @@
Credits to taxicat1 aka Mow: https://github.com/taxicat1/dsprot/
@@ -17,7 +17,7 @@
#ifndef DSP_NO_NITRO
#include <types.h> // For u32
#include <nitro/types.h> // For u32
#else /* DSP_NO_NITRO */
@@ -113,8 +113,14 @@ extern u32 DSProt_DetectNotDummy(void *callback);
#else /* SDK_ASM */
.public DSProt_DetectFlashcart.public DSProt_DetectNotFlashcart.public DSProt_DetectEmulator.public DSProt_DetectNotEmulator
.public DSProt_DetectDummy.public DSProt_DetectNotDummy
// clang-format off
.public DSProt_DetectFlashcart
.public DSProt_DetectNotFlashcart
.public DSProt_DetectEmulator
.public DSProt_DetectNotEmulator
.public DSProt_DetectDummy
.public DSProt_DetectNotDummy
// clang-format on
#endif /* SDK_ASM */
+91
View File
@@ -0,0 +1,91 @@
#pragma once
#include "dsprot/encoding_constants.h"
.macro arm_func_start name
.balign 4, 0
.global \name
.type \name, @function
.arm
.endm
.macro local_arm_func_start name
.balign 4, 0
.type \name, @function
.arm
.endm
.macro arm_func_end name
.size \name, .-\name
.endm
.macro sinit sinit_func
.type NitroStaticInit_\@, @object
NitroStaticInit_\@:
.word \sinit_func
.size NitroStaticInit_\@, .-NitroStaticInit_\@
.endm
.public DSProt_BSS
.public Encryptor_DecryptFunction
.public Encryptor_EncryptFunction
.macro run_encrypted_func func, length, key
stmfd sp!, {r4-r7} ; `r0`-`r3` contain the arguments that must be passed into the inner function.
stmfd sp!, {r0-r3} ; Stack manipulation to move `r0`-`r3` into `r4`-`r7` for storage.
ldmfd sp!, {r4-r7} ; Original values of `r4`-`r7` get pushed onto the stack.
ldr r1, func_\@ ; Get second function decrypter argument, obfuscated function address.
adr r3, storage_\@ ; `lr` cannot be stored on the stack when we call the inner function,
str lr, [r3] ; so it is stored in the pool below.
ldr r2, length_\@ ; Get third function decrypter argument, obfuscated length.
ldr r0, key_\@ ; Get first function decrypter argument, obfuscated key.
bl Encryptor_DecryptFunction ; Call function decrypter with args (key, addr, len).
mov ip, r0 ; Function decrypter returns the de-obfuscated function address. Save it in `ip`.
stmfd sp!, {r4-r7} ; Stack manipulation again to restore the original `r0`-`r3`.
ldmfd sp!, {r0-r3} ;
ldmfd sp!, {r4-r7} ; Stack is now restored, so `sp` is correct for the inner function call.
blx ip ; Call inner function.
stmfd sp!, {r4} ; `r4` about to be used as storage space for the inner function return, so save it on the stack.
mov r4, r0 ; Copy the return from the inner function into `r4` so we can can run the function re-encrypter.
ldr r1, func_\@ ; Get second function encrypter argument, obfuscated function address.
ldr r2, length_\@ ; Get third function encrypter argument, obfuscated length.
ldr r0, key_\@ ; Get first function encrypter argument, obfuscated key.
bl Encryptor_EncryptFunction ; Call function encrypter.
str r0, key_\@ ; Function encrypter returns the new key it used, store this back into the pool for next time.
mov r0, r4 ; Restore the return value from the inner function from `r4` to `r0`.
ldmfd sp!, {r4} ; Restore the original value of `r4` from the stack.
ldr lr, storage_\@ ; Load `lr` return address back from the storage space in the pool.
str pc, storage_\@ ; Store `pc` in its place, presumably just to overwrite the return address.
bx lr ; Return with return value from inner function.
storage_\@:
.word DSProt_BSS + 1
length_\@:
.word DSProt_BSS + \length + ENC_VAL_1
key_\@:
.word DSProt_BSS + \key + ENC_VAL_1
func_\@:
.word \func + ENC_VAL_1
.endm
.public Encryptor_DecodeFunctionTable
.macro decode_func_table table
stmdb sp!, {lr}
adr r0, \table
bl Encryptor_DecodeFunctionTable
ldmia sp!, {pc}
.endm
.macro func_table_entry func, size
.word \func + ENC_VAL_1, DSProt_BSS + \size + ENC_VAL_1
.endm
.macro func_table_end
.word 0, 0
.endm
.macro garbage_ref ref
.word \ref + ENC_VAL_1
.endm
+8
View File
@@ -0,0 +1,8 @@
#ifndef BSS_H
#define BSS_H
#include <nitro/types.h>
extern u8 DSProt_BSS[4];
#endif
@@ -0,0 +1,21 @@
#ifndef ENCODING_CONSTANTS_H
#define ENCODING_CONSTANTS_H
#define INS_OPCODE_LINKBIT (0x01)
#define INS_OPCODE_MASK (0xFF000000)
#define INS_OPCODE_SHIFT (24)
#define INS_OPERANDS_MASK (0x00FFFFFF)
#define ADDR_PLUS_ADDEND(ref, addend) ((u32) (&ref + ((addend) / sizeof(ref))))
#define ENC_VAL_1 (0x1400)
#define ENC_VAL_2 ((ENC_VAL_1 >> 2) + 2)
#define ENC_BYTE_A (0x65)
#define ENC_BYTE_B (0x56)
#define ENC_BYTE_C (0x68)
#define ENC_BYTE_D (0xD0)
#define ENC_SBOX_XOR (0x01)
#endif
+23
View File
@@ -0,0 +1,23 @@
#ifndef ENCRYPTOR_H
#define ENCRYPTOR_H
#include <nitro/types.h>
typedef struct {
u32 obfs_addr;
u32 obfs_size;
} FuncInfo;
enum {
INS_TYPE_OTHER = 0,
INS_TYPE_BLXIMM,
INS_TYPE_BL,
INS_TYPE_B
};
u32 Encryptor_CategorizeInstruction(u32 instruction);
void Encryptor_DecodeFunctionTable(FuncInfo *functions);
void *Encryptor_DecryptFunction(u32 key, u32 func_addr, u32 size);
u32 Encryptor_EncryptFunction(u32 key, u32 func_addr, u32 size);
#endif
+8
View File
@@ -0,0 +1,8 @@
#ifndef GARBAGE_H
#define GARBAGE_H
#include <nitro/types.h>
extern const u32 DSProt_Garbage[6];
#endif
+12
View File
@@ -0,0 +1,12 @@
#ifndef INTEGRITY_H
#define INTEGRITY_H
#include <nitro/types.h>
// Assembly decryption wrappers
extern u32 RunEncrypted_Integrity_MACOwner_IsBad(void);
extern u32 RunEncrypted_Integrity_MACOwner_IsGood(void);
extern u32 RunEncrypted_Integrity_ROMTest_IsBad(void);
extern u32 RunEncrypted_Integrity_ROMTest_IsGood(void);
#endif
+10
View File
@@ -0,0 +1,10 @@
#ifndef MAC_OWNER_H
#define MAC_OWNER_H
#include <nitro/types.h>
// Assembly decryption wrappers
extern u32 RunEncrypted_MACOwner_IsBad(void);
extern u32 RunEncrypted_MACOwner_IsGood(void);
#endif
+9
View File
@@ -0,0 +1,9 @@
#ifndef RC4_H
#define RC4_H
#include <nitro/types.h>
u32 RC4_InitAndEncryptInstructions(void *key, void *dst, void *src, u32 size);
u32 RC4_InitAndDecryptInstructions(void *key, void *dst, void *src, u32 size);
#endif
+10
View File
@@ -0,0 +1,10 @@
#ifndef ROM_TEST_H
#define ROM_TEST_H
#include <nitro/types.h>
// Assembly decryption wrappers
extern u32 RunEncrypted_ROMTest_IsBad(void);
extern u32 RunEncrypted_ROMTest_IsGood(void);
#endif
+10
View File
@@ -0,0 +1,10 @@
#ifndef ROM_UTIL_H
#define ROM_UTIL_H
#include <nitro/types.h>
// Assembly decryption wrappers
extern void RunEncrypted_ROMUtil_Read(void *dest, u32 addr, s32 num_bytes);
extern u32 RunEncrypted_ROMUtil_CRC32(void *buf, u32 size);
#endif
+152
View File
@@ -0,0 +1,152 @@
/* No dedicated header */
#include "dsprot.h"
#include "dsprot/encoding_constants.h"
#include "dsprot/encryptor.h"
#include "dsprot/integrity.h"
#include "dsprot/mac_owner.h"
#include "dsprot/rom_test.h"
// Functions to be encrypted (cannot be called directly)
u32 DetectFlashcart(void *callback);
u32 DetectNotFlashcart(void *callback);
u32 DetectEmulator(void *callback);
u32 DetectNotEmulator(void *callback);
u32 DetectDummy(void *callback);
u32 DetectNotDummy(void *callback);
#define DSP_OBFS_OFFSET (0x320)
#define FUNC_QUEUE_END (0)
typedef u32 (*TaskFunc)(void);
typedef void (*CallbackFunc)(void);
enum {
EXPECT_FALSE,
EXPECT_TRUE
};
// This was likely not originally an inline, but an inline is able to match here nicely
static inline u32 dsprotMain(u32 *func_queue, int expected_result, void *callback) {
BOOL ret;
BOOL func_result;
s32 compare_sum;
u32 i;
s32 func_result_sum;
// These two bit arrays must be signed to match
compare_sum = 0;
func_result_sum = 0;
for (i = 0; func_queue[i] != FUNC_QUEUE_END; i++) {
func_result = ((TaskFunc) (func_queue[i] - ENC_VAL_1 - DSP_OBFS_OFFSET))() != 0;
func_result_sum += func_result;
func_result_sum <<= 1;
compare_sum += TRUE;
compare_sum <<= 1;
}
if (expected_result == EXPECT_TRUE) {
ret = (func_result_sum >> 1) == (compare_sum >> 1);
} else {
ret = ((func_result_sum & compare_sum) >> 1) != 0;
}
if (callback != NULL && ret) {
((CallbackFunc) callback)();
}
return (u32) ret;
}
u32 DetectFlashcart(void *callback) {
u32 func_queue[32];
func_queue[2] = FUNC_QUEUE_END;
func_queue[0] = ADDR_PLUS_ADDEND(RunEncrypted_ROMTest_IsBad, ENC_VAL_1) + DSP_OBFS_OFFSET;
func_queue[1] = ADDR_PLUS_ADDEND(RunEncrypted_Integrity_ROMTest_IsBad, ENC_VAL_1) + DSP_OBFS_OFFSET;
return dsprotMain(&func_queue[0], EXPECT_FALSE, callback);
}
u32 DetectNotFlashcart(void *callback) {
u32 func_queue[32];
func_queue[2] = FUNC_QUEUE_END;
func_queue[0] = ADDR_PLUS_ADDEND(RunEncrypted_ROMTest_IsGood, ENC_VAL_1) + DSP_OBFS_OFFSET;
func_queue[1] = ADDR_PLUS_ADDEND(RunEncrypted_Integrity_ROMTest_IsGood, ENC_VAL_1) + DSP_OBFS_OFFSET;
return dsprotMain(&func_queue[0], EXPECT_TRUE, callback);
}
u32 DetectEmulator(void *callback) {
u32 func_queue[32];
func_queue[2] = FUNC_QUEUE_END;
func_queue[0] = ADDR_PLUS_ADDEND(RunEncrypted_MACOwner_IsBad, ENC_VAL_1) + DSP_OBFS_OFFSET;
func_queue[1] = ADDR_PLUS_ADDEND(RunEncrypted_Integrity_MACOwner_IsBad, ENC_VAL_1) + DSP_OBFS_OFFSET;
return dsprotMain(&func_queue[0], EXPECT_FALSE, callback);
}
u32 DetectNotEmulator(void *callback) {
u32 func_queue[32];
func_queue[2] = FUNC_QUEUE_END;
func_queue[0] = ADDR_PLUS_ADDEND(RunEncrypted_MACOwner_IsGood, ENC_VAL_1) + DSP_OBFS_OFFSET;
func_queue[1] = ADDR_PLUS_ADDEND(RunEncrypted_Integrity_MACOwner_IsGood, ENC_VAL_1) + DSP_OBFS_OFFSET;
return dsprotMain(&func_queue[0], EXPECT_TRUE, callback);
}
u32 DetectDummy(void *callback) {
u32 func_queue[32];
// Prevent optimization of the function queue processing
*(u32 *) &func_queue[0] = FUNC_QUEUE_END;
return dsprotMain(&func_queue[0], EXPECT_FALSE, callback);
}
u32 DetectNotDummy(void *callback) {
u32 func_queue[32];
// Prevent optimization of the function queue processing
*(u32 *) &func_queue[0] = FUNC_QUEUE_END;
return dsprotMain(&func_queue[0], EXPECT_TRUE, callback);
}
// DECRYPTION_WRAPPER(DetectFlashcart, 0xac, 0x2e8b, DSProt_)
// DECRYPTION_WRAPPER(DetectNotFlashcart, 0xac, 0x2e8b, DSProt_)
// DECRYPTION_WRAPPER(DetectEmulator, 0xac, 0x2e8b, DSProt_)
// DECRYPTION_WRAPPER(DetectNotEmulator, 0xac, 0x2e8b, DSProt_)
// DECRYPTION_WRAPPER(DetectDummy, 0x94, 0x2e8b, DSProt_)
// DECRYPTION_WRAPPER(DetectNotDummy, 0x94, 0x2e8b, DSProt_)
// // clang-format off
// asm void NitroStaticInit() {
// stmdb sp!, {lr};
// add r0, pc, #0x4;
// bl Encryptor_DecodeFunctionTable;
// ldmia sp!, {pc};
// dcd DSProt_DetectFlashcart + ENC_VAL_1
// dcd DSProt_BSS + 0x68 + ENC_VAL_1
// dcd DSProt_DetectNotFlashcart + ENC_VAL_1
// dcd DSProt_BSS + 0x68 + ENC_VAL_1
// dcd DSProt_DetectEmulator + ENC_VAL_1
// dcd DSProt_BSS + 0x68 + ENC_VAL_1
// dcd DSProt_DetectNotEmulator + ENC_VAL_1
// dcd DSProt_BSS + 0x68 + ENC_VAL_1
// dcd DSProt_DetectDummy + ENC_VAL_1
// dcd DSProt_BSS + 0x68 + ENC_VAL_1
// dcd DSProt_DetectNotDummy + ENC_VAL_1
// dcd DSProt_BSS + 0x68 + ENC_VAL_1
// dcd 0
// dcd 0
// dcd DSProt_Garbage + 0x1400
// }
// // clang-format on
+137
View File
@@ -0,0 +1,137 @@
#include "dsprot/encryptor.h"
#include <nitro/os/cache.h>
#include "dsprot/bss.h"
#include "dsprot/encoding_constants.h"
#include "dsprot/rc4.h"
#define ROTL(x, a) ((a) == 0 ? (x) : (((x) << (a)) | ((x) >> (32 - (a)))))
static void clearDataAndInstructionCache(void *start_addr, u32 num_bytes);
static void clearDataAndInstructionCache(void *start_addr, u32 num_bytes) {
DC_FlushRange(start_addr, num_bytes);
IC_InvalidateRange(start_addr, num_bytes);
}
u32 Encryptor_CategorizeInstruction(u32 instruction) {
u8 opcode;
opcode = instruction >> INS_OPCODE_SHIFT;
// Branch instruction
if ((opcode & 0x0E) == 0x0A) {
// BLX immediate type
if ((opcode & 0xF0) == 0xF0) {
return INS_TYPE_BLXIMM;
}
// Link bit
if (opcode & INS_OPCODE_LINKBIT) {
return INS_TYPE_BL;
} else {
return INS_TYPE_B;
}
}
return INS_TYPE_OTHER;
}
void Encryptor_DecodeFunctionTable(FuncInfo *functions) {
u32 *addr;
u32 size;
u32 *end_addr;
if (functions == NULL) {
return;
}
for (; functions->obfs_addr != 0; functions++) {
addr = (u32 *) functions->obfs_addr;
size = functions->obfs_size - (u32) &DSProt_BSS - ENC_VAL_1;
if (addr == NULL) {
break;
}
addr = (u32 *) ((u32) addr - ENC_VAL_1);
end_addr = addr + (size / 4);
for (; addr < end_addr; addr++) {
switch (Encryptor_CategorizeInstruction(*addr)) {
case INS_TYPE_BLXIMM:
case INS_TYPE_BL: {
u32 opcode = (*addr & INS_OPCODE_MASK) ^ (INS_OPCODE_LINKBIT << INS_OPCODE_SHIFT);
u32 operands = ((*addr & INS_OPERANDS_MASK) - ENC_VAL_1) & INS_OPERANDS_MASK;
*addr = opcode | operands;
} break;
case INS_TYPE_B: {
u32 opcode = (*addr & INS_OPCODE_MASK) ^ (INS_OPCODE_LINKBIT << INS_OPCODE_SHIFT);
u32 operands = ((*addr & INS_OPERANDS_MASK) - ENC_VAL_2) & INS_OPERANDS_MASK;
*addr = opcode | operands;
} break;
default: {
u8 *addr_bytes = (u8 *) addr;
*addr = (addr_bytes[0] ^ ENC_BYTE_A) | ((addr_bytes[1] ^ ENC_BYTE_B) << 8) |
((addr_bytes[2] ^ ENC_BYTE_C) << 16) | ((addr_bytes[3] ^ ENC_BYTE_D) << 24);
} break;
}
}
clearDataAndInstructionCache((void *) (functions->obfs_addr - ENC_VAL_1), size);
}
}
static inline void expandRC4Key(u32 seed_key, u32 size, u32 *expanded_key) {
expanded_key[0] = ROTL(seed_key, 0) ^ size;
expanded_key[1] = ROTL(seed_key, 8) ^ size;
expanded_key[2] = ROTL(seed_key, 16) ^ size;
expanded_key[3] = ROTL(seed_key, 24) ^ size;
}
void *Encryptor_DecryptFunction(u32 key, u32 func_addr, u32 size) {
u32 expanded_key[4];
void *func_ptr;
// Deobfuscate arguments
func_ptr = (void *) func_addr;
func_ptr -= ENC_VAL_1;
size -= (u32) &DSProt_BSS + ENC_VAL_1;
key -= (u32) &DSProt_BSS + ENC_VAL_1;
expandRC4Key(key, size, &expanded_key[0]);
RC4_InitAndDecryptInstructions(&expanded_key[0], func_ptr, func_ptr, size);
clearDataAndInstructionCache(func_ptr, size);
return func_ptr;
}
u32 Encryptor_EncryptFunction(u32 key, u32 func_addr, u32 size) {
u32 expanded_key[4];
void *func_ptr;
// Deobfuscate arguments
func_ptr = (void *) func_addr;
func_ptr -= ENC_VAL_1;
size -= (u32) &DSProt_BSS + ENC_VAL_1;
key -= (u32) &DSProt_BSS + ENC_VAL_1;
// Change key
key += func_addr >> 20;
expandRC4Key(key, size, &expanded_key[0]);
RC4_InitAndEncryptInstructions(&expanded_key[0], func_ptr, func_ptr, size);
clearDataAndInstructionCache(func_ptr, size);
// Re-obfuscate key
key += (u32) &DSProt_BSS + ENC_VAL_1;
return key;
}
+8
View File
@@ -0,0 +1,8 @@
#include "dsprot/bss.h"
#include "dsprot/garbage.h"
u8 DSProt_BSS[4];
const u32 DSProt_Garbage[6] = {
0xebaa0114, 0x40064eb7, 0x5f013696, 0xe5211f83, 0xe7ef335b, 0xe84b197c,
};
+120
View File
@@ -0,0 +1,120 @@
#include "dsprot/integrity.h"
#include "dsprot/encoding_constants.h"
#include "dsprot/mac_owner.h"
#include "dsprot/rom_test.h"
// Functions to be encrypted (cannot be called directly)
u32 Integrity_MACOwner_IsBad(void);
u32 Integrity_MACOwner_IsGood(void);
u32 Integrity_ROMTest_IsBad(void);
u32 Integrity_ROMTest_IsGood(void);
#define INTEGRITY_OBFS_OFFSET (ENC_VAL_1 & ~0xFFF)
// This was likely not originally an inline, but an inline is able to match here nicely
static inline u32 checkDecryptionWrapper(u8 *addr, u32 match_ret, u32 mismatch_ret) {
u32 offset;
addr += INTEGRITY_OBFS_OFFSET;
offset = ENC_VAL_1 - INTEGRITY_OBFS_OFFSET;
// The bytes checked here are from the `run_encrypted_func` macro defined in asm_macro.inc:
// e92d00f0 stmfd sp!, {r4-r7}
// e92d000f stmfd sp!, {r0-r3}
// e8bd00f0 ldmfd sp!, {r4-r7}
// e59f103c ldr r1, [pc, #60]
if (addr[offset++] != 0xF0) {
return mismatch_ret;
}
if (addr[offset++] != 0x00) {
return mismatch_ret;
}
if (addr[offset++] != 0x2D) {
return mismatch_ret;
}
if (addr[offset++] != 0xE9) {
return mismatch_ret;
}
if (addr[offset++] != 0x0F) {
return mismatch_ret;
}
if (addr[offset++] != 0x00) {
return mismatch_ret;
}
if (addr[offset++] != 0x2D) {
return mismatch_ret;
}
if (addr[offset++] != 0xE9) {
return mismatch_ret;
}
if (addr[offset++] != 0xF0) {
return mismatch_ret;
}
if (addr[offset++] != 0x00) {
return mismatch_ret;
}
if (addr[offset++] != 0xBD) {
return mismatch_ret;
}
if (addr[offset++] != 0xE8) {
return mismatch_ret;
}
if (addr[offset++] != 0x60) {
return mismatch_ret;
}
if (addr[offset++] != 0x10) {
return mismatch_ret;
}
if (addr[offset++] != 0x9F) {
return mismatch_ret;
}
if (addr[offset++] != 0xE5) {
return mismatch_ret;
}
return match_ret;
}
u32 Integrity_MACOwner_IsBad(void) {
u8 *addr;
u32 ret;
addr = (u8 *) ADDR_PLUS_ADDEND(RunEncrypted_MACOwner_IsBad, ENC_VAL_1) - (ENC_VAL_1 * 2);
ret = (u32) addr + 1;
return checkDecryptionWrapper(addr, 0, ret);
}
u32 Integrity_MACOwner_IsGood(void) {
u8 *addr;
u32 ret;
addr = (u8 *) ADDR_PLUS_ADDEND(RunEncrypted_MACOwner_IsGood, ENC_VAL_1) - (ENC_VAL_1 * 2);
ret = (u32) addr;
return checkDecryptionWrapper(addr, ret + 1, 0);
}
u32 Integrity_ROMTest_IsBad(void) {
u8 *addr;
u32 ret;
addr = (u8 *) ADDR_PLUS_ADDEND(RunEncrypted_ROMTest_IsBad, ENC_VAL_1) - (ENC_VAL_1 * 2);
ret = (u32) addr + 1;
return checkDecryptionWrapper(addr, 0, ret);
}
u32 Integrity_ROMTest_IsGood(void) {
u8 *addr;
u32 ret;
addr = (u8 *) ADDR_PLUS_ADDEND(RunEncrypted_ROMTest_IsGood, ENC_VAL_1) - (ENC_VAL_1 * 2);
ret = (u32) addr;
return checkDecryptionWrapper(addr, ret + 1, 0);
}
+55
View File
@@ -0,0 +1,55 @@
#include "dsprot/mac_owner.h"
#include <nitro/os.h>
// Functions to be encrypted (cannot be called directly)
u32 MACOwner_IsBad(void);
u32 MACOwner_IsGood(void);
#define MAC_ADDR_SIZE (6)
#define ENC_MAC_ADDR_BYTE (0xFF)
static const u8 bad_mac_addr[MAC_ADDR_SIZE] = {0x00 ^ ENC_MAC_ADDR_BYTE, 0x09 ^ ENC_MAC_ADDR_BYTE, 0xBF ^ ENC_MAC_ADDR_BYTE,
0x00 ^ ENC_MAC_ADDR_BYTE, 0x00 ^ ENC_MAC_ADDR_BYTE, 0x31 ^ ENC_MAC_ADDR_BYTE};
static inline u32 testMACOwner(u32 pass_ret, u32 fail_ret) {
u8 mac_addr[MAC_ADDR_SIZE];
OSOwnerInfo owner_info;
int i;
u32 ret;
OS_func_0176(&mac_addr[0]);
for (i = 0; i < MAC_ADDR_SIZE; i++) {
if (bad_mac_addr[i] != (mac_addr[i] ^ ENC_MAC_ADDR_BYTE)) {
break;
}
}
OS_func_0177(&owner_info);
if (i == MAC_ADDR_SIZE && owner_info.birthday.month == 1 && owner_info.birthday.day == 1 &&
owner_info.nickNameLength == 0) {
ret = fail_ret;
goto EXIT;
}
for (i = 0; i < MAC_ADDR_SIZE; i++) {
if (mac_addr[i] != 0x00) {
ret = pass_ret;
goto EXIT;
}
}
ret = fail_ret;
EXIT:
return ret;
}
u32 MACOwner_IsBad(void) {
return testMACOwner(0, 1);
}
u32 MACOwner_IsGood(void) {
return testMACOwner(1, 0);
}
+210
View File
@@ -0,0 +1,210 @@
#include "dsprot/rc4.h"
#include "dsprot/encoding_constants.h"
#include "dsprot/encryptor.h"
#define RC4_KEY_SIZE (16)
typedef struct {
int i;
int j;
u8 S[256];
} RC4_Ctx;
// Functions to be encoded (cannot be static)
void RC4_Init(RC4_Ctx *ctx, const void *key, u32 key_len);
u8 RC4_Byte(RC4_Ctx *ctx);
u32 RC4_InitSBox(u8 *sbox);
u32 RC4_EncryptInstructions(RC4_Ctx *ctx, void *src, void *dst, u32 size);
u32 RC4_DecryptInstructions(RC4_Ctx *ctx, void *src, void *dst, u32 size);
void RC4_Init(RC4_Ctx *ctx, const void *key, u32 key_len) {
u8 tmp1;
u8 tmp2;
int Ki;
u8 Si;
int i;
int j;
Ki = 0;
Si = 0;
ctx->i = 0;
ctx->j = 0;
for (j = 0; j < 256; j++) {
ctx->S[j] = j;
}
// Modification to RC4: i = 255 -> 0, instead of 0 -> 255
for (i = 255; i >= 0; i--) {
tmp1 = ctx->S[i];
Si = Si + ((u8 *) key)[Ki] + tmp1;
tmp2 = ctx->S[Si];
ctx->S[Si] = tmp1;
ctx->S[i] = tmp2;
Ki++;
if (Ki >= key_len) {
Ki = 0;
}
}
}
u8 RC4_Byte(RC4_Ctx *ctx) {
u8 i;
u8 ival;
u8 j;
u8 jval;
i = ctx->i + 1;
ival = ctx->S[i];
j = ival + ctx->j;
jval = ctx->S[j];
ctx->i = i;
ctx->j = j;
ctx->S[j] = ival;
ctx->S[i] = jval;
return ctx->S[(ival + jval) & 0xFF];
}
u32 RC4_InitSBox(u8 *sbox) {
int i;
for (i = 0; i < 256; i++) {
sbox[i] = (u8) i ^ ENC_SBOX_XOR;
}
return 0;
}
u32 RC4_EncryptInstructions(RC4_Ctx *ctx, void *src, void *dst, u32 size) {
u8 sbox[256];
ulong offset;
u8 *src_bytes;
u8 *dst_bytes;
if (size & 3) {
return -1;
}
src_bytes = (u8 *) src;
dst_bytes = (u8 *) dst;
RC4_InitSBox(&sbox[0]);
for (offset = 0; offset < size; offset += 4) {
switch (Encryptor_CategorizeInstruction(*(u32 *) (src_bytes + offset))) {
case INS_TYPE_BLXIMM:
case INS_TYPE_BL: {
u32 opcode;
u32 operands;
u32 *src_addr = (u32 *) (src_bytes + offset);
u32 *dst_addr = (u32 *) (dst_bytes + offset);
*dst_addr = *src_addr;
opcode = (*dst_addr & INS_OPCODE_MASK) ^ (INS_OPCODE_LINKBIT << INS_OPCODE_SHIFT);
operands = ((*dst_addr & INS_OPERANDS_MASK) + ENC_VAL_2) & INS_OPERANDS_MASK;
*dst_addr = opcode | operands;
} break;
case INS_TYPE_B: {
u32 opcode;
u32 operands;
u32 *src_addr = (u32 *) (src_bytes + offset);
u32 *dst_addr = (u32 *) (dst_bytes + offset);
*dst_addr = *src_addr;
opcode = (*dst_addr & INS_OPCODE_MASK) ^ (INS_OPCODE_LINKBIT << INS_OPCODE_SHIFT);
operands = ((*dst_addr & INS_OPERANDS_MASK) + ENC_VAL_1) & INS_OPERANDS_MASK;
*dst_addr = opcode | operands;
} break;
default:
dst_bytes[offset] = src_bytes[offset] ^ RC4_Byte(ctx);
dst_bytes[offset + 1] = src_bytes[offset + 1] ^ RC4_Byte(ctx);
dst_bytes[offset + 2] = sbox[src_bytes[offset + 2]];
dst_bytes[offset + 3] = src_bytes[offset + 3];
break;
}
}
return 0;
}
u32 RC4_DecryptInstructions(RC4_Ctx *ctx, void *src, void *dst, u32 size) {
u8 sbox[256];
ulong offset;
u8 *src_bytes;
u8 *dst_bytes;
if (size & 3) {
return -1;
}
src_bytes = (u8 *) src;
dst_bytes = (u8 *) dst;
RC4_InitSBox(&sbox[0]);
for (offset = 0; offset < size; offset += 4) {
switch (Encryptor_CategorizeInstruction(*(u32 *) (src_bytes + offset))) {
case INS_TYPE_BLXIMM:
case INS_TYPE_BL: {
u32 opcode;
u32 operands;
u32 *src_addr = (u32 *) (src_bytes + offset);
u32 *dst_addr = (u32 *) (dst_bytes + offset);
*dst_addr = *src_addr;
opcode = (*dst_addr & INS_OPCODE_MASK) ^ (INS_OPCODE_LINKBIT << INS_OPCODE_SHIFT);
operands = ((*dst_addr & INS_OPERANDS_MASK) - ENC_VAL_1) & INS_OPERANDS_MASK;
*dst_addr = opcode | operands;
} break;
case INS_TYPE_B: {
u32 opcode;
u32 operands;
u32 *src_addr = (u32 *) (src_bytes + offset);
u32 *dst_addr = (u32 *) (dst_bytes + offset);
*dst_addr = *src_addr;
opcode = (*dst_addr & INS_OPCODE_MASK) ^ (INS_OPCODE_LINKBIT << INS_OPCODE_SHIFT);
operands = ((*dst_addr & INS_OPERANDS_MASK) - ENC_VAL_2) & INS_OPERANDS_MASK;
*dst_addr = opcode | operands;
} break;
default:
dst_bytes[offset] = src_bytes[offset] ^ RC4_Byte(ctx);
dst_bytes[offset + 1] = src_bytes[offset + 1] ^ RC4_Byte(ctx);
dst_bytes[offset + 2] = sbox[src_bytes[offset + 2]];
dst_bytes[offset + 3] = src_bytes[offset + 3];
break;
}
}
return 0;
}
u32 RC4_InitAndEncryptInstructions(void *key, void *dst, void *src, u32 size) {
RC4_Ctx ctx;
RC4_Init(&ctx, key, RC4_KEY_SIZE);
// Must coerce output to -1 or 0 like this to match
return RC4_EncryptInstructions(&ctx, dst, src, size) == -1 ? -1 : 0;
}
u32 RC4_InitAndDecryptInstructions(void *key, void *dst, void *src, u32 size) {
RC4_Ctx ctx;
RC4_Init(&ctx, key, RC4_KEY_SIZE);
// Must coerce output to -1 or 0 like this to match
return RC4_DecryptInstructions(&ctx, dst, src, size) == -1 ? -1 : 0;
}
+67
View File
@@ -0,0 +1,67 @@
#include "dsprot/rom_test.h"
#include "dsprot/rom_util.h"
#include <nitro/card.h>
// Functions to be encrypted (cannot be called directly)
u32 ROMTest_IsBad(void);
u32 ROMTest_IsGood(void);
#define ROM_BLOCK_SIZE CARD_ROM_PAGE_SIZE
static inline u32 testROM(u32 pass_ret, u32 fail_ret) {
// Extra CRC entry is required to match
u32 crcs[7];
u8 rom_buf[ROM_BLOCK_SIZE];
int i;
u32 rom_addr;
u32 ret;
rom_addr = 0x1000;
for (i = 0; i < 6; i++) {
RunEncrypted_ROMUtil_Read(&rom_buf[0], rom_addr, ROM_BLOCK_SIZE);
crcs[i] = RunEncrypted_ROMUtil_CRC32(&rom_buf[0], ROM_BLOCK_SIZE);
if (i == 2) {
// Has to be like this to match
rom_addr = 1;
rom_addr <<= 15;
} else {
rom_addr += ROM_BLOCK_SIZE;
}
}
// Checking the ROM reading results were as expected:
// 0 == 1 == 2 == 3
// 3 != 4 and 3 != 5
for (i = 0; i < 3; i++) {
if (crcs[i] != crcs[3]) {
ret = fail_ret;
goto EXIT;
}
}
if (crcs[3] == crcs[4] && crcs[3] == crcs[5]) {
ret = fail_ret;
} else {
ret = pass_ret;
}
EXIT:
// Erasing read buffer
for (i = 0; i < ROM_BLOCK_SIZE; i++) {
rom_buf[i] = 0;
}
return ret;
}
u32 ROMTest_IsBad(void) {
return testROM(0, 1);
}
u32 ROMTest_IsGood(void) {
return testROM(1, 0);
}
+150
View File
@@ -0,0 +1,150 @@
#include "dsprot/rom_util.h"
#include <nitro/card.h>
#include <nitro/os.h>
#include <nitro/reg.h>
// Functions to be encrypted (cannot be called directly)
void ROMUtil_Read(void *dest, u32 addr, s32 num_bytes);
u32 ROMUtil_CRC32(void *buf, u32 size);
void ROMUtil_Read(void *dest, u32 addr, s32 num_bytes) {
u8 buffer[8];
vu8 *vnull;
u32 register_base_1;
vu8 *register_base_2;
u32 card_ctrl_13;
s32 addr_offset;
u16 lock_id;
u16 ext_mem_register_val_original;
u32 output;
s32 card_ctrl_cmd;
int i;
lock_id = OS_GetLockID();
CARD_func_0010(lock_id);
// Alias for volatile null pointer
vnull = NULL;
// Alias for register base (0x04000000)
register_base_1 = 1;
register_base_1 <<= 26;
// Another alias for register base (0x04000000)
register_base_2 = (vu8 *) REG_BASE;
// External memory control register (0x04000204)
// Save value to rewrite later
ext_mem_register_val_original = REG_EXMEM_CNT;
// Set current processor accessing the gamecard bus to the ARM9
OS_SetNdsSlotAccess(OS_CPU_ARM9);
// Obfuscated, create address 0x027FFE60
// This is offset 0x60 in the ROM header: port 0x040001A4 / setting for normal commands
card_ctrl_13 = 5;
card_ctrl_13 <<= 18;
card_ctrl_13 -= 13;
// Detect if the system is in DSi mode. If so, change the address to 0x02FFFE60
if (*(vu8 *) (register_base_1 + REG_A9ROM_OFFSET) & 1) {
card_ctrl_13 |= 0x40000;
}
card_ctrl_13 <<= 5;
// Read port setting and set page read flags
card_ctrl_cmd = (*(vs32 *) card_ctrl_13 & ~CARD_CTL_CMD_MASK) | (CARD_CTL_CMD_PAGE | CARD_CTL_READ | CARD_CTL_START);
// Calculate offset to round back to nearest 0x200-byte block.
// E.G. if we want to read starting from 0x1208, we actually need to
// request the block at 0x1200 and then ignore the first 8 bytes of the result.
// This would set `addr_offset` to -8.
addr_offset = 0 - (addr & (CARD_ROM_PAGE_SIZE - 1));
// Wait for card to not be busy
while (*(vu32 *) (register_base_1 + REG_CARD_CNT_OFFSET) & CARD_CTL_START) {
continue;
}
// Write enable flag to card ROM and SPI control register
*(vu8 *) (register_base_1 + REG_CARD_AUX_SPI_CNT_OFFSET + 1) = CARDMST_ENABLE;
// Read 8-byte command out from gamecard bus, write this back later
for (i = 0; i < 8; i++) {
buffer[i] = *(vnull + _MAIN_REG_BASE + REG_CARD_CMD_OFFSET + i);
}
addr += addr_offset;
while (addr_offset < num_bytes) {
// Read a 0x200-byte data block from ROM
// Write 8-byte command to registers
// B7XXXXXXXX000000 -> 0x200-byte encrypted data read from address XXXXXXXX
register_base_2[REG_CARD_CMD_OFFSET + 0] = CARD_CMD_ENCRYPTED_READ;
register_base_2[REG_CARD_CMD_OFFSET + 1] = addr >> 24;
register_base_2[REG_CARD_CMD_OFFSET + 2] = addr >> 16;
register_base_2[REG_CARD_CMD_OFFSET + 3] = addr >> 8;
register_base_2[REG_CARD_CMD_OFFSET + 4] = addr;
register_base_2[REG_CARD_CMD_OFFSET + 5] = 0x00;
register_base_2[REG_CARD_CMD_OFFSET + 6] = 0x00;
register_base_2[REG_CARD_CMD_OFFSET + 7] = 0x00;
// Submit command
*(vu32 *) (register_base_1 + REG_CARD_CNT_OFFSET) = card_ctrl_cmd;
// Copy the output into the destination buffer, within the bounds of num_bytes
// (Must read the output out of the I/O register regardless)
do {
if (*(vu32 *) (register_base_1 + REG_CARD_CNT_OFFSET) & CARD_DATA_READY) {
output = *(vu32 *) (register_base_1 + REG_CARD_DATA_OFFSET);
if (addr_offset >= 0 && addr_offset < num_bytes) {
*(u32 *) ((u32) dest + addr_offset) = output;
}
addr_offset += 4;
}
} while (*(vu32 *) (register_base_1 + REG_CARD_CNT_OFFSET) & CARD_CTL_START);
// Advance address to next block
addr += CARD_ROM_PAGE_SIZE;
}
// Done reading, restore everything how it was before
// Write original command back to gamecard bus
for (i = 0; i < 8; i++) {
*(vnull + _MAIN_REG_BASE + REG_CARD_CMD_OFFSET + i) = buffer[i];
}
// Write original value back to to external memory control register
*(vu16 *) (register_base_1 + REG_EXMEM_CNT_OFFSET) = ext_mem_register_val_original;
CARD_func_0011(lock_id);
OS_func_0178(lock_id);
}
u32 ROMUtil_CRC32(void *buf, u32 size) {
int i;
u32 crc;
u32 poly;
u8 *byte_ptr;
byte_ptr = (u8 *) buf;
crc = 0xFFFFFFFF;
poly = 0xEDB88320;
while (size-- != 0) {
crc ^= *byte_ptr++;
for (i = 0; i < 8; i++) {
if (crc & 1) {
crc = (crc >> 1);
} else {
crc = poly ^ (crc >> 1);
}
}
}
return ~crc;
}
+254
View File
@@ -0,0 +1,254 @@
import sys
from argparse import ArgumentParser, Namespace
from bisect import bisect_left, bisect_right
from collections.abc import Generator
from io import TextIOWrapper
from pathlib import Path
from typing import Never
import elftools.construct
import elftools.elf.sections
from elftools.elf.elffile import ELFFile
from elftools.elf.sections import SymbolTableSection
ASM_COMMON_INCLUDE = "dsprot/asm_macro.inc"
STATIC_INIT_FN_NAME = "NitroStaticInit"
def address(symbol: elftools.elf.sections.Symbol) -> int:
value = symbol.entry.get("st_value")
if type(value) is not int:
panic(
f"Expected st_value of symbol {symbol.name} to be an int but got {type(value)} = {value}"
)
return value
class Symbol:
def __init__(self, symbol: elftools.elf.sections.Symbol):
self.symbol = symbol
self.address = address(symbol)
self.section: Section | None = None
def name(self) -> str:
return self.symbol.name
def size(self) -> int:
size = self.symbol.entry.get("st_size")
if type(size) is not int:
panic(
f"Expected st_size of symbol {self.symbol.name} to be an int but got {type(size)} = {size}"
)
return size
def _st_info(self) -> elftools.construct.Container:
st_info = self.symbol.entry.get("st_info")
if type(st_info) is not elftools.construct.Container:
panic(
f"Expected st_info of symbol {self.symbol.name} to be a Container but got {type(st_info)} = {st_info}"
)
return st_info
def section_index(self) -> int | None:
shndx = self.symbol.entry.get("st_shndx")
if shndx in ["SHN_UNDEF", "SHN_ABS"]:
return None
if type(shndx) is not int:
panic(
f"Expected st_shndx of symbol {self.symbol.name} to be an int but got {type(shndx)} = {shndx}"
)
return shndx
def type(self) -> str:
st_info = self._st_info()
st_type = st_info.get("type")
if type(st_type) is not str:
panic(
f"Expected st_info.type of symbol {self.symbol.name} to be a str but got {type(st_type)} = {st_type}"
)
return st_type
def code_size(self) -> int:
if self.type() != "STT_FUNC":
return 0
address = self.address
size = self.size()
end_address = address + size
# Look for constant pool inside this function
if self.section is not None:
for next_symbol in self.section.symbols_by_address(address + 1):
if next_symbol.address >= end_address:
break
if next_symbol.name() == "$d":
return next_symbol.address - self.address
# If no constant pool exists, this function's size is st_size
return size
class Section:
def __init__(self, elf: "Elf", section: elftools.elf.sections.Section):
self.elf = elf
self.section = section
self.symbols: list[Symbol] = []
self.symbol_indices_by_address: list[int] = []
def name(self) -> str:
return self.section.name
def add_symbol(self, symbol: Symbol):
index = len(self.symbols)
self.symbols.append(symbol)
pos = bisect_right(
self.symbol_indices_by_address,
symbol.address,
key=lambda s: self.symbols[s].address,
)
self.symbol_indices_by_address.insert(pos, index)
def symbols_by_address(self, start_address=0) -> Generator[Symbol]:
start_index = bisect_left(
self.symbol_indices_by_address,
start_address,
key=lambda i: self.symbols[i].address,
)
for i in range(start_index, len(self.symbols)):
yield self.symbols[self.symbol_indices_by_address[i]]
class Elf:
def __init__(self, elf: ELFFile):
self.elf = elf
self.sections: list[Section] = [
Section(self, section) for section in elf.iter_sections()
]
for section in elf.iter_sections():
if not isinstance(section, SymbolTableSection):
continue
for symbol in section.iter_symbols():
symbol = Symbol(symbol)
section_index = symbol.section_index()
if section_index is not None:
symbol.section = self.sections[section_index]
symbol.section.add_symbol(symbol)
def symbol_by_name(self, name: str) -> Generator[Symbol]:
for section in self.sections:
for symbol in section.symbols:
if symbol.name() == name:
yield symbol
class Args:
def __init__(self, args: Namespace):
self.output = Path(args.output)
self.garbage: str | None = args.garbage
self.prefix: str = args.prefix
self.inputs = list(map(Path, args.input))
for input in self.inputs:
if not input.exists():
raise ValueError(f"Input file '{input}' does not exist")
key: str | None = args.key
if key is None:
self.key = None
elif key.startswith("0x"):
self.key = int(key, base=16)
else:
self.key = int(key, base=10)
if args.key is None:
self.symbols = [f"{args.prefix}{symbol}" for symbol in args.symbols]
else:
self.symbols = list(map(str, args.symbols))
def panic(message) -> Never:
print(message)
sys.exit(1)
def write_assembly(f: TextIOWrapper, args: Args, symbols: list[Symbol]) -> None:
f.write("; Generated by libs/dsprot/tools/asmwriter.py\n")
f.write("\n")
f.write(f'.include "{ASM_COMMON_INCLUDE}"\n')
f.write("\n")
for symbol in symbols:
f.write(f".public {symbol.name()}\n")
if args.garbage is not None:
f.write(f".public {args.garbage}\n")
f.write("\n")
f.write(" .text\n")
f.write(" .balign 4, 0\n")
f.write("\n")
if args.key is not None:
for symbol in symbols:
f.write(f" arm_func_start {args.prefix}{symbol.name()}\n")
f.write(f"{args.prefix}{symbol.name()}:\n")
f.write(
f" run_encrypted_func {symbol.name()}, {symbol.code_size():#x}, {args.key:#x}\n"
)
f.write(f" arm_func_end {args.prefix}{symbol.name()}\n")
f.write("\n")
else:
f.write(f" local_arm_func_start {STATIC_INIT_FN_NAME}\n")
f.write(f"{STATIC_INIT_FN_NAME}:\n")
f.write(" decode_func_table encoded_func_table\n")
f.write("encoded_func_table:\n")
for symbol in symbols:
symbol_name = symbol.name()
if args.key is not None:
symbol_name = args.prefix + symbol_name
f.write(f" func_table_entry {symbol_name}, {symbol.code_size():#x}\n")
f.write(" func_table_end\n")
if args.garbage is not None:
f.write(f" garbage_ref {args.garbage}\n")
f.write(f" arm_func_end {STATIC_INIT_FN_NAME}\n")
f.write("\n")
f.write(" .section .ctor, 4\n")
f.write(f" sinit {STATIC_INIT_FN_NAME}\n")
f.write("\n")
def main():
parser = ArgumentParser()
parser.add_argument("-i", "--input", required=True, nargs="+")
parser.add_argument("-o", "--output", required=True)
parser.add_argument("-s", "--symbols", required=True, nargs="+")
parser.add_argument("-g", "--garbage")
parser.add_argument("-k", "--key")
parser.add_argument("-p", "--prefix", default="RunEncrypted_")
try:
args = Args(parser.parse_args())
except ValueError as e:
panic(e)
symbols = {}
missing_symbols = args.symbols.copy()
for input in args.inputs:
with input.open("rb") as f:
elf = Elf(ELFFile(f))
for symbol_name in missing_symbols.copy():
matches = list(elf.symbol_by_name(symbol_name))
if len(matches) == 0:
continue
symbols[symbol_name] = matches[0]
missing_symbols.remove(symbol_name)
if len(missing_symbols) > 0:
panic(f"Symbol {missing_symbols[0]} does not exist")
symbols = [symbols[name] for name in args.symbols]
with args.output.open("w") as f:
write_assembly(f, args, symbols)
if __name__ == "__main__":
main()
-1
View File
@@ -2,7 +2,6 @@
#include <stddef.h>
#include "nitro/card.h"
#include "nitro/dc.h"
#include "nitro/fs.h"
#include "nitro/fx.h"
#include "nitro/g2.h"
+16
View File
@@ -29,6 +29,19 @@ extern "C" {
#define CARD_RESULT_NO_RESPONSE
#define CARD_RESULT_ERROR
#define CARD_ROM_PAGE_SIZE 0x200
#define CARD_DATA_READY 0x800000
#define CARD_CTL_CMD_MASK 0x7000000
#define CARD_CTL_CMD_PAGE 0x1000000
#define CARD_CTL_READ 0x20000000
#define CARD_CTL_START 0x80000000
#define CARD_CMD_ENCRYPTED_READ 0xb7
#define CARDMST_ENABLE 0x80
typedef u32 CARDBackupType;
typedef u32 CARDResult;
@@ -45,6 +58,9 @@ CARDResult CARD_GetResultCode(void);
BOOL CARD_func_0033();
void CARD_func_0034();
void CARD_func_0010(u32);
void CARD_func_0011(u32);
inline BOOL CARD_ReadEepromAsync(u32 offset, void *buf, u32 size, void *param4, void *param5) {
return CARD_ReadWriteBackupAsync(offset, buf, size, param4, param5, 1, 6, 1, 0);
}
+18
View File
@@ -7,8 +7,10 @@ extern "C" {
#include <stdarg.h>
#include "nitro/os/cache.h"
#include "nitro/os/context.h"
#include "nitro/os/mutex.h"
#include "nitro/os/owner.h"
#include "nitro/os/thread.h"
#include "nitro/reg.h"
@@ -30,6 +32,12 @@ extern "C" {
#define OS_THREAD_LAUNCHER_PRIORITY 0x10
#define OS_EXMEM_CNT_NDS_SLOT_ACCESS_SHIFT 11
#define OS_EXMEM_CNT_NDS_SLOT_ACCESS (1 << OS_EXMEM_CNT_NDS_SLOT_ACCESS_SHIFT)
#define OS_CPU_ARM9 0
#define OS_CPU_ARM7 1
typedef struct OSLinkedList {
/* 00 */ void *head;
/* 04 */ void *tail;
@@ -166,6 +174,9 @@ s32 OS_func_0171(u32, u32, u32);
s32 OS_func_0174(void);
BOOL OS_func_0065(void);
void OS_func_0176(u8 *);
void OS_func_0178(u32);
inline void OS_SetIrqCheckFlag(void) {
REG_IRQ |= 1;
}
@@ -228,9 +239,16 @@ inline BOOL OS_IsRunOnTwl(void) {
return false;
#else
// Probably checks some reg here
#define REG_A9ROM_OFFSET 0x4000
#define REG_SCFG_A9ROM_SEC_MASK 1
#endif
}
inline void OS_SetNdsSlotAccess(u32 processor) {
REG_EXMEM_CNT = (REG_EXMEM_CNT & ~OS_EXMEM_CNT_NDS_SLOT_ACCESS) | (processor << OS_EXMEM_CNT_NDS_SLOT_ACCESS_SHIFT);
}
#ifdef __cplusplus
} // extern "C"
#endif
@@ -1,12 +1,14 @@
#ifndef _NITRO_DC_H
#define _NITRO_DC_H
#include "nitro/types.h"
#ifndef _NITRO_OS_CACHE_H
#define _NITRO_OS_CACHE_H
#ifdef __cplusplus
extern "C" {
#endif
#include "nitro/types.h"
#define OS_CACHE_LINE_SIZE 0x20
void DC_StoreAll(void);
void DC_StoreRange(void *ptr, u32 size);
@@ -15,9 +17,10 @@ void DC_FlushRange(void *ptr, u32 size);
void DC_InvalidateRange(void *ptr, u32 size);
void DC_func_0004(void *, int);
void DC_func_0002();
void IC_InvalidateRange(void *ptr, u32 size);
#ifdef __cplusplus
} // extern "C"
#endif
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef _NITRO_CONTEXT_H
#define _NITRO_CONTEXT_H
#include <types.h>
#include "nitro/types.h"
typedef struct OSContext {
/* 0x00 */ u32 cpsr;
+2 -2
View File
@@ -1,8 +1,8 @@
#ifndef NITROSDK_OS_MUTEX_H
#define NITROSDK_OS_MUTEX_H
#include <nitro/os/thread.h>
#include <types.h>
#include "nitro/os/thread.h"
#include "nitro/types.h"
typedef struct OSMutex {
/* 0x00 */ OSThreadQueue queue;
+28
View File
@@ -0,0 +1,28 @@
#ifndef _NITRO_OS_OWNER_H
#define _NITRO_OS_OWNER_H
#ifdef __cplusplus
extern "C" {
#endif
#include "nitro/types.h"
typedef struct OSOwnerInfo {
/* 00 */ u8 unk_00[0x2];
struct {
/* 02 */ u8 month;
/* 03 */ u8 day;
} birthday;
/* 04 */ u8 unk_04[0x16];
/* 1a */ u16 nickNameLength;
/* 1c */ u8 unk_1c[0x38];
/* 54 */
} OSOwnerInfo;
void OS_func_0177(OSOwnerInfo *info);
#ifdef __cplusplus
} // extern "C"
#endif
#endif
+64 -47
View File
@@ -7,32 +7,37 @@ extern "C" {
#include "nitro/types.h"
#define REG_POWER_CNT (*(vu16 *) 0x04000304)
#define REG_IME (*(vu16 *) 0x04000208)
#define REG_BASE 0x4000000
#define REG_DISPSTAT (*(vu16 *) 0x4000004)
#define REG_VCOUNT (*(vu16 *) 0x04000006)
#define REG_DISP3DCNT (*(vu16 *) 0x04000060)
#define REG_DISPCAPCNT (*(vu32 *) 0x04000064)
#define REG_GFX_STATUS (*(vu32 *) 0x04000600)
#define REG_POWER_CNT (*(vu16 *) (REG_BASE | 0x304))
#define REG_IME (*(vu16 *) (REG_BASE | 0x208))
#define REG_DMA ((OSDma *) 0x040000B0)
#define REG_DMA0SAD (*(vu32 *) 0x040000B0)
#define REG_DMA0DAD (*(vu32 *) 0x040000B4)
#define REG_DMA0CNT (*(vu32 *) 0x040000B8)
#define REG_DISPSTAT (*(vu16 *) (REG_BASE | 0x4))
#define REG_VCOUNT (*(vu16 *) (REG_BASE | 0x6))
#define REG_DISP3DCNT (*(vu16 *) (REG_BASE | 0x60))
#define REG_DISPCAPCNT (*(vu32 *) (REG_BASE | 0x64))
#define REG_GFX_STATUS (*(vu32 *) (REG_BASE | 0x600))
#define REG_VRAM_CNT_ABCD (*(vu32 *) 0x04000240)
#define REG_VRAM_CNT_A (*(vu8 *) 0x04000240)
#define REG_VRAM_CNT_B (*(vu8 *) 0x04000241)
#define REG_VRAM_CNT_C (*(vu8 *) 0x04000242)
#define REG_VRAM_CNT_D (*(vu8 *) 0x04000243)
#define REG_VRAM_CNT_E (*(vu8 *) 0x04000244)
#define REG_VRAM_CNT_F (*(vu8 *) 0x04000245)
#define REG_VRAM_CNT_G (*(vu8 *) 0x04000246)
#define REG_WRAM_CNT (*(vu8 *) 0x04000247)
#define REG_VRAM_CNT_HI (*(vu16 *) 0x04000248)
#define REG_VRAM_CNT_H (*(vu8 *) 0x04000248)
#define REG_VRAM_CNT_I (*(vu8 *) 0x04000249)
#define REG_DMA ((OSDma *) (REG_BASE | 0xB0))
#define REG_DMA0SAD (*(vu32 *) (REG_BASE | 0xB0))
#define REG_DMA0DAD (*(vu32 *) (REG_BASE | 0xB4))
#define REG_DMA0CNT (*(vu32 *) (REG_BASE | 0xB8))
#define REG_VRAM_CNT_ABCD (*(vu32 *) (REG_BASE | 0x240))
#define REG_VRAM_CNT_A (*(vu8 *) (REG_BASE | 0x240))
#define REG_VRAM_CNT_B (*(vu8 *) (REG_BASE | 0x241))
#define REG_VRAM_CNT_C (*(vu8 *) (REG_BASE | 0x242))
#define REG_VRAM_CNT_D (*(vu8 *) (REG_BASE | 0x243))
#define REG_VRAM_CNT_E (*(vu8 *) (REG_BASE | 0x244))
#define REG_VRAM_CNT_F (*(vu8 *) (REG_BASE | 0x245))
#define REG_VRAM_CNT_G (*(vu8 *) (REG_BASE | 0x246))
#define REG_WRAM_CNT (*(vu8 *) (REG_BASE | 0x247))
#define REG_VRAM_CNT_HI (*(vu16 *) (REG_BASE | 0x248))
#define REG_VRAM_CNT_H (*(vu8 *) (REG_BASE | 0x248))
#define REG_VRAM_CNT_I (*(vu8 *) (REG_BASE | 0x249))
#define REG_EXMEM_CNT_OFFSET 0x204
#define REG_EXMEM_CNT (*(vu16 *) (REG_BASE | REG_EXMEM_CNT_OFFSET))
#if NITRO_VERSION >= 0x05057533
#define _BIOS_REG_BASE 0x02FFF000
@@ -41,7 +46,16 @@ extern "C" {
#endif
#define REG_PAD (*(u16 *) (_BIOS_REG_BASE | 0xFA8))
#define REG_KEYINPUT (*(u16 *) 0x04000130)
#define REG_KEYINPUT (*(u16 *) (REG_BASE | 0x130))
#define REG_CARD_AUX_SPI_CNT_OFFSET 0x1A0
#define REG_CARD_AUX_SPI_CNT (*(vu16 *) (REG_BASE | 0x1A0))
#define REG_CARD_CNT_OFFSET 0x1A4
#define REG_CARD_CNT (*(vu32 *) (REG_BASE | REG_CARD_CNT_OFFSET))
#define REG_CARD_CMD_OFFSET 0x1A8
#define REG_CARD_CMD (*(vu8 *) (REG_BASE | REG_CARD_CMD_OFFSET))
#define REG_CARD_DATA_OFFSET 0x100010
#define REG_CARD_DATA (*(vu32 *) (REG_BASE | REG_CARD_DATA_OFFSET))
#define REG_FRAME_COUNTER (*(u32 *) (_BIOS_REG_BASE | 0xC3C))
#define REG_027FFC40 (*(u16 *) (_BIOS_REG_BASE | 0xC40))
@@ -56,33 +70,33 @@ extern "C" {
#define REG_027FFF9C (*(u32 *) (_BIOS_REG_BASE | 0xF9C))
#define REG_027FFFA0 (*(u32 *) (_BIOS_REG_BASE | 0xFA0))
#define REG_GFX_FIFO (*(vu32 *) 0x04000400)
#define REG_GFX_FIFO_MATRIX_MODE (*(vu32 *) 0x04000440)
#define REG_GFX_FIFO_MATRIX_PUSH (*(vu32 *) 0x04000444)
#define REG_GFX_FIFO_MATRIX_POP (*(vu32 *) 0x04000448)
#define REG_GFX_FIFO_MATRIX_STORE (*(vu32 *) 0x0400044C)
#define REG_GFX_FIFO_MATRIX_RESTORE (*(vu32 *) 0x04000450)
#define REG_GFX_FIFO_MATRIX_IDENTITY (*(vu32 *) 0x04000454)
#define REG_GFX_FIFO_MATRIX_TRANSLATE (*(vu32 *) 0x04000470)
#define REG_GFX_FIFO_VERTEX_COLOR (*(vu32 *) 0x04000480)
#define REG_GFX_FIFO_VERTEX_TEXCOORD (*(vu32 *) 0x04000488)
#define REG_GFX_FIFO_VERTEX_16 (*(vu32 *) 0x0400048C)
#define REG_GFX_FIFO_VERTEX_XZ (*(vu32 *) 0x04000498)
#define REG_GFX_FIFO_POLYGON_ATTR (*(vu32 *) 0x040004A4)
#define REG_GFX_FIFO_TEXTURE_PARAM (*(vu32 *) 0x040004A8)
#define REG_GFX_FIFO_TEXTURE_PALETTE (*(vu32 *) 0x040004AC)
#define REG_GFX_FIFO_DIFFUSE_AMBIENT_REFLECT (*(vu32 *) 0x040004C0)
#define REG_GFX_FIFO_POLYGONS_BEGIN (*(vu32 *) 0x04000500)
#define REG_GFX_FIFO_POLYGONS_END (*(vu32 *) 0x04000504)
#define REG_GFX_FIFO_SWAP_BUFFERS (*(vu32 *) 0x04000540)
#define REG_GFX_FIFO_VIEWPORT (*(vu32 *) 0x04000580)
#define REG_GFX_FIFO (*(vu32 *) (REG_BASE | 0x400))
#define REG_GFX_FIFO_MATRIX_MODE (*(vu32 *) (REG_BASE | 0x440))
#define REG_GFX_FIFO_MATRIX_PUSH (*(vu32 *) (REG_BASE | 0x444))
#define REG_GFX_FIFO_MATRIX_POP (*(vu32 *) (REG_BASE | 0x448))
#define REG_GFX_FIFO_MATRIX_STORE (*(vu32 *) (REG_BASE | 0x44C))
#define REG_GFX_FIFO_MATRIX_RESTORE (*(vu32 *) (REG_BASE | 0x450))
#define REG_GFX_FIFO_MATRIX_IDENTITY (*(vu32 *) (REG_BASE | 0x454))
#define REG_GFX_FIFO_MATRIX_TRANSLATE (*(vu32 *) (REG_BASE | 0x470))
#define REG_GFX_FIFO_VERTEX_COLOR (*(vu32 *) (REG_BASE | 0x480))
#define REG_GFX_FIFO_VERTEX_TEXCOORD (*(vu32 *) (REG_BASE | 0x488))
#define REG_GFX_FIFO_VERTEX_16 (*(vu32 *) (REG_BASE | 0x48C))
#define REG_GFX_FIFO_VERTEX_XZ (*(vu32 *) (REG_BASE | 0x498))
#define REG_GFX_FIFO_POLYGON_ATTR (*(vu32 *) (REG_BASE | 0x4A4))
#define REG_GFX_FIFO_TEXTURE_PARAM (*(vu32 *) (REG_BASE | 0x4A8))
#define REG_GFX_FIFO_TEXTURE_PALETTE (*(vu32 *) (REG_BASE | 0x4AC))
#define REG_GFX_FIFO_DIFFUSE_AMBIENT_REFLECT (*(vu32 *) (REG_BASE | 0x4C0))
#define REG_GFX_FIFO_POLYGONS_BEGIN (*(vu32 *) (REG_BASE | 0x500))
#define REG_GFX_FIFO_POLYGONS_END (*(vu32 *) (REG_BASE | 0x504))
#define REG_GFX_FIFO_SWAP_BUFFERS (*(vu32 *) (REG_BASE | 0x540))
#define REG_GFX_FIFO_VIEWPORT (*(vu32 *) (REG_BASE | 0x580))
extern u32 __DTCM_LO;
#define DTCM_LO ((u8 *) &__DTCM_LO)
#define REG_IRQ (*(u32 *) (DTCM_LO + 0x3FF8))
#define _MAIN_REG_BASE 0x04000000
#define _SUB_REG_BASE 0x04001000
#define _MAIN_REG_BASE REG_BASE
#define _SUB_REG_BASE (REG_BASE | 0x1000)
#define _REG_DISPCNT(base) (*(u32 *) ((base) | 0x0))
#define _REG_BG0CNT(base) (*(vu16 *) ((base) | 0x8))
@@ -171,7 +185,10 @@ extern u32 __DTCM_LO;
#define REG_BLDALPHA_SUB _REG_BLDALPHA(_SUB_REG_BASE)
#define REG_MASTER_BRIGHT_SUB _REG_MASTER_BRIGHT(_SUB_REG_BASE)
#define REG_04FFF200 (*(vu32 *) 0x04FFF200)
#define REG_A9ROM_OFFSET 0x4000
#define REG_A9ROM (*(vu16 *) (REG_BASE | REG_A9ROM_OFFSET))
#define REG_04FFF200 (*(vu32 *) (REG_BASE | 0xFFF200))
#ifdef __cplusplus
} // extern "C"
+6
View File
@@ -9,11 +9,13 @@ extern "C" {
#endif
typedef unsigned long long u64;
typedef unsigned long ulong;
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef long long s64;
typedef long long slong;
typedef int s32;
typedef short s16;
typedef char s8;
@@ -22,11 +24,13 @@ typedef float f32;
typedef double f64;
typedef volatile u64 vu64;
typedef volatile u64 vulong;
typedef volatile u32 vu32;
typedef volatile u16 vu16;
typedef volatile u8 vu8;
typedef volatile s64 vs64;
typedef volatile s64 vslong;
typedef volatile s32 vs32;
typedef volatile s16 vs16;
typedef volatile s8 vs8;
@@ -35,6 +39,8 @@ typedef volatile f32 vf32;
typedef volatile f64 vf64;
typedef s32 BOOL;
#define TRUE 1
#define FALSE 0
#define ATTRIBUTE_ALIGN(x) __attribute__((aligned(x)))