REVISION := r$(shell git rev-list --count HEAD):$(shell git rev-parse HEAD | head -c8)
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
-CFLAGS := -MMD -MP -Wall -Wextra -Werror -fno-omit-frame-pointer -Os $(ASFLAGS) -fno-builtin -std=c11 -DVERSION=\"$(REVISION)\"
+CFLAGS := -MMD -MP -Wall -Wextra -Werror -fno-omit-frame-pointer -Os $(ASFLAGS) -fno-builtin -std=c11 -DVERSION=\"$(REVISION)\" -DBUFFER=1
FLAGS := dir_out=$(abspath $(dir_out)) --no-print-directory
LDFLAGS := -nostdlib -Wl,-z,defs -lgcc -Wl,-Map,$(dir_build)/link.map
$(call rwildcard, $(dir_source), *.s *.c)))
.PHONY: all
-all: a9lh external
+all: a9lh patch external
.PHONY: full
full: host/langemu.conf all
external:
make -C external
+.PHONY: patch
+patch:
+ make -C patch
+
.PHONY: a9lh
a9lh: $(dir_out)/arm9loaderhax.bin
clean:
rm -f host/langemu.conf
make -C external clean
+ make -C patch clean
rm -rf $(dir_out) $(dir_build)
.PHONY: $(dir_out)/arm9loaderhax.bin
Pattern to test.
jmp <offset> : 3 bytes : opcode 0x07
- Jumps to the Nth instruction within the bytecode, and
+ Jumps to offset instruction within the bytecode, and
resumes execution from there.
+ Note that the assembler should be passed the number of instrcution
+ and will automatically calculate the offset needed.
+
<offset> : 2 bytes
- Index to jump to.
+ Offset to jump to.
rewind : 1 byte : opcode 0x08
Resets the location to the beginning of the space we're working off.
Cloning / Compilation
--------------------------
-Okay, first thing's first. I can't support compiling on Windows. Use Linux. The repo abuses symbolic links, relies on certain software being present which isn't with devkitPro, and has host tools which are untested on Windows and require a native gcc (as in, mingw only.)
+Okay, first thing's first. I can't support compiling on Windows. Use Linux. The repo abuses symbolic links, relies on certain software being present which isn't with devkitPro, and has host tools which are untested on Windows and require a native gcc (as in, mingw only.) Therefore, do NOT attempt to use windows to compile this. No, I will not port the build scripts to Windows. If you want to fix it without invasive changes, be my guest and make a PR. If I deem the maintenance cost too high, I'll tell you.
-If you want to fix windows builds, be my guest. I'll merge it so long as it A) doesn't break my machine's builds and B) uses mingw/cygwin as the native compiler. No msvcisms will be allowed on my watch.
+It may or may not compile with an OSX based cross compiler. I dunno.
You'll need the following to compile:
* git
+ * python2
* gcc (as in, host gcc)
- * arm-none-eabi-gcc (as in, devkitarm OR baremetal gcc (the latter isn't well tested, but may work)
- * a brain (hard requirement)
+ * arm-none-eabi-gcc (as in, devkitarm OR baremetal gcc (the latter isn't well tested, but may work. Compiling devkitPro using https://github.com/devkitPro/buildscripts is highly recommended.)
+ * bash (as /bin/bash)
To clone: use `git clone --recursive`. Some parts of this CFW are submodules.
-Things I won't implement
+Things I won't implement (for a number of reasons)
==========================
* Memekey Support.
* Gateway launcher dat
-Screw off. Need I explain why? Do it yourself. No support will be offered to gateway users. You're paying for a piracy tool. Seriously, why?
+Screw off. Do it yourself. No support will be offered to gateway users. You're paying for a piracy tool. Not to mention, I only integrate code I'm capable of testing safely, so this won't ever be a part of corbenik.
* 3dsx
-Get a9lh. Seriously. You might be able to use Brahma, but hell if I know. a9lh is the only supported method of running this, and no 3dsx launcher will be provided.
+You might be able to use Brahma, but hell if I know. Either way, I'm not going to attempt to get stuff on menuhax since there's limits on version now. I recommend any menuhax users get a9lh.
Not bugs
=========
* CETK decryption
-No, I can't fix this on a9lh. Here's how to do it; boot another CFW, go into system settings, then boot corbenik. You'll get the keys you need. This works with Cakes as well. After this, you'll never need a key again.
-
-Another thing to know is only NATIVE_FIRM is required to boot, so you can boot Corbenik without AGB and TWL suceeding, reboot from settings and they'll decrypt if the CETK is there.
-
+This has been removed from the FIRM decryptor, since it's unreliable on a9lh. I may re-add it someday.
data += struct.pack('I', len(title))
data += struct.pack('I', len(deps))
data += struct.pack('I', size)
- for f in title:
- data += bytearray.fromhex(f)
- for f in deps:
- data += pad_zero_r(bytearray.fromhex(f), 8)
+ if title:
+ for f in title:
+ data += bytearray.fromhex(f)
+ if deps:
+ for f in deps:
+ data += pad_zero_r(bytearray.fromhex(f), 8)
data += bytecode
writ.write(data)
.PHONY: all
all: $(patsubst %.pco, %.vco, $(wildcard *.pco))
+ mkdir -p ../out/corbenik/bin
+ cp *.vco ../out/corbenik/bin/
%.vco: %.pco
../host/bytecode_asm.py $< $@
# Pattern 2.
find b5224d0c
+back 01
set 00207047
// 243
// patch.c
-#define FCRAM_PATCHBIN_EXEC_LOC (FCRAM_START + FCRAM_SPACING * 4)
+#define FCRAM_PATCH_LOC (FCRAM_START + FCRAM_SPACING * 4)
// 244
// Throwaway temporary space. Don't expect it to stay sane.
--- /dev/null
+#include <stdint.h>
+#include "std/unused.h"
+#include "std/memory.h"
+#include "firm/firm.h"
+#include "config.h"
+#include "common.h"
+
+#define OP_NOP 0x00
+#define OP_REL 0x01
+#define OP_FIND 0x02
+#define OP_BACK 0x03
+#define OP_FWD 0x04
+#define OP_SET 0x05
+#define OP_TEST 0x06
+#define OP_JMP 0x07
+#define OP_REWIND 0x08
+#define OP_AND 0x09
+#define OP_TITLE 0x0A
+
+struct mode {
+ uint8_t* memory;
+ uint32_t size;
+};
+
+struct mode modes[19];
+int init_bytecode = 0;
+
+int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug) {
+ if (!init_bytecode) {
+ modes[0].memory = (uint8_t*)firm_loc;
+ modes[0].size = FCRAM_SPACING; // NATIVE_FIRM
+
+ modes[1].memory = (uint8_t*)agb_firm_loc;
+ modes[1].size = FCRAM_SPACING; // AGB_FIRM
+
+ modes[2].memory = (uint8_t*)twl_firm_loc;
+ modes[2].size = FCRAM_SPACING; // TWL_FIRM
+
+ // NATIVE_FIRM Process9 (This is also the default mode.)
+ modes[3].memory = (uint8_t*)firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset;
+ modes[3].size = firm_p9_exefs->fileHeaders[0].size;
+ // AGB_FIRM Process9
+ modes[4].memory = (uint8_t*)agb_firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset;
+ modes[4].size = firm_p9_exefs->fileHeaders[0].size;
+ // TWL_FIRM Process9
+ modes[5].memory = (uint8_t*)twl_firm_p9_exefs + sizeof(exefs_h) + firm_p9_exefs->fileHeaders[0].offset;
+ modes[5].size = firm_p9_exefs->fileHeaders[0].size;
+
+ // NATIVE_FIRM Sect 0
+ modes[6].memory = (uint8_t*)&firm_loc->section[0] + firm_loc->section[0].offset;
+ modes[6].size = firm_loc->section[0].size;
+ // NATIVE_FIRM Sect 1
+ modes[7].memory = (uint8_t*)&firm_loc->section[1] + firm_loc->section[1].offset;
+ modes[7].size = firm_loc->section[1].size;
+ // NATIVE_FIRM Sect 2
+ modes[8].memory = (uint8_t*)&firm_loc->section[2] + firm_loc->section[2].offset;
+ modes[8].size = firm_loc->section[2].size;
+ // NATIVE_FIRM Sect 3
+ modes[9].memory = (uint8_t*)&firm_loc->section[3] + firm_loc->section[3].offset;
+ modes[9].size = firm_loc->section[3].size;
+
+ // AGB_FIRM Sect 0
+ modes[10].memory = (uint8_t*)&agb_firm_loc->section[0] + agb_firm_loc->section[0].offset;
+ modes[10].size = agb_firm_loc->section[0].size;
+ // AGB_FIRM Sect 1
+ modes[11].memory = (uint8_t*)&agb_firm_loc->section[1] + agb_firm_loc->section[1].offset;
+ modes[11].size = agb_firm_loc->section[1].size;
+ // AGB_FIRM Sect 2
+ modes[12].memory = (uint8_t*)&agb_firm_loc->section[2] + agb_firm_loc->section[2].offset;
+ modes[12].size = agb_firm_loc->section[2].size;
+ // AGB_FIRM Sect 3
+ modes[13].memory = (uint8_t*)&agb_firm_loc->section[3] + agb_firm_loc->section[3].offset;
+ modes[13].size = agb_firm_loc->section[3].size;
+
+ // TWL_FIRM Sect 0
+ modes[14].memory = (uint8_t*)&twl_firm_loc->section[0] + twl_firm_loc->section[0].offset;
+ modes[14].size = twl_firm_loc->section[0].size;
+ // TWL_FIRM Sect 1
+ modes[15].memory = (uint8_t*)&twl_firm_loc->section[1] + twl_firm_loc->section[1].offset;
+ modes[15].size = twl_firm_loc->section[1].size;
+ // TWL_FIRM Sect 2
+ modes[16].memory = (uint8_t*)&twl_firm_loc->section[2] + twl_firm_loc->section[2].offset;
+ modes[16].size = twl_firm_loc->section[2].size;
+ // TWL_FIRM Sect 3
+ modes[17].memory = (uint8_t*)&twl_firm_loc->section[3] + twl_firm_loc->section[3].offset;
+ modes[17].size = twl_firm_loc->section[3].size;
+
+ // Loader (not valid in bootmode)
+ // modes[18] = { 0, 0 };
+
+ init_bytecode = 1;
+ }
+
+ struct mode* current_mode = &modes[3];
+ uint32_t offset = 0;
+ uint8_t test_was_false = 0;
+
+ uint32_t set_mode = 0;
+
+ uint32_t i;
+
+ uint8_t* code = bytecode;
+ uint8_t* end = code + len;
+ while (code < end && code >= bytecode) {
+ switch(*code) {
+ case OP_NOP:
+ if (debug)
+ fprintf(stderr, "nop\n");
+ code++;
+ test_was_false = 0;
+ break;
+ case OP_REL: // Change relativity.
+ if (debug)
+ fprintf(stderr, "rel\n");
+ code++;
+ if (!test_was_false)
+ current_mode = &modes[*code];
+ else
+ test_was_false = 0;
+ set_mode = *code;
+ code++;
+ break;
+ case OP_FIND: // Find pattern.
+ if (debug)
+ fprintf(stderr, "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 {
+ test_was_false = 0;
+ }
+ code += *(code-1);
+ break;
+ case OP_BACK:
+ if (debug)
+ fprintf(stderr, "back\n");
+ code++;
+ if (!test_was_false) {
+ if (offset < *code) {
+ // Went out of bounds. Error.
+ abort("Back underflowed.\n");
+ }
+ offset -= *code;
+ } else {
+ test_was_false = 0;
+ }
+ code++;
+ break;
+ case OP_FWD:
+ if (debug)
+ fprintf(stderr, "fwd\n");
+ code++;
+ if (!test_was_false) {
+ offset += *code;
+ if (offset >= current_mode->size) {
+ // Went out of bounds. Error.
+ abort("Fwd overflowed.\n");
+ }
+ } else {
+ test_was_false = 0;
+ }
+ code++;
+ break;
+ case OP_SET: // Set data.
+ if (debug)
+ fprintf(stderr, "set\n");
+ code += 2;
+ if (!test_was_false)
+ memcpy(current_mode->memory+offset, code, *(code-1));
+ else
+ test_was_false = 0;
+ offset += *(code-1);
+ code += *(code-1);
+ break;
+ case OP_TEST: // Test data.
+ if (debug)
+ fprintf(stderr, "test\n");
+ code += 2;
+ if(memcmp(current_mode->memory+offset, code, *(code-1))) {
+ test_was_false = 1;
+ }
+ offset += *(code-1);
+ code += *(code-1);
+ break;
+ case OP_JMP: // Jump to offset.
+ if (debug)
+ fprintf(stderr, "jmp\n");
+ code++;
+ if (!test_was_false)
+ code = bytecode + *((uint16_t*)code);
+ else
+ test_was_false = 0;
+ break;
+ case OP_REWIND:
+ if (debug)
+ fprintf(stderr, "rewind\n");
+ code++;
+ if (!test_was_false)
+ offset = 0;
+ else
+ test_was_false = 0;
+ break;
+ case OP_AND:
+ if (debug)
+ fprintf(stderr, "and\n");
+ code += 2;
+ if (!test_was_false) {
+ for(i=0; i < *(code-1); i++) {
+ *(current_mode->memory + offset) &= code[i];
+ }
+ offset += *(code-1);
+ } else {
+ test_was_false = 0;
+ }
+ code += *(code-1);
+ break;
+ case OP_TITLE:
+ if (debug)
+ fprintf(stderr, "title\n");
+ // FIXME - NYI
+ default:
+ // Panic; not proper opcode.
+ fprintf(stderr, "Invalid opcode. State:\n"
+ " Relative: %u\n"
+ " Actual: %x:%u\n"
+ " Memory: %x\n"
+ " Actual: %x\n"
+ " Code Loc: %x\n"
+ " Actual: %x\n"
+ " Opcode: %u\n",
+ set_mode,
+ current_mode->memory, current_mode->size,
+ offset,
+ current_mode->memory + offset,
+ code - bytecode,
+ code,
+ *code);
+ abort("Halting startup.\n");
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int execb(char* filename) {
+ FILE* f = fopen(filename, "r");
+ size_t len = fsize(f);
+ fread((uint8_t*)FCRAM_PATCH_LOC, 1, len, f);
+ fclose(f);
+
+ struct system_patch* patch = (struct system_patch*)FCRAM_PATCH_LOC;
+ fprintf(stderr, "Name: %s\nDesc: %s\n", patch->name, patch->desc);
+ uint8_t* patch_mem = (uint8_t*)patch + sizeof(struct system_patch) + (patch->depends * 8) + (patch->titles * 8);
+ uint32_t patch_len = patch->size;
+
+ return exec_bytecode(patch_mem, patch_len, 1);
+}
--- /dev/null
+#ifndef __INTERP_H
+#define __INTERP_H
+
+uint8_t* execb(char* filename);
+int exec_bytecode(uint8_t* bytecode, uint32_t len, int debug);
+
+#endif
#include "../firm/fcram.h"
#include "../config.h"
#include "../common.h"
+#include "../interp.h"
exefs_h* get_firm_proc9_exefs();
exefs_h* get_twl_proc9_exefs();
PATCH(signatures)
{
-
+/*
// Look for signature checks
uint8_t pat1[] = { 0xC0, 0x1C, 0x76, 0xE7 };
memcpy(off2, sigpatch, 4);
fprintf(stderr, "Signature patch succeded.\n");
+*/
+ execb(PATH_PATCHES "/sig.vco");
return 0;
}
"/slot0x11key96.bin" // Hey, your perrogative, buddy. I like cleaned up
// paths.
+#define PATCH_FLAG_REQUIRE (1 << 0) // Force enable patch unless 'Unsafe Options' is checked.
+#define PATCH_FLAG_DEVMODE (1 << 1) // Require 'Developer Options' to be checked.
+#define PATCH_FLAG_NOABORT (1 << 2) // Don't abort on error.
+
// Structure of a patch file.
struct system_patch
{
char magic[4]; // "AIDA" for shits and giggles and because we like .hack.
- uint32_t version; // Version of the patch itself.
+ uint8_t version; // Version of the patch itself.
char name[64]; // User-readable name for patch in menu.
char desc[256]; // User-readable description for patch in menu.
uint64_t uuid; // Unique ID for patch. Each unique patch should provide
// a unique ID.
- uint8_t flags; // Extra flags for patch.
-
- #define PATCH_FLAG_REQUIRE (1 << 0) // Force enable patch unless 'Unsafe Options' is checked.
- #define PATCH_FLAG_DEVMODE (1 << 1) // Require 'Developer Options' to be checked.
- #define PATCH_FLAG_NOABORT (1 << 2) // Don't abort on error.
+ uint32_t flags; // Extra flags for patch.
- uint32_t titles; // What title this patch is intended for. Certain values are
- // specially handled.
+ uint32_t titles; // How many titles this patch should be applied to (listed later)
uint32_t depends; // How many deps there are.
#include "draw.h"
+int menu_poweroff();
+uint32_t wait_key();
+
#define abort(x...) \
{ \
- fprintf(stderr, x); \
- fumount(); \
- while (1) \
- ; \
+ fprintf(stderr, x); \
+ wait_key(); \
+ menu_poweroff(); \
}
#endif
memset(&colorbuf[(height - 1) * width], 0, width);
clear_disp(buf); // Clear screen.
+
+ cursor_y[0]--;
#else
clear_disp(buf);
cursor_x[0] = 0;
memmove(&screen[x * col + one_c], &screen[x * col + one_c], col - one_c);
} */
#endif
- cursor_y[0]--;
}
switch (c) {