]> Chaos Git - corbenik/corbenik.git/commitdiff
Loader now uses externalized patches.
authorroot <chaos.kagami@gmail.com>
Thu, 2 Jun 2016 18:20:47 +0000 (14:20 -0400)
committerroot <chaos.kagami@gmail.com>
Thu, 2 Jun 2016 18:20:47 +0000 (14:20 -0400)
Aside from a few ones that involve complicated steps, of course.
It's STILL smaller than Nintendo's loader, incidentally!

(A few things need tweaking - namely, it is very slow to boot.
 I expect I need some kind of patch cache generated prior to boot.
 I also need to turn off the altmenu patch.)

17 files changed:
external/loader/source/interp.c
external/loader/source/interp.h [new file with mode: 0644]
external/loader/source/logger.c
external/loader/source/memory.c
external/loader/source/patch/block_cart_update.c [deleted file]
external/loader/source/patch/block_eshop_update.c [deleted file]
external/loader/source/patch/block_nim_update.c [deleted file]
external/loader/source/patch/errdisp.c [deleted file]
external/loader/source/patch/friends_ver.c [deleted file]
external/loader/source/patch/mset_str.c [deleted file]
external/loader/source/patch/patch.h [deleted file]
external/loader/source/patch/regionfree.c [deleted file]
external/loader/source/patch/ro_sigs.c [deleted file]
external/loader/source/patch/secinfo_sigs.c [deleted file]
external/loader/source/patcher.c
host/bytecode_asm.py
source/interp.c

index d09955e569fe81f9b25cf481de5c2cbb3a455ed9..92440af32bc02b022b55026e3573b507a990859e 100644 (file)
@@ -1,8 +1,6 @@
 // 'Tis not ready for the world at large yet.
 // I don't want to delete it since I'm working on it though,
 // so it's temporarliy #if'd 0.
-#if 0
-
 #define LOADER 1
 
 #include <3ds.h>
 #include "config.h"
 #include "../../../source/patch_format.h"
 
-#include "patch/patch.h"
+// Because I want to avoid malloc.
+// Patches must be smaller than this (including header!)
+#define MAX_PATCHSIZE 512
 
 // Yes, we're including a C file. Problem?
 #include "../../../source/interp.c"
 
+#if 0
+
 #endif
diff --git a/external/loader/source/interp.h b/external/loader/source/interp.h
new file mode 100644 (file)
index 0000000..06849dd
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __INTERP_H
+#define __INTERP_H
+
+int execb(char* filename, uint64_t tid, uint8_t* search_mem, uint32_t search_len);
+
+#endif
index 4aa090a2416ae135fab57baaee634378a6cbab58..9f71e53618275f58c3794a86080b0f9893626c92 100644 (file)
@@ -11,8 +11,6 @@
 #include "config.h"
 #include "../../../source/patch_format.h"
 
-#include "patch/patch.h"
-
 Handle log_file_hdl;
 int logger_is_initd = 0;
 
@@ -51,7 +49,7 @@ void logstr(const char* str) {
                return;
 
        // Write data.
-       FSFILE_Write(log_file_hdl, &wrote, size, str, len, 0);
+       FSFILE_Write(log_file_hdl, &wrote, size, str, len, FS_WRITE_FLUSH);
 }
 
 void logu64(u64 progId) {
index 40a9dddb5de55b6f7c1c226299952c6ed3f65d4d..b13161606b4740c6374ea0b83d1c372c64fbaaa5 100644 (file)
@@ -10,8 +10,6 @@
 #include "config.h"
 #include "../../../source/patch_format.h"
 
-#include "patch/patch.h"
-
 int
 memcmp(const void* buf1, const void* buf2, u32 size)
 {
diff --git a/external/loader/source/patch/block_cart_update.c b/external/loader/source/patch/block_cart_update.c
deleted file mode 100644 (file)
index 362a7d2..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "patch.h"
-
-/*
-  find 4, 0x0C, 0x18, 0xE1, 0xD8
-  set  4, 0x0B, 0x18, 0x21, 0xC8
-
-  find 4, 0x0C, 0x18, 0xE1, 0xD8
-  set  4, 0x0B, 0x18, 0x21, 0xC8
-*/
-
-void
-disable_cart_updates(u64 progId, u8* code, u32 size)
-{
-    static const u8 stopCartUpdatesPattern[] = { 0x0C, 0x18, 0xE1, 0xD8 };
-    static const u8 stopCartUpdatesPatch[] = { 0x0B, 0x18, 0x21, 0xC8 };
-
-    // Disable updates from foreign carts (makes carts region-free)
-    patchMemory(code, size, stopCartUpdatesPattern,
-                sizeof(stopCartUpdatesPattern), 0, stopCartUpdatesPatch,
-                sizeof(stopCartUpdatesPatch), 2);
-
-       logstr("  disable_cart_updates\n");
-}
diff --git a/external/loader/source/patch/block_eshop_update.c b/external/loader/source/patch/block_eshop_update.c
deleted file mode 100644 (file)
index b2894f6..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "patch.h"
-
-/*
-  find 4, 0x30, 0xB5, 0xF1, 0xB0
-  set  6, 0x00, 0x20, 0x08, 0x60, 0x70, 0x47
- */
-
-void
-disable_eshop_updates(u64 progId, u8* code, u32 size)
-{
-    static const u8 skipEshopUpdateCheckPattern[] = { 0x30, 0xB5, 0xF1, 0xB0 };
-    static const u8 skipEshopUpdateCheckPatch[] = { 0x00, 0x20, 0x08,
-                                                    0x60, 0x70, 0x47 };
-
-    // Skip update checks to access the EShop
-    patchMemory(code, size, skipEshopUpdateCheckPattern,
-                sizeof(skipEshopUpdateCheckPattern), 0,
-                skipEshopUpdateCheckPatch, sizeof(skipEshopUpdateCheckPatch),
-                1);
-
-       logstr("  disable_eshop_updates\n");
-}
diff --git a/external/loader/source/patch/block_nim_update.c b/external/loader/source/patch/block_nim_update.c
deleted file mode 100644 (file)
index 1e049a0..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "patch.h"
-
-/*
-  find 4, 0x25, 0x79, 0x0B, 0x99
-  set  2, 0xE3, 0xA0
- */
-
-void
-disable_nim_updates(u64 progId, u8* code, u32 size)
-{
-    static const u8 blockAutoUpdatesPattern[] = { 0x25, 0x79, 0x0B, 0x99 };
-    static const u8 blockAutoUpdatesPatch[] = { 0xE3, 0xA0 };
-
-    // Block silent auto-updates
-    patchMemory(code, size, blockAutoUpdatesPattern,
-                sizeof(blockAutoUpdatesPattern), 0, blockAutoUpdatesPatch,
-                sizeof(blockAutoUpdatesPatch), 1);
-
-       logstr("  disable_nim_updates\n");
-}
diff --git a/external/loader/source/patch/errdisp.c b/external/loader/source/patch/errdisp.c
deleted file mode 100644 (file)
index 8446b8f..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "patch.h"
-
-/*
-  find 8, 0x14, 0x00, 0xD0, 0xE5, 0xDB, 0x9A, 0x9F, 0xED
-  set  4, 0x00, 0x00, 0xA0, 0xE3
-
-  find 8, 0x14, 0x00, 0xD0, 0xE5, 0x01, 0x00, 0x10, 0xE3
-  set  4, 0x00, 0x00, 0xA0, 0xE3
-  find 8, 0x14, 0x00, 0xD0, 0xE5, 0x01, 0x00, 0x10, 0xE3
-  set  4, 0x00, 0x00, 0xA0, 0xE3
-  find 8, 0x14, 0x00, 0xD0, 0xE5, 0x01, 0x00, 0x10, 0xE3
-  set  4, 0x00, 0x00, 0xA0, 0xE3
- */
-
-void errdisp_devpatch(u64 progId, u8* code, u32 size) {
-       static const u8 unitinfoCheckPattern1[] = {0x14, 0x00, 0xD0, 0xE5, 0xDB, 0x9A, 0x9F, 0xED};
-       static const u8 unitinfoCheckPattern2[] = {0x14, 0x00, 0xD0, 0xE5, 0x01, 0x00, 0x10, 0xE3} ;
-       static const u8 unitinfoCheckPatch[] = {0x00, 0x00, 0xA0, 0xE3} ;
-
-       patchMemory(code, size,
-               unitinfoCheckPattern1,
-               sizeof(unitinfoCheckPattern1), 0,
-               unitinfoCheckPatch,
-               sizeof(unitinfoCheckPatch), 1
-       );
-
-       patchMemory(code, size,
-               unitinfoCheckPattern2,
-               sizeof(unitinfoCheckPattern2), 0,
-               unitinfoCheckPatch,
-               sizeof(unitinfoCheckPatch), 3
-       );
-}
diff --git a/external/loader/source/patch/friends_ver.c b/external/loader/source/patch/friends_ver.c
deleted file mode 100644 (file)
index f24c228..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "patch.h"
-
-/*
-  find 8, 0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01
-  fwd 9
-  set 1, 0x06
- */
-
-void
-fake_friends_version(u64 progId, u8* code, u32 size)
-{
-    static const u8 fpdVerPattern[] = { 0xE0, 0x1E, 0xFF, 0x2F,
-                                        0xE1, 0x01, 0x01, 0x01 };
-    static const u8 fpdVerPatch = 0x06; // Latest version.
-
-    // Allow online access to work with old friends modules
-    patchMemory(code, size, fpdVerPattern, sizeof(fpdVerPattern), 9,
-                &fpdVerPatch, sizeof(fpdVerPatch), 1);
-
-       logstr("  fake_friends_version\n");
-}
diff --git a/external/loader/source/patch/mset_str.c b/external/loader/source/patch/mset_str.c
deleted file mode 100644 (file)
index 1569199..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "patch.h"
-
-/*
-  find 8, u"Ver."
-  set  8, u".hax"
- */
-
-void
-settings_string(u64 progId, u8* code, u32 size)
-{
-    static const u16 verPattern[] = u"Ver.";
-    static const u16 verPatch[] = u".hax";
-
-    // Patch Ver. string
-    patchMemory(code, size, verPattern, sizeof(verPattern) - sizeof(u16), 0,
-                verPatch, sizeof(verPatch) - sizeof(u16), 1);
-
-       logstr("  settings_string\n");
-}
diff --git a/external/loader/source/patch/patch.h b/external/loader/source/patch/patch.h
deleted file mode 100644 (file)
index e9bc4c4..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __PATCH_PATCH_H
-#define __PATCH_PATCH_H
-
-#include <3ds.h>
-#include "../patcher.h"
-#include "../memory.h"
-#include "../logger.h"
-
-#ifndef PATH_MAX
-#define PATH_MAX 255
-#define _MAX_LFN 255
-#endif
-#include "../config.h"
-#include "../../../../source/patch_format.h"
-
-void disable_cart_updates(u64 progId, u8* code, u32 size);
-void disable_eshop_updates(u64 progId, u8* code, u32 size);
-void disable_nim_updates(u64 progId, u8* code, u32 size);
-void fake_friends_version(u64 progId, u8* code, u32 size);
-void settings_string(u64 progId, u8* code, u32 size);
-void region_patch(u64 progId, u8* code, u32 size);
-void ro_sigpatch(u64 progId, u8* code, u32 size);
-void secureinfo_sigpatch(u64 progId, u8* code, u32 size);
-void errdisp_devpatch(u64 progId, u8* code, u32 size);
-
-#endif
diff --git a/external/loader/source/patch/regionfree.c b/external/loader/source/patch/regionfree.c
deleted file mode 100644 (file)
index f8e677e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "patch.h"
-
-/*
-  find 8, 0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3
-  back 16
-  set  8, 0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
- */
-
-void
-region_patch(u64 progId, u8* code, u32 size)
-{
-    static const u8 regionFreePattern[] = { 0x00, 0x00, 0x55, 0xE3,
-                                            0x01, 0x10, 0xA0, 0xE3 };
-    static const u8 regionFreePatch[] = { 0x01, 0x00, 0xA0, 0xE3,
-                                          0x1E, 0xFF, 0x2F, 0xE1 };
-
-    // Patch SMDH region checks
-    patchMemory(code, size, regionFreePattern, sizeof(regionFreePattern), -16,
-                regionFreePatch, sizeof(regionFreePatch), 1);
-
-       logstr("  region_patch\n");
-}
diff --git a/external/loader/source/patch/ro_sigs.c b/external/loader/source/patch/ro_sigs.c
deleted file mode 100644 (file)
index b44d821..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "patch.h"
-
-/*
-  find 8, 0x30, 0x40, 0x2D, 0xE9, 0x02, 0x50, 0xA0, 0xE1
-  set  8, 0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
-
-  find 8, 0x30, 0x40, 0x2D, 0xE9, 0x24, 0xD0, 0x4D, 0xE2
-  set  8, 0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
-
-  find 8, 0xF8, 0x4F, 0x2D, 0xE9, 0x01, 0x70, 0xA0, 0xE1
-  set  8, 0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
- */
-
-void
-ro_sigpatch(u64 progId, u8* code, u32 size)
-{
-    static const u8 sigCheckPattern[] = { 0x30, 0x40, 0x2D, 0xE9,
-                                          0x02, 0x50, 0xA0, 0xE1 };
-    static const u8 sha256ChecksPattern1[] = { 0x30, 0x40, 0x2D, 0xE9,
-                                               0x24, 0xD0, 0x4D, 0xE2 };
-    static const u8 sha256ChecksPattern2[] = { 0xF8, 0x4F, 0x2D, 0xE9,
-                                               0x01, 0x70, 0xA0, 0xE1 };
-
-    // mov r0, #0; bx lr - equivalent to 'return 0;'
-    static const u8 stub[] = { 0x00, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 };
-
-    // Disable CRR0 signature (RSA2048 with SHA256) check
-    patchMemory(code, size, sigCheckPattern, sizeof(sigCheckPattern), 0, stub,
-                sizeof(stub), 1);
-
-    // Disable CRO0/CRR0 SHA256 hash checks (section hashes, and hash table)
-    patchMemory(code, size, sha256ChecksPattern1, sizeof(sha256ChecksPattern1),
-                0, stub, sizeof(stub), 1);
-
-    patchMemory(code, size, sha256ChecksPattern2, sizeof(sha256ChecksPattern2),
-                0, stub, sizeof(stub), 1);
-
-       logstr("  ro_sigpatch\n");
-}
diff --git a/external/loader/source/patch/secinfo_sigs.c b/external/loader/source/patch/secinfo_sigs.c
deleted file mode 100644 (file)
index 525b386..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "patch.h"
-
-/*
-  find 5, 0x06, 0x46, 0x10, 0x48, 0xFC
-  set  2, 0x00, 0x26
- */
-
-void
-secureinfo_sigpatch(u64 progId, u8* code, u32 size)
-{
-    static const u8 secureinfoSigCheckPattern[] = { 0x06, 0x46, 0x10, 0x48,
-                                                    0xFC };
-    static const u8 secureinfoSigCheckPatch[] = { 0x00, 0x26 };
-
-    // Disable SecureInfo signature check
-    patchMemory(code, size, secureinfoSigCheckPattern,
-                sizeof(secureinfoSigCheckPattern), 0, secureinfoSigCheckPatch,
-                sizeof(secureinfoSigCheckPatch), 1);
-
-       logstr("  secureinfo_sigpatch\n");
-}
index 121f55c874a0140122200cb56c6acdb90e8b70c3..ca98da643a57f796343c038a4801271fd243d5fb 100644 (file)
@@ -4,15 +4,14 @@
 #include "internal.h"
 #include "memory.h"
 #include "logger.h"
+#include "../../../source/patch_format.h"
+#include "interp.h"
 
 #ifndef PATH_MAX
 #define PATH_MAX 255
 #define _MAX_LFN 255
 #endif
 #include "config.h"
-#include "../../../source/patch_format.h"
-
-#include "patch/patch.h"
 
 int
 fileOpen(Handle* file, FS_ArchiveID id, const char* path, int flags)
@@ -57,8 +56,7 @@ load_config()
 
     FSFILE_Close(file); // Read to memory.
 
-    if (config.magic[0] != 'O' || config.magic[1] != 'V' ||
-        config.magic[2] != 'A' || config.magic[3] != 'N') {
+    if (memcmp(config.magic, "OVAN", 4)) {
         // Incorrect magic.
         // Failed to read.
         return;
@@ -355,69 +353,21 @@ patch_ro(u64 progId, u8* ro, u32 size, u32 orig_size)
 void
 patch_text(u64 progId, u8* text, u32 size, u32 orig_size)
 {
-    switch (progId) {
-        case 0x0004003000008F02LL: // USA Menu
-        case 0x0004003000008202LL: // EUR Menu
-        case 0x0004003000009802LL: // JPN Menu
-        case 0x000400300000A102LL: // CHN Menu
-        case 0x000400300000A902LL: // KOR Menu
-        case 0x000400300000B102LL: // TWN Menu
-        {
-            region_patch(progId, text, orig_size);
-            break;
-        }
-
-        case 0x0004013000002C02LL: // NIM
-        {
-            disable_nim_updates(progId, text, orig_size);
-            disable_eshop_updates(progId, text, orig_size);
-            break;
-        }
-
-        case 0x0004013000003202LL: // FRIENDS
-        {
-            fake_friends_version(progId, text, orig_size);
-            break;
-        }
-
-        case 0x0004001000021000LL: // USA MSET
-        case 0x0004001000020000LL: // JPN MSET
-        case 0x0004001000022000LL: // EUR MSET
-        case 0x0004001000026000LL: // CHN MSET
-        case 0x0004001000027000LL: // KOR MSET
-        case 0x0004001000028000LL: // TWN MSET
-        {
-            settings_string(progId, text, size);
-            break;
-        }
-        case 0x0004013000008002LL: // NS
-        {
-            disable_cart_updates(progId, text, orig_size);
-            adjust_cpu_settings(progId, text, orig_size);
-            break;
-        }
-
-        case 0x0004013000001702LL: // CFG
-        {
-            secureinfo_sigpatch(progId, text, orig_size);
-            break;
-        }
-        case 0x0004013000003702LL: // RO
-        {
-            ro_sigpatch(progId, text, orig_size);
-            break;
-        }
-               case 0x0004003000008A02LL: // ErrDisp
-               {
-                       errdisp_devpatch(progId, text, orig_size);
-                       break;
-               }
-        default: // Anything else.
-        {
-            language_emu(progId, text, orig_size);
-            break;
-        }
-    }
+       if (progId == 0x0004013000008002LL)
+        adjust_cpu_settings(progId, text, orig_size);
+
+       execb(PATH_PATCHES "/block_nim_update.vco", progId, text, orig_size);
+       execb(PATH_PATCHES "/block_eshop_update.vco", progId, text, orig_size);
+       execb(PATH_PATCHES "/block_cart_update.vco", progId, text, orig_size);
+       execb(PATH_PATCHES "/errdisp.vco", progId, text, orig_size);
+       execb(PATH_PATCHES "/friends_ver.vco", progId, text, orig_size);
+       execb(PATH_PATCHES "/mset_str.vco", progId, text, orig_size);
+       execb(PATH_PATCHES "/ns_force_menu.vco", progId, text, orig_size);
+       execb(PATH_PATCHES "/regionfree.vco", progId, text, orig_size);
+       execb(PATH_PATCHES "/secinfo_sigs.vco", progId, text, orig_size);
+       execb(PATH_PATCHES "/ro_sigs.vco", progId, text, orig_size);
+
+    language_emu(progId, text, orig_size);
 }
 
 // Gets how many bytes .text must be extended by for patches to fit.
index 30aed0e28696ce6df5fa8de3a5ac0c5b425de6f1..993ee46b32f3668dc7b531cf18b9904b4783208f 100755 (executable)
@@ -204,8 +204,6 @@ with open(in_file, "r") as ins:
                                offsets += [size]
                                size += len(bytes)
 
-               print(offsets)
-
                ins.seek(0)
 
                for line in ins:
@@ -226,7 +224,11 @@ with open(in_file, "r") as ins:
                data += struct.pack('I', size)
                if title:
                        for f in title:
-                               data += bytearray.fromhex(f)
+                               tid = bytearray.fromhex(f) # Endianness.
+                               print([tid])
+                               tid.reverse()
+                               print([tid])
+                               data += tid
                if deps:
                        for f in deps:
                                data += pad_zero_r(bytearray.fromhex(f), 8)
index ad8297045b3018f843df78ac559d22055dfd2bae..70e183ae18a468a6ee7daf795d310bbb8afe4bd1 100644 (file)
 #define OP_TITLE  0x0A
 
 #ifdef LOADER
-  #define fprintf(a...)
-  #define abort(a...)
+  #define log(a) logstr(a)
+  #define abort(a) { logstr(a) ; svcBreak(USERBREAK_ASSERT) ; }
+#else
+  #define log(a) fprintf(stderr, a)
 #endif
 
 struct mode {
@@ -119,7 +121,7 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) {
                switch(*code) {
                        case OP_NOP:
                                if (debug)
-                                       fprintf(stderr, "nop\n");
+                                       log("nop\n");
                                code++;
                                test_was_false = 0;
                                break;
@@ -129,7 +131,7 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) {
                                code += 2;
 #else
                                if (debug)
-                                       fprintf(stderr, "rel\n");
+                                       log("rel\n");
                                code++;
                                if (!test_was_false)
                                        current_mode = &modes[*code];
@@ -141,15 +143,13 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) {
                                break;
                        case OP_FIND: // Find pattern.
                                if (debug)
-                                       fprintf(stderr, "find\n");
+                                       log("find\n");
                                code += 2;
                                if (!test_was_false) {
                                        offset = (uint32_t)memfind(current_mode->memory+offset, current_mode->size - offset, code, *(code-1));
                                        if ((uint8_t*)offset == NULL) {
                                                // Error. Abort.
                                                abort("Find opcode failed.\n");
-                                       } else if (debug) {
-                                               fprintf(stderr, "Match @ %x\n", offset);
                                        }
                                        offset = offset - (uint32_t)current_mode->memory;
                                } else {
@@ -159,7 +159,7 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) {
                                break;
                        case OP_BACK:
                                if (debug)
-                                       fprintf(stderr, "back\n");
+                                       log("back\n");
                                code++;
                                if (!test_was_false) {
                                        if (offset < *code) {
@@ -174,7 +174,7 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) {
                                break;
                        case OP_FWD:
                                if (debug)
-                                       fprintf(stderr, "fwd\n");
+                                       log("fwd\n");
                                code++;
                                if (!test_was_false) {
                                        offset += *code;
@@ -189,7 +189,7 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) {
                                break;
                        case OP_SET: // Set data.
                                if (debug)
-                                       fprintf(stderr, "set\n");
+                                       log("set\n");
                                code += 2;
                                if (!test_was_false)
                                        memcpy(current_mode->memory+offset, code, *(code-1));
@@ -200,24 +200,22 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) {
                                break;
                        case OP_TEST: // Test data.
                                if (debug)
-                                       fprintf(stderr, "test\n");
+                                       log("test\n");
                                code += 2;
                                if(memcmp(current_mode->memory+offset, code, *(code-1))) {
                                        test_was_false = 1;
                                        if (debug)
-                                               fprintf(stderr, "false\n");
+                                               log("false\n");
                                } else if (debug) {
-                                       fprintf(stderr, "true\n");
+                                       log("true\n");
                                }
                                code   += *(code-1);
                                break;
                        case OP_JMP: // Jump to offset.
                                if (debug)
-                                       fprintf(stderr, "jmp\n");
+                                       log("jmp\n");
                                code++;
                                if (!test_was_false) {
-                                       if (debug)
-                                               fprintf(stderr, "jmp to %hu,%hu\n", code[0], code[1]);
                                        code = bytecode + code[1] + ( code[0] * 0x100 );
                                } else {
                                        code += 2;
@@ -226,7 +224,7 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) {
                                break;
                        case OP_REWIND:
                                if (debug)
-                                       fprintf(stderr, "rewind\n");
+                                       log("rewind\n");
                                code++;
                                if (!test_was_false)
                                        offset = 0;
@@ -235,7 +233,7 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) {
                                break;
                        case OP_AND:
                                if (debug)
-                                       fprintf(stderr, "and\n");
+                                       log("and\n");
                                code += 2;
                                if (!test_was_false) {
                                        for(i=0; i < *(code-1); i++) {
@@ -249,9 +247,10 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) {
                                break;
                        case OP_TITLE:
                                if (debug)
-                                       fprintf(stderr, "title\n");
+                                       log("title\n");
                                // FIXME - NYI
                        default:
+#ifndef LOADER
                                // Panic; not proper opcode.
                                fprintf(stderr, "Invalid opcode. State:\n"
                                                                "  Relative:  %u\n"
@@ -268,6 +267,7 @@ int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) {
                                                                code - bytecode,
                                                                code,
                                                                *code);
+#endif
                                abort("Halting startup.\n");
                                break;
                }
@@ -281,24 +281,97 @@ int execb(char* filename, uint64_t tid, uint8_t* search_mem, uint32_t search_len
 #else
 int execb(char* filename) {
 #endif
-       uint8_t* patch_mem;
        uint32_t patch_len;
        struct system_patch* patch;
 #ifdef LOADER
-       // Loader can use actual allocation functions, so this isn't as much of an issue
+       log("  check ");
+       log(filename);
+       log("\n");
+
+       uint8_t  patch_dat2[MAX_PATCHSIZE];
+       uint8_t *patch_dat = patch_dat2;
+
+       patch = (struct system_patch*)patch_dat;
+
+       Handle file;
+       u32 total;
+
+    // Open file.
+    if (!R_SUCCEEDED(fileOpen(&file, ARCHIVE_SDMC, filename, FS_OPEN_READ))) {
+        // Failed to open.
+        return 1;
+    }
+
+       u64 file_size;
+
+       if (!R_SUCCEEDED(FSFILE_GetSize(file, &file_size))) {
+        FSFILE_Close(file); // Read to memory.
+
+               return 1;
+       }
+
+       if (file_size > MAX_PATCHSIZE) {
+               log("  too large (please report)\n");
+
+        FSFILE_Close(file); // Read to memory.
+
+               return 1;
+       }
+
+    // Read file.
+    if (!R_SUCCEEDED(FSFILE_Read(file, &total, 0, patch_dat, file_size))) {
+        FSFILE_Close(file); // Read to memory.
+
+        // Failed to read.
+        return 1;
+    }
+
+    FSFILE_Close(file); // Done reading in.
 
        // Set memory.
        modes[18].memory = search_mem;
        modes[18].size   = search_len;
 
-       // Load patch. We need memory, so...
-       // svcControlMemory(&tmp, __loader_prog_heap, 0x0, __ctru_heap_size, MEMOP_ALLOC, MEMPERM_READ | MEMPERM_WRITE);
-
        // Check magic.
+       if (memcmp(patch->magic, "AIDA", 4)) {
+               log("  magic wrong\n");
+
+               return 1; // Incorrect patch magic.
+       }
 
        // Check TID supported.
+       if (patch->titles == 0) {
+               return 0; // Not an error - this patch isn't meant for us.
+       }
+
+       log("  checking tid\n");
+
+       uint8_t* title_buf = patch_dat + sizeof(struct system_patch);
+
+       int apply = 0;
 
+       for(uint32_t i=0; i < patch->titles; i++, title_buf += 8) {
+               if(!memcmp(title_buf, (uint8_t*)&tid, 8)) {
+                       // Applicable patch found.
+                       log("  applicable\n");
+                       apply = 1;
+                       break;
+               }
+       }
+
+       if (!apply) {
+               // Not meant for us. Not an error, though.
+               return 0;
+       }
+
+       // Patch is relevant to us, so we'll apply it.
+
+       log("  exec\n");
+
+       uint8_t* patch_mem = (uint8_t*)patch + sizeof(struct system_patch) + (patch->depends * 8) + (patch->titles * 8);
+       patch_len = patch->size;
 #else
+       uint8_t* patch_mem;
        // Read patch to scrap memory.
 
        FILE* f = fopen(filename, "r");
@@ -325,5 +398,5 @@ int execb(char* filename) {
        patch_mem = (uint8_t*)patch + sizeof(struct system_patch) + (patch->depends * 8) + (patch->titles * 8);
        patch_len = patch->size;
 #endif
-       return exec_bytecode(patch_mem, patch_len, 0);
+       return exec_bytecode(patch_mem, patch_len, 1);
 }