Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatic ROM Patching #75

Merged
merged 2 commits into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "libn3ds"]
path = libn3ds
url = https://github.com/profi200/libn3ds.git
url = https://github.com/profi200/libn3ds
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ X+LEFT - Turn off LCD backlight.

X+RIGHT - Turn on LCD backlight.

Hold the X button while launching a game to skip applying patches (if present)

Hold the power button to turn off the 3DS.

## Configuration
Expand Down Expand Up @@ -80,6 +82,9 @@ Game-specific settings. Only intended to be used in the per-game settings (romNa
`u8 saveSlot` - Savegame slot (0-9)
* Default: `0`

`u8 saveType` - Override to use a specific save type, see values for `defaultSave` (0-15, 255)
* Default: `255` (disabled)

### Advanced
Options for advanced users. No pun intended.

Expand All @@ -98,6 +103,10 @@ Options for advanced users. No pun intended.
* `14`: SRAM 256k
* `15`: None

## Patches
open_agb_firm supports automatically applying IPS and UPS patches. To use a patch, rename the patch file to match the ROM file name (without the extension).
* If you wanted to apply an IPS patch to `example.gba`, rename the patch file to `example.ips`

## Known Issues
This section is reserved for a listing of known issues. At present only this remains:
* Sleep mode is not fully implemented.
Expand Down
2 changes: 1 addition & 1 deletion include/arm11/open_agb_firm.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ Result oafParseConfigEarly(void);
void changeBacklight(s16 amount);
Result oafInitAndRun(void);
void oafUpdate(void);
void oafFinish(void);
void oafFinish(void);
3 changes: 3 additions & 0 deletions include/arm11/patch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#pragma once

Result patchRom(const char *const gamePath, u32 *romSize);
28 changes: 20 additions & 8 deletions source/arm11/open_agb_firm.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "arm11/drivers/lcd.h"
#include "arm11/gpu_cmd_lists.h"
#include "arm11/drivers/mcu.h"
#include "arm11/patch.h"
#include "kernel.h"
#include "kevent.h"

Expand All @@ -58,7 +59,6 @@
"saveOverride=false\n" \
"defaultSave=14"


typedef struct
{
// [general]
Expand All @@ -76,7 +76,7 @@ typedef struct

// [game]
u8 saveSlot;
// TODO: Per-game save type override.
u8 saveType;

// [advanced]
bool saveOverride;
Expand Down Expand Up @@ -110,23 +110,21 @@ static OafConfig g_oafConfig =

// [game]
0, // saveSlot
0xFF, // saveType

// [advanced]
false, // saveOverride
14 // defaultSave
};
static KHandle g_frameReadyEvent = 0;



static u32 fixRomPadding(u32 romFileSize)
{
// Pad unused ROM area with 0xFFs (trimmed ROMs).
// Smallest retail ROM chip is 8 Mbit (1 MiB).
u32 romSize = nextPow2(romFileSize);
if(romSize < 0x100000u) romSize = 0x100000u;
memset((void*)(ROM_LOC + romFileSize), 0xFFFFFFFFu, romSize - romFileSize);

if(romSize > 0x100000u) // >1 MiB.
{
// Fake "open bus" padding.
Expand All @@ -140,6 +138,7 @@ static u32 fixRomPadding(u32 romFileSize)
}
else
{

// ROM mirroring (Classic NES Series/possibly others with 8 Mbit ROM).
// Mirror ROM across the entire 32 MiB area.
for(uintptr_t i = ROM_LOC + romSize; i < ROM_LOC + MAX_ROM_SIZE; i += romSize)
Expand Down Expand Up @@ -167,9 +166,10 @@ static Result loadGbaRom(const char *const path, u32 *const romSizeOut)

u32 read;
res = fRead(f, (u8*)ROM_LOC, fileSize, &read);
if(read == fileSize) *romSizeOut = fixRomPadding(fileSize);

fClose(f);

if(read == fileSize) *romSizeOut = fixRomPadding(fileSize); //, path);

}

return res;
Expand Down Expand Up @@ -549,6 +549,8 @@ static int cfgIniCallback(void* user, const char* section, const char* name, con
{
if(strcmp(name, "saveSlot") == 0)
config->saveSlot = (u8)strtoul(value, NULL, 10);
if(strcmp(name, "saveType") == 0)
config->saveType = (u8)strtoul(value, NULL, 10);
}
else if(strcmp(section, "advanced") == 0)
{
Expand Down Expand Up @@ -751,6 +753,11 @@ Result oafInitAndRun(void)
}
else if(res != RES_OK) break;

//make copy of rom path
char *const romFilePath = (char*)calloc(strlen(filePath)+1, 1);
if(romFilePath == NULL) { res = RES_OUT_OF_MEM; break; }
strcpy(romFilePath, filePath);

// Load the ROM file.
u32 romSize;
if((res = loadGbaRom(filePath, &romSize)) != RES_OK) break;
Expand All @@ -762,11 +769,16 @@ Result oafInitAndRun(void)
// Adjust the path for the save file and get save type.
gameCfg2SavePath(filePath, g_oafConfig.saveSlot);
u16 saveType;
if(g_oafConfig.useGbaDb || g_oafConfig.saveOverride)
if(g_oafConfig.saveType != 0xFF)
saveType = g_oafConfig.saveType;
else if(g_oafConfig.useGbaDb || g_oafConfig.saveOverride)
saveType = getSaveType(romSize, filePath);
else
saveType = detectSaveType(romSize);

patchRom(romFilePath, &romSize);
free(romFilePath);

// Prepare ARM9 for GBA mode + save loading.
if((res = LGY_prepareGbaMode(g_oafConfig.directBoot, saveType, filePath)) == RES_OK)
{
Expand Down
Loading