From: chaoskagami Date: Thu, 28 Apr 2016 19:53:16 +0000 (-0400) Subject: stdlib work X-Git-Tag: stable-1~85 X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=f26564b120282c63cfa12f93af1c1f60382659fc;p=corbenik%2Fcorbenik.git stdlib work --- diff --git a/Makefile b/Makefile index f0a7196..2579ad1 100644 --- a/Makefile +++ b/Makefile @@ -17,9 +17,9 @@ dir_out := out REVISION := $(shell git rev-list --count HEAD) ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te -CFLAGS := -Wall -Wextra -MMD -MP -O2 -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -DVERSION=\"r$(REVISION)\" -FLAGS := dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) --no-print-directory -LDFLAGS := -nostdlib -lgcc +CFLAGS := -Wall -Wextra -Os $(ASFLAGS) -fno-builtin -std=c11 -DVERSION=\"r$(REVISION)\" +FLAGS := dir_out=$(abspath $(dir_out)) --no-print-directory +LDFLAGS := -nostdlib -Wl,-z,defs -lgcc objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ diff --git a/doc/CODE_ORIGIN.md b/doc/CODE_ORIGIN.md new file mode 100644 index 0000000..0aa1c28 --- /dev/null +++ b/doc/CODE_ORIGIN.md @@ -0,0 +1,5 @@ +While most everything in this repo is original, some parts are derived from existing software, and I make the best effort to document what is derivative in the interest of giving proper credits: + +src/firm - Firmware decryptor originally from CakesFW (http://github.com/mid-kid/CakesForeveryWan) +src/fatfs - FatFS - http://elm-chan.org/fsw/ff/00index_e.html . This version originates from Decrypt9's repo. +src/std - Work was originally based on memfuncs.c and memory.c from Cakes and ReiNand, but contains near none of the original code now. diff --git a/doc/STDLIB.md b/doc/STDLIB.md new file mode 100644 index 0000000..f8197d3 --- /dev/null +++ b/doc/STDLIB.md @@ -0,0 +1,16 @@ +The stdlib/ directory is a self-contained, mostly conformant implementation of the C Standard Library for 3DS in ARM9 code. It supports a good chunk of standard functions and interfaces which follow: + +FILE* fopen(const char* name, const char* mode) + + Opens a file @name@ with access mode @mode@ and returns an opaque FILE pointer. + +size_t fread(void* buf, size_t size, size_t elem, FILE* handle) + + Reads @elem@ elements of size @size@ from the file @handle@, storing read data to @buf@. + +size_t fread(void* buf, size_t size, size_t elem, FILE* handle) + + Writes @elem@ elements of size @size@ to the file @handle@, reading data to write from @buf@. + +void fseek(FILE* file, ); + diff --git a/linker.ld b/linker.ld index d57403d..51bd054 100644 --- a/linker.ld +++ b/linker.ld @@ -1,11 +1,53 @@ +/* This memory map is mainly to assist in doing stuff in code. +MEMORY +{ + INSTRUCTION_TCM (rw) : ORIGIN = 0x00000000, LENGTH = 0x08000000 + ARM_INTERNAL (rw) : ORIGIN = 0x08000000, LENGTH = 0x00100000 + NEW_INTERNAL (rw) : ORIGIN = 0x08100000, LENGTH = 0x00080000 + IO_MEMORY (rw) : ORIGIN = 0x10000000, LENGTH = 0x08000000 + VRAM (rw) : ORIGIN = 0x18000000, LENGTH = 0x00600000 + DSP_MEMORY (rw) : ORIGIN = 0x1FF00000, LENGTH = 0x00080000 + AXI_WRAM (rw) : ORIGIN = 0x1FF80000, LENGTH = 0x00080000 + FCRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x08000000 + NEW_FCRAM (rwx) : ORIGIN = 0x28000000, LENGTH = 0x08000000 + DATA_TCM (rw) : ORIGIN = 0xFFF00000, LENGTH = 0x00004000 + BOOTROM (rw) : ORIGIN = 0xFFFF0000, LENGTH = 0x00010000 +} */ + ENTRY(_start) SECTIONS { . = 0x23F00000; - .text.start : { *(.text.start) } - .text : { *(.text) } - .data : { *(.data) } - .bss : { *(.bss COMMON) } - .rodata : { *(.rodata) } + + START_SECTION = .; + .text.start : { + *(.text.start) + } + START_SECTION_END = .; + + TEXT_SECTION = .; + .text : { + *(.text) + } + TEXT_SECTION_END = .; + + DATA_SECTION = .; + .data : { + *(.data) + } + DATA_SECTION_END = .; + + BSS_SECTION = .; + .bss : { + *(.bss COMMON) + } + BSS_SECTION_END = .; + + RODATA_SECTION = .; + .rodata : { + *(.rodata) + } + RODATA_SECTION_END = .; + . = ALIGN(4); } diff --git a/source/common.h b/source/common.h index 7f41f50..f58b083 100644 --- a/source/common.h +++ b/source/common.h @@ -6,6 +6,7 @@ #include "std/font.h" #include "std/fs.h" #include "std/memory.h" +#include "std/abort.h" #include "firm/fcram.h" #include "firm/crypto.h" diff --git a/source/config.c b/source/config.c index 161d77b..d4e8eaa 100644 --- a/source/config.c +++ b/source/config.c @@ -1,6 +1,6 @@ #include "common.h" -FILE conf_handle; +FILE* conf_handle; void regenerate_config() { f_mkdir(PATH_CFW); @@ -11,33 +11,35 @@ void regenerate_config() { f_mkdir(PATH_KEYS); f_mkdir(PATH_EXEFS); - cprintf(BOTTOM_SCREEN, "Created directory structure.\n"); + fprintf(BOTTOM_SCREEN, "Created directory structure.\n"); memset(&config, 0, sizeof(config)); memcpy(&(config.magic), CONFIG_MAGIC, 4); config.config_ver = config_version; - fopen(&conf_handle, PATH_CONFIG, "w"); - fwrite(&config, 1, sizeof(config), &conf_handle); - fclose(&conf_handle); + if(!(conf_handle = fopen(PATH_CONFIG, "w"))) + abort("Failed to open config for write?\n"); - cprintf(BOTTOM_SCREEN, "Config file written.\n"); + fwrite(&config, 1, sizeof(config), conf_handle); + fclose(conf_handle); + + fprintf(BOTTOM_SCREEN, "Config file written.\n"); } void load_config() { // Zero on success. - if (fopen(&conf_handle, PATH_CONFIG, "r")) { - cprintf(BOTTOM_SCREEN, "Config file is missing:\n" + if (!(conf_handle = fopen(PATH_CONFIG, "r"))) { + fprintf(BOTTOM_SCREEN, "Config file is missing:\n" " %s\n" "Will create it with defaults.\n", PATH_CONFIG); regenerate_config(); } else { - fread(&config, 1, sizeof(config), &conf_handle); - fclose(&conf_handle); + fread(&config, 1, sizeof(config), conf_handle); + fclose(conf_handle); if (memcmp(&(config.magic), CONFIG_MAGIC, 4)) { - cprintf(BOTTOM_SCREEN, "Config file at:\n" + fprintf(BOTTOM_SCREEN, "Config file at:\n" " %s\n" "has incorrect magic:\n" " '%c%c%c%c'\n" @@ -49,7 +51,7 @@ void load_config() { } if (config.config_ver < config_version) { - cprintf(BOTTOM_SCREEN, "Config file has outdated version:\n" + fprintf(BOTTOM_SCREEN, "Config file has outdated version:\n" " %s\n" "Regenerating with defaults.\n", PATH_CONFIG); @@ -58,6 +60,6 @@ void load_config() { } } - cprintf(BOTTOM_SCREEN, "Config file loaded.\n"); + fprintf(BOTTOM_SCREEN, "Config file loaded.\n"); } diff --git a/source/firm/firm.c b/source/firm/firm.c index 2f885d8..622e8d4 100644 --- a/source/firm/firm.c +++ b/source/firm/firm.c @@ -26,13 +26,14 @@ void slot0x11key96_init() uint8_t key[AES_BLOCK_SIZE]; if (read_file(key, PATH_SLOT0X11KEY96, AES_BLOCK_SIZE) || read_file(key, PATH_ALT_SLOT0X11KEY96, AES_BLOCK_SIZE)) { - // If we can't read the key, we assume it's not needed, and the firmware is the right version. - // Otherwise, we make sure the error message for decrypting arm9bin mentions this. + // Read key successfully. aes_setkey(0x11, key, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); // Tell boot_firm it needs to regenerate the keys. update_96_keys = 1; } + // If we can't read the key, we assume it's not needed, and the firmware is the right version. + // Otherwise, we make sure the error message for decrypting arm9bin mentions this. } int decrypt_cetk_key(void *key, const void *cetk) @@ -59,7 +60,7 @@ int decrypt_cetk_key(void *key, const void *cetk) // At i, there's 7 keys with 4 bytes padding between them. // We only need the 2nd. memcpy(common_key_y, i + AES_BLOCK_SIZE + 4, sizeof(common_key_y)); - cprintf(BOTTOM_SCREEN, "Found the common key Y\n"); + fprintf(BOTTOM_SCREEN, "Found the common key Y\n"); break; } @@ -74,7 +75,7 @@ int decrypt_cetk_key(void *key, const void *cetk) memcpy(iv, ticket->titleID, sizeof(ticket->titleID)); - cprintf(BOTTOM_SCREEN, "Decrypting key\n"); + fprintf(BOTTOM_SCREEN, "Decrypting key\n"); memcpy(key, ticket->titleKey, sizeof(ticket->titleKey)); aes(key, key, 1, iv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); @@ -87,7 +88,7 @@ int decrypt_firm_title(firm_h *dest, ncch_h *ncch, uint32_t *size, void *key) uint8_t exefs_key[16] = {0}; uint8_t exefs_iv[16] = {0}; - cprintf(BOTTOM_SCREEN, "Decrypting the NCCH\n"); + fprintf(BOTTOM_SCREEN, "Decrypting the NCCH\n"); aes_setkey(0x16, key, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); aes_use_keyslot(0x16); aes(ncch, ncch, *size / AES_BLOCK_SIZE, firm_iv, AES_CBC_DECRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); @@ -102,7 +103,7 @@ int decrypt_firm_title(firm_h *dest, ncch_h *ncch, uint32_t *size, void *key) exefs_h *exefs = (exefs_h *)((void *)ncch + ncch->exeFSOffset * MEDIA_UNITS); uint32_t exefs_size = ncch->exeFSSize * MEDIA_UNITS; - cprintf(BOTTOM_SCREEN, "Decrypting the exefs\n"); + fprintf(BOTTOM_SCREEN, "Decrypting the exefs\n"); aes_setkey(0x2C, exefs_key, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_use_keyslot(0x2C); aes(exefs, exefs, exefs_size / AES_BLOCK_SIZE, exefs_iv, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); @@ -123,7 +124,7 @@ int decrypt_firm_title(firm_h *dest, ncch_h *ncch, uint32_t *size, void *key) int decrypt_arm9bin(arm9bin_h *header, uint64_t firm_title) { uint8_t slot = 0x15; - cprintf(BOTTOM_SCREEN, "Decrypting ARM9 FIRM binary\n"); + fprintf(BOTTOM_SCREEN, "Decrypting ARM9 FIRM binary\n"); // if (firm_title == NATIVE_FIRM_TITLEID && version > 0x0F) { if (firm_title == NATIVE_FIRM_TITLEID) { @@ -158,28 +159,28 @@ int decrypt_firm(firm_h *dest, char *path_firmkey, char *path_cetk, uint32_t *si // Firmware is likely encrypted. Decrypt. if (!read_file(firm_key, path_firmkey, AES_BLOCK_SIZE)) { - cprintf(BOTTOM_SCREEN, "Failed to load FIRM key,\n" + fprintf(BOTTOM_SCREEN, "Failed to load FIRM key,\n" " Attempting to generate with CETK.\n"); if (!read_file(fcram_temp, path_cetk, FCRAM_SPACING)) { - cprintf(BOTTOM_SCREEN, "Failed to load CETK\n"); + fprintf(BOTTOM_SCREEN, "Failed to load CETK\n"); return 1; } - cprintf(BOTTOM_SCREEN, "Loaded CETK\n"); + fprintf(BOTTOM_SCREEN, "Loaded CETK\n"); if (decrypt_cetk_key(firm_key, fcram_temp) != 0) { - cprintf(BOTTOM_SCREEN, "Failed to decrypt the CETK\n"); + fprintf(BOTTOM_SCREEN, "Failed to decrypt the CETK\n"); return 1; } - cprintf(BOTTOM_SCREEN, "Saving FIRM key for future use\n"); + fprintf(BOTTOM_SCREEN, "Saving FIRM key for future use\n"); write_file(firm_key, path_firmkey, AES_BLOCK_SIZE); } else { - cprintf(BOTTOM_SCREEN, "Loaded FIRM key\n"); + fprintf(BOTTOM_SCREEN, "Loaded FIRM key\n"); } - cprintf(BOTTOM_SCREEN, "Decrypting FIRM\n"); + fprintf(BOTTOM_SCREEN, "Decrypting FIRM\n"); if (decrypt_firm_title(dest, (void *)dest, size, firm_key) != 0) { - cprintf(BOTTOM_SCREEN, "Failed to decrypt the firmware\n"); + fprintf(BOTTOM_SCREEN, "Failed to decrypt the firmware\n"); return 1; } return 0; @@ -190,11 +191,11 @@ int load_firm(firm_h *dest, char *path, char *path_firmkey, char *path_cetk, uin int firmware_changed = 0; if (read_file(dest, path, *size)) { - cprintf(BOTTOM_SCREEN, "Failed to read FIRM from SD\n"); + fprintf(BOTTOM_SCREEN, "Failed to read FIRM from SD\n"); // Only whine about this if it's NATIVE_FIRM, which is important. if (firm_title == NATIVE_FIRM_TITLEID) { - cprintf(BOTTOM_SCREEN, "Failed to load NATIVE_FIRM from:\n" + fprintf(BOTTOM_SCREEN, "Failed to load NATIVE_FIRM from:\n" " " PATH_NATIVE_F "\n" "This is fatal. Aborting.\n"); } @@ -208,14 +209,14 @@ int load_firm(firm_h *dest, char *path, char *path_firmkey, char *path_cetk, uin status = decrypt_firm(dest, path_firmkey, path_cetk, size, firm_title); if (status != 0) { if (firm_title == NATIVE_FIRM_TITLEID) { - cprintf(BOTTOM_SCREEN, "Failed to decrypt firmware.\n" + fprintf(BOTTOM_SCREEN, "Failed to decrypt firmware.\n" "This is fatal. Aborting.\n"); } goto exit_error; } firmware_changed = 1; // Decryption performed. } else { - cprintf(BOTTOM_SCREEN, "FIRM not encrypted\n"); + fprintf(BOTTOM_SCREEN, "FIRM not encrypted\n"); } // The N3DS firm has an additional encryption layer for ARM9 @@ -236,7 +237,7 @@ int load_firm(firm_h *dest, char *path, char *path_firmkey, char *path_cetk, uin if (arm9bin_iscrypt) { // Decrypt the arm9bin. if (decrypt_arm9bin((arm9bin_h *)((uintptr_t)dest + section->offset), firm_title)) { - cprintf(BOTTOM_SCREEN, "Couldn't decrypt ARM9 FIRM binary.\n" + fprintf(BOTTOM_SCREEN, "Couldn't decrypt ARM9 FIRM binary.\n" "Check if you have the needed key at:\n" " " PATH_SLOT0X11KEY96 "\n"); status = 1; @@ -244,7 +245,7 @@ int load_firm(firm_h *dest, char *path, char *path_firmkey, char *path_cetk, uin } firmware_changed = 1; // Decryption of arm9bin performed. } else { - cprintf(BOTTOM_SCREEN, "ARM9 FIRM binary not encrypted\n"); + fprintf(BOTTOM_SCREEN, "ARM9 FIRM binary not encrypted\n"); // if (firm_type == NATIVE_FIRM && firm_current->version > 0x0F) { slot0x11key96_init(); // This has to be loaded regardless, otherwise boot will fail. // } @@ -258,13 +259,13 @@ int load_firm(firm_h *dest, char *path, char *path_firmkey, char *path_cetk, uin // Save firmware.bin if decryption was done. if (firmware_changed) { - cprintf(BOTTOM_SCREEN, "Saving decrypted FIRM\n"); + fprintf(BOTTOM_SCREEN, "Saving decrypted FIRM\n"); write_file(dest, path, *size); } //if (firm_current->console == console_n3ds) { - cprintf(BOTTOM_SCREEN, "Fixing arm9 entrypoint\n"); + fprintf(BOTTOM_SCREEN, "Fixing arm9 entrypoint\n"); // Patch the entrypoint to skip arm9loader if (firm_title == NATIVE_FIRM_TITLEID) { @@ -310,7 +311,7 @@ void boot_firm() { *(uint8_t *)(keydata + 0xF) += 1; } - cprintf(BOTTOM_SCREEN, "Updated keyX keyslots\n"); + fprintf(BOTTOM_SCREEN, "Updated keyX keyslots\n"); } struct memory_header *memory = (void *)(memory_loc + 1); @@ -318,43 +319,43 @@ void boot_firm() { memcpy((void *)memory->location, memory + 1, memory->size); memory = (void *)((uintptr_t)(memory + 1) + memory->size); } - cprintf(BOTTOM_SCREEN, "Copied memory\n"); + fprintf(BOTTOM_SCREEN, "Copied memory\n"); for (firm_section_h *section = firm_loc->section; section < firm_loc->section + 4 && section->address != 0; section++) { memcpy((void *)section->address, (void *)firm_loc + section->offset, section->size); } - cprintf(BOTTOM_SCREEN, "Copied FIRM\n"); + fprintf(BOTTOM_SCREEN, "Copied FIRM\n"); *a11_entry = (uint32_t)disable_lcds; while (*a11_entry); // Make sure it jumped there correctly before changing it. *a11_entry = (uint32_t)firm_loc->a11Entry; - cprintf(BOTTOM_SCREEN, "Prepared arm11 entry, jumping to FIRM\n"); + fprintf(BOTTOM_SCREEN, "Prepared arm11 entry, jumping to FIRM\n"); ((void (*)())firm_loc->a9Entry)(); } int load_firms() { - cprintf(TOP_SCREEN, "[Loading FIRM]"); + fprintf(TOP_SCREEN, "[Loading FIRM]"); - cprintf(BOTTOM_SCREEN, "Loading NATIVE_FIRM\n"); + fprintf(BOTTOM_SCREEN, "Loading NATIVE_FIRM\n"); if (load_firm(firm_loc, PATH_NATIVE_F, PATH_NATIVE_FIRMKEY, PATH_NATIVE_CETK, &firm_size, NATIVE_FIRM_TITLEID) != 0) return 1; - cprintf(BOTTOM_SCREEN, "Loading TWL_FIRM\n"); + fprintf(BOTTOM_SCREEN, "Loading TWL_FIRM\n"); if(load_firm(twl_firm_loc, PATH_TWL_F, PATH_TWL_FIRMKEY, PATH_TWL_CETK, &twl_firm_size, TWL_FIRM_TITLEID)) - cprintf(BOTTOM_SCREEN, "TWL_FIRM failed to load.\n"); + fprintf(BOTTOM_SCREEN, "TWL_FIRM failed to load.\n"); - cprintf(BOTTOM_SCREEN, "Loading AGB_FIRM\n"); + fprintf(BOTTOM_SCREEN, "Loading AGB_FIRM\n"); if(load_firm(agb_firm_loc, PATH_AGB_F, PATH_AGB_FIRMKEY, PATH_AGB_CETK, &agb_firm_size, AGB_FIRM_TITLEID)) - cprintf(BOTTOM_SCREEN, "AGB_FIRM failed to load.\n"); + fprintf(BOTTOM_SCREEN, "AGB_FIRM failed to load.\n"); return 0; } void boot_cfw() { - cprintf(TOP_SCREEN, "[Patching]"); + fprintf(TOP_SCREEN, "[Patching]"); // if (patch_firm_all() != 0) // return; @@ -362,34 +363,34 @@ void boot_cfw() { // and either the patches have been modified, or the file doesn't exist. if ((save_firm || config.options[OPTION_AUTOBOOT]) && f_stat(PATH_NATIVE_P, NULL) != 0) { - cprintf(BOTTOM_SCREEN, "Saving patched NATIVE_FIRM\n"); + fprintf(BOTTOM_SCREEN, "Saving patched NATIVE_FIRM\n"); if (write_file(firm_loc, PATH_NATIVE_P, firm_size) != firm_size) { - cprintf(BOTTOM_SCREEN, "%pFailed to save patched FIRM.\nWriting SD failed.\nThis is fatal.\n", COLOR(RED, BLACK)); + fprintf(BOTTOM_SCREEN, "%pFailed to save patched FIRM.\nWriting SD failed.\nThis is fatal.\n", COLOR(RED, BLACK)); return; } } if ((save_firm || config.options[OPTION_AUTOBOOT]) && f_stat(PATH_MEMBIN, NULL) != 0) { - cprintf(BOTTOM_SCREEN, "Saving patched memory\n"); + fprintf(BOTTOM_SCREEN, "Saving patched memory\n"); if (write_file(memory_loc, PATH_MEMBIN, *memory_loc) != *memory_loc) { - cprintf(BOTTOM_SCREEN, "%pFailed to save the patched FIRM\nWriting SD failed.\n", COLOR(RED, BLACK)); + fprintf(BOTTOM_SCREEN, "%pFailed to save the patched FIRM\nWriting SD failed.\n", COLOR(RED, BLACK)); return; } } if (f_stat(PATH_TWL_P, NULL) != 0) { - cprintf(BOTTOM_SCREEN, "Saving patched TWL_FIRM\n"); + fprintf(BOTTOM_SCREEN, "Saving patched TWL_FIRM\n"); if (write_file(twl_firm_loc, PATH_TWL_P, twl_firm_size) != twl_firm_size) { - cprintf(BOTTOM_SCREEN, "%pFailed to save the patched FIRM\nWriting SD failed.\n", COLOR(RED, BLACK)); + fprintf(BOTTOM_SCREEN, "%pFailed to save the patched FIRM\nWriting SD failed.\n", COLOR(RED, BLACK)); return; } } if (f_stat(PATH_AGB_P, NULL) != 0) { - cprintf(BOTTOM_SCREEN, "Saving patched AGB_FIRM\n"); + fprintf(BOTTOM_SCREEN, "Saving patched AGB_FIRM\n"); if (write_file(agb_firm_loc, PATH_AGB_P, agb_firm_size) != agb_firm_size) { - cprintf(BOTTOM_SCREEN, "%pFailed to save the patched FIRM\nWriting SD failed.\n", COLOR(RED, BLACK)); + fprintf(BOTTOM_SCREEN, "%pFailed to save the patched FIRM\nWriting SD failed.\n", COLOR(RED, BLACK)); return; } } diff --git a/source/i2c.c b/source/i2c.c index fcaab9c..2053fbb 100644 --- a/source/i2c.c +++ b/source/i2c.c @@ -2,7 +2,7 @@ //----------------------------------------------------------------------------- -static const struct { uint8_t bus_id, reg_addr } dev_data[] = { +static const struct { uint8_t bus_id, reg_addr; } dev_data[] = { {0, 0x4A}, {0, 0x7A}, {0, 0x78}, {1, 0x4A}, {1, 0x78}, {1, 0x2C}, {1, 0x2E}, {1, 0x40}, {1, 0x44}, @@ -10,11 +10,11 @@ static const struct { uint8_t bus_id, reg_addr } dev_data[] = { {2, 0xA4}, {2, 0x9A}, {2, 0xA0}, }; -const uint8_t i2cGetDeviceBusId(uint8_t device_id) { +uint8_t i2cGetDeviceBusId(uint8_t device_id) { return dev_data[device_id].bus_id; } -const uint8_t i2cGetDeviceRegAddr(uint8_t device_id) { +uint8_t i2cGetDeviceRegAddr(uint8_t device_id) { return dev_data[device_id].reg_addr; } @@ -26,7 +26,7 @@ static volatile uint8_t* const reg_data_addrs[] = { (volatile uint8_t*)(I2C3_REG_OFF + I2C_REG_DATA), }; -volatile uint8_t* const i2cGetDataReg(uint8_t bus_id) { +volatile uint8_t* i2cGetDataReg(uint8_t bus_id) { return reg_data_addrs[bus_id]; } @@ -38,13 +38,13 @@ static volatile uint8_t* const reg_cnt_addrs[] = { (volatile uint8_t*)(I2C3_REG_OFF + I2C_REG_CNT), }; -volatile uint8_t* const i2cGetCntReg(uint8_t bus_id) { +volatile uint8_t* i2cGetCntReg(uint8_t bus_id) { return reg_cnt_addrs[bus_id]; } //----------------------------------------------------------------------------- -int i2cWaitBusy(uint8_t bus_id) { +void i2cWaitBusy(uint8_t bus_id) { while (*i2cGetCntReg(bus_id) & 0x80); } diff --git a/source/i2c.h b/source/i2c.h index 8620e4c..ebde4ac 100644 --- a/source/i2c.h +++ b/source/i2c.h @@ -15,13 +15,13 @@ #define I2C_DEV_GYRO 10 #define I2C_DEV_IR 13 -const uint8_t i2cGetDeviceBusId(uint8_t device_id); -const uint8_t i2cGetDeviceRegAddr(uint8_t device_id); +uint8_t i2cGetDeviceBusId(uint8_t device_id); +uint8_t i2cGetDeviceRegAddr(uint8_t device_id); -volatile uint8_t* const i2cGetDataReg(uint8_t bus_id); -volatile uint8_t* const i2cGetCntReg(uint8_t bus_id); +volatile uint8_t* i2cGetDataReg(uint8_t bus_id); +volatile uint8_t* i2cGetCntReg(uint8_t bus_id); -int i2cWaitBusy(uint8_t bus_id); +void i2cWaitBusy(uint8_t bus_id); int i2cGetResult(uint8_t bus_id); uint8_t i2cGetData(uint8_t bus_id); void i2cStop(uint8_t bus_id, uint8_t arg0); diff --git a/source/main.c b/source/main.c index 7239aa3..7d97e53 100644 --- a/source/main.c +++ b/source/main.c @@ -32,7 +32,7 @@ uint32_t wait_key() { } void header() { - cprintf(TOP_SCREEN, "%p[Corbenik - The Rebirth - %s]\n", COLOR(CYAN, BLACK), VERSION); + fprintf(stdout, "\x1b[33;40m[.corbenik//%s]\n", VERSION); } int menu_options() { return MENU_MAIN; } @@ -46,7 +46,7 @@ int menu_help() { header(); - cprintf(TOP_SCREEN, "Corbenik is a 3DS firmware patcher\n" + fprintf(stdout, "Corbenik is a 3DS firmware patcher\n" " commonly known as a CFW. It seeks to address\n" " some faults in other CFWs and is generally\n" " just another choice for users - but primarily\n" @@ -78,15 +78,19 @@ int menu_help() { } int menu_reset() { + fumount(); // Unmount SD. + // Reboot. - cprintf(BOTTOM_SCREEN, "Resetting system.\n"); + fprintf(BOTTOM_SCREEN, "Resetting system.\n"); i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); while(1); } int menu_poweroff() { + fumount(); // Unmount SD. + // Reboot. - cprintf(BOTTOM_SCREEN, "Powering off system.\n"); + fprintf(BOTTOM_SCREEN, "Powering off system.\n"); i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0); while(1); } @@ -95,13 +99,13 @@ int menu_main() { set_cursor(TOP_SCREEN, 0, 0); const char *list[] = { - "Options", - "Patches", - "Info", - "Help/Readme", - "Reset", - "Power off", - "Boot firmware" + "Options ", + "Patches ", + "Info ", + "Help/Readme ", + "Reset ", + "Power off ", + "Boot firmware " }; header(); @@ -110,10 +114,10 @@ int menu_main() { for(int i=0; i < menu_max; i++) { if (cursor_y == i) - cprintf(TOP_SCREEN, "%p>> ", COLOR(GREEN, BLACK)); + fprintf(TOP_SCREEN, "\x1b[42m>> "); else - cprintf(TOP_SCREEN, " "); - cprintf(TOP_SCREEN, "%s\n", list[i]); + fprintf(TOP_SCREEN, " "); + fprintf(TOP_SCREEN, "%s\n", list[i]); } uint32_t key = wait_key(); @@ -177,9 +181,9 @@ int menu_handler() { void main() { if (fmount()) { // Failed to mount SD. Bomb out. - cprintf(BOTTOM_SCREEN, "%pFailed to mount SD card.\n", COLOR(RED, BLACK)); + fprintf(BOTTOM_SCREEN, "%pFailed to mount SD card.\n", COLOR(RED, BLACK)); } else { - cprintf(BOTTOM_SCREEN, "Mounted SD card.\n"); + fprintf(BOTTOM_SCREEN, "Mounted SD card.\n"); } load_config(); // Load configuration. diff --git a/source/std/abort.h b/source/std/abort.h new file mode 100644 index 0000000..b672e82 --- /dev/null +++ b/source/std/abort.h @@ -0,0 +1,10 @@ +#ifndef __ABORT_H +#define __ABORT_H + +#define abort(x...) { \ + fprintf(2, x); \ + fumount(); \ + while(1); \ +} + +#endif diff --git a/source/std/draw.c b/source/std/draw.c index 2883962..0819167 100644 --- a/source/std/draw.c +++ b/source/std/draw.c @@ -5,6 +5,8 @@ #include #include "memory.h" #include "font.h" +#include "../fatfs/ff.h" +#include "fs.h" static unsigned int top_cursor_x = 0, top_cursor_y = 0; static unsigned int bottom_cursor_x = 0, bottom_cursor_y = 0; @@ -38,9 +40,9 @@ void clear_screen(uint8_t* screen) { uint32_t size = 0; char* buffer = 0; uint32_t buffer_size = 0; - if (screen == TOP_SCREEN) + if ((int)screen == TOP_SCREEN) screen = framebuffers->top_left; - else if (screen == BOTTOM_SCREEN) + else if ((int)screen == BOTTOM_SCREEN) screen = framebuffers->bottom; if(screen == framebuffers->top_left || @@ -121,80 +123,83 @@ void draw_character(uint8_t* screen, const char character, const unsigned int bu } } -void putc(int buf, unsigned char color, const int c) { - unsigned int width = 0; - unsigned int height = 0; - unsigned int size = 0; - unsigned int cursor_x; - unsigned int cursor_y; - char* colorbuf; - char* strbuf; - - if (buf == TOP_SCREEN) { - width = TEXT_TOP_WIDTH; - height = TEXT_TOP_HEIGHT; - size = TEXT_TOP_SIZE; - colorbuf = color_buffer_top; - strbuf = text_buffer_top; - cursor_x = top_cursor_x; - cursor_y = top_cursor_y; - } else if (buf == BOTTOM_SCREEN) { - width = TEXT_BOTTOM_WIDTH; - height = TEXT_BOTTOM_HEIGHT; - size = TEXT_BOTTOM_SIZE; - colorbuf = color_buffer_bottom; - strbuf = text_buffer_bottom; - cursor_x = bottom_cursor_x; - cursor_y = bottom_cursor_y; +void putc(void* buf, unsigned char color, const int c) { + if ((int)buf == stdout || (int)buf == stderr) { + unsigned int width = 0; + unsigned int height = 0; + unsigned int size = 0; + unsigned int cursor_x; + unsigned int cursor_y; + char* colorbuf; + char* strbuf; + + if ((int)buf == TOP_SCREEN) { + width = TEXT_TOP_WIDTH; + height = TEXT_TOP_HEIGHT; + size = TEXT_TOP_SIZE; + colorbuf = color_buffer_top; + strbuf = text_buffer_top; + cursor_x = top_cursor_x; + cursor_y = top_cursor_y; + } else if ((int)buf == BOTTOM_SCREEN) { + width = TEXT_BOTTOM_WIDTH; + height = TEXT_BOTTOM_HEIGHT; + size = TEXT_BOTTOM_SIZE; + colorbuf = color_buffer_bottom; + strbuf = text_buffer_bottom; + cursor_x = bottom_cursor_x; + cursor_y = bottom_cursor_y; + } + + unsigned int offset = width * cursor_y + cursor_x; + + if (offset >= size) { + // Scroll a line back. This involves memcpy. + // Yes, memcpy overwrites part of the buffer it is reading. + memcpy(strbuf, strbuf+width, size-width); + memcpy(colorbuf, colorbuf+width, size-width); + cursor_y -= 1; + offset = width * cursor_y + cursor_x; + } + + if (offset >= size) { + // So if we're being real, this won't ever happen. + return; + } + + switch(c) { + case '\n': + cursor_y++; // Increment line. + cursor_x = 0; + break; + case '\r': + cursor_x = 0; // Reset to beginning of line. + break; + default: + strbuf[offset] = c; + colorbuf[offset] = color; // White on black. + cursor_x++; + if (cursor_x >= width) { + cursor_y++; + cursor_x = 0; + } + break; + } + + if ((int)buf == TOP_SCREEN) { + top_cursor_x = cursor_x; + top_cursor_y = cursor_y; + } else if ((int)buf == BOTTOM_SCREEN) { + bottom_cursor_x = cursor_x; + bottom_cursor_y = cursor_y; + } } else { - return; // Invalid buffer. + // FILE*, not stdin or stdout. + fwrite(&c, 1, 1, (FILE*)buf); } - - unsigned int offset = width * cursor_y + cursor_x; - - if (offset >= size) { - // Scroll a line back. This involves memcpy. - // Yes, memcpy overwrites part of the buffer it is reading. - memcpy(strbuf, strbuf+width, size-width); - memcpy(colorbuf, colorbuf+width, size-width); - cursor_y -= 1; - offset = width * cursor_y + cursor_x; - } - - if (offset >= size) { - // So if we're being real, this won't ever happen. - return; - } - - switch(c) { - case '\n': - cursor_y++; // Increment line. - cursor_x = 0; - break; - case '\r': - cursor_x = 0; // Reset to beginning of line. - break; - default: - strbuf[offset] = c; - colorbuf[offset] = color; // White on black. - cursor_x++; - if (cursor_x >= width) { - cursor_y++; - cursor_x = 0; - } - break; - } - - if (buf == TOP_SCREEN) { - top_cursor_x = cursor_x; - top_cursor_y = cursor_y; - } else if (buf == BOTTOM_SCREEN) { - bottom_cursor_x = cursor_x; - bottom_cursor_y = cursor_y; - } } -void puts(int buf, unsigned char color, const char *string) { +void puts(void* buf, unsigned char color, const char *string) { char *ref = (char*)string; while(*ref != '\0') { @@ -203,10 +208,10 @@ void puts(int buf, unsigned char color, const char *string) { } } -void put_int(int channel, unsigned char color, int n) { - char conv[16], out[16]; - memset(conv, 0, 16); - memset(out, 0, 16); +void put_int64(void* channel, unsigned char color, int64_t n, int length) { + char conv[32], out[32]; + memset(conv, 0, 32); + memset(out, 0, 32); int i = 0, sign = 0; if (n < 0) { @@ -222,6 +227,9 @@ void put_int(int channel, unsigned char color, int n) { if (sign) conv[i++] = '-'; + if (length > 0) + out[length] = '\0'; + int len = strlen(conv); for(int i=0; i < len; i++) out[i] = conv[(len-1) - i]; @@ -229,16 +237,19 @@ void put_int(int channel, unsigned char color, int n) { puts(channel, color, out); } -void put_uint(int channel, unsigned char color, unsigned int n) { - char conv[16], out[16]; - memset(conv, 0, 16); - memset(out, 0, 16); +void put_uint64(void* channel, unsigned char color, uint64_t n, int length) { + char conv[32], out[32]; + memset(conv, 0, 32); + memset(out, 0, 32); int i = 0; do { conv[i++] = (n % 10) + '0'; } while((n /= 10) != 0); + if (length > 0) + out[length] = '\0'; + int len = strlen(conv); for(int i=0; i < len; i++) out[i] = conv[(len-1) - i]; @@ -246,8 +257,16 @@ void put_uint(int channel, unsigned char color, unsigned int n) { puts(channel, color, out); } -void cflush(int channel) { - if (channel == TOP_SCREEN) { +void put_uint(void* channel, unsigned char color, unsigned int n, int length) { + put_uint64(channel, color, n, length); +} + +void put_int(void* channel, unsigned char color, int n, int length) { + put_int64(channel, color, n, length); +} + +void fflush(void* channel) { + if ((int)channel == TOP_SCREEN) { for(int x=0; x < TEXT_TOP_WIDTH; x++) { for(int y=0; y < TEXT_TOP_HEIGHT; y++) { char c = text_buffer_top[y*TEXT_TOP_WIDTH+x]; @@ -256,7 +275,7 @@ void cflush(int channel) { draw_character(framebuffers->top_left, c, x, y, color_fg, color_bg); } } - } else if (channel == BOTTOM_SCREEN) { + } else if ((int)channel == BOTTOM_SCREEN) { for(int x=0; x < TEXT_BOTTOM_WIDTH; x++) { for(int y=0; y < TEXT_BOTTOM_HEIGHT; y++) { char c = text_buffer_bottom[y*TEXT_BOTTOM_WIDTH+x]; @@ -265,10 +284,12 @@ void cflush(int channel) { draw_character(framebuffers->bottom, c, x, y, color_fg, color_bg); } } + } else { + f_sync(&(((FILE*)channel)->handle)); // Sync to disk. } } -void cprintf(int channel, const char* format, ...) { +void fprintf(void* channel, const char* format, ...) { va_list ap; va_start( ap, format ); @@ -276,15 +297,63 @@ void cprintf(int channel, const char* format, ...) { unsigned char color = 0xf0; while(*ref != '\0') { - if(*ref == '%') { + if (*ref == 0x1B && *(++ref) == '[' && ( (int)channel == stdout || (int)channel == stderr) ) { +ansi_codes: + // Ansi escape code. + ++ref; + // [30-37] Set text color + if (*ref == '3') { + ++ref; + if(*ref >= '0' && *ref <= '7') { + // Valid FG color. + color &= 0x0f; // Remove fg color. + color |= (*ref - '0') << 4; + } + } + // [40-47] Set bg color + else if (*ref == '4') { + ++ref; + if(*ref >= '0' && *ref <= '7') { + // Valid BG color. + color &= 0xf0; // Remove bg color. + color |= *ref - '0'; + } + } + + ++ref; + + if (*ref == ';') { + goto ansi_codes; // Another code. + } + + // Loop until the character is somewhere 0x40 - 0x7E, which terminates an ANSI sequence + while(!(*ref >= 0x40 && *ref <= 0x7E)) ref++; + } else if (*ref == '%') { + int type_size = 0; + int length = -1; +check_format: // Format string. - ref++; + ++ref; switch(*ref) { case 'd': - put_int(channel, color, va_arg( ap, int )); + switch(type_size) { + case 2: + put_int64(channel, color, va_arg( ap, int64_t ), length); + break; + default: + put_int(channel, color, va_arg( ap, int ), length); + break; + } break; case 'u': - put_uint(channel, color, va_arg( ap, unsigned int )); + switch(type_size) { + case 2: + put_uint64(channel, color, va_arg( ap, uint64_t ), length); + break; + default: + put_uint(channel, color, va_arg( ap, unsigned int ), length); + break; + } break; case 's': puts(channel, color, va_arg( ap, char* )); @@ -298,17 +367,26 @@ void cprintf(int channel, const char* format, ...) { case '%': putc(channel, color, '%'); break; + case 'h': + goto check_format; // Integers get promoted. No point here. + case 'l': + ++type_size; + goto check_format; default: + if (*ref >= '0' && *ref <= '9') { + length = *ref - '0'; + goto check_format; + } break; } } else { putc(channel, color, *ref); } - ref++; + ++ref; } va_end( ap ); - cflush(channel); + fflush(channel); } diff --git a/source/std/draw.h b/source/std/draw.h index a79eb0b..be36d37 100644 --- a/source/std/draw.h +++ b/source/std/draw.h @@ -49,22 +49,30 @@ void clear_screens(); void draw_character(uint8_t* screen, const char character, const unsigned int pos_x, const unsigned int pos_y, const uint32_t color_fg, const uint32_t color_bg); #define TOP_SCREEN 0 -#define BOTTOM_SCREEN 1 +#define BOTTOM_SCREEN 2 -void putc(int buf, unsigned char color, const int c); -void puts(int buf, unsigned char color, const char *string); -void cflush(int channel); +#define stdout TOP_SCREEN +#define stderr BOTTOM_SCREEN -void put_int(int channel, unsigned char color, int n); -void put_uint(int channel, unsigned char color, unsigned int n); +void putc(void* buf, unsigned char color, const int c); +void puts(void* buf, unsigned char color, const char *string); +void fflush(void* channel); void set_cursor(int channel, unsigned int x, unsigned int y); // Like printf. Supports the following format specifiers: -// %s %c %d %u -// The following non-standard formats are also supported (but are subject to replacement) -// %p - unsigned char, changes color of text (will be replaced with ANSI codes eventually) -void cprintf(int channel, const char* format, ...); +// %s - char* +// %c - char +// %d - int +// %u - unsigned int +// The following non-standard +// The following prefixes are also supported: +// %h - word (stub) +// %hh - byte (stub) +// %[0-9][0-9] +// Formats are also supported (but are subject to replacement) +// %p - unsigned char, changes color of text (will be replaced with ANSI codes eventually) +void fprintf(void* channel, const char* format, ...); #define BLACK 0 #define BLUE 1 diff --git a/source/std/fs.c b/source/std/fs.c index e25a7a3..bb5fe54 100644 --- a/source/std/fs.c +++ b/source/std/fs.c @@ -2,30 +2,63 @@ #include "fs.h" #include "memory.h" #include "../fatfs/ff.h" +#include "draw.h" static FATFS fs; +static FILE files[MAX_FILES_OPEN]; + int fmount(void) { - if (f_mount(&fs, "0:", 1)) return 1; + if (f_mount(&fs, "0:", 1)) + return 1; + + for(int i=0; i < MAX_FILES_OPEN; i++) + memset(&files[i], 0, sizeof(FILE)); + return 0; } int fumount(void) { - if (f_mount(NULL, "0:", 1)) return 1; + for(int i=0; i < MAX_FILES_OPEN; i++) + if (files[i].is_open) + fclose(&files[i]); + + if (f_mount(NULL, "0:", 1)) + return 1; + return 0; } -int fopen(FILE* fp, const char *filename, const char *mode) { +FILE* fopen(const char *filename, const char *mode) { if (*mode != 'r' && *mode != 'w' && *mode != 'a') - return 1; // Mode not valid. + return NULL; // Mode not valid. + + FILE* fp; + int i; + for(i=0; i < MAX_FILES_OPEN; i++) { + if(!files[i].is_open) { + fp = &files[i]; + break; + } + } + + if (i == MAX_FILES_OPEN) + return NULL; // Out of handles. fp->mode = (*mode == 'r' ? FA_READ : (FA_WRITE | FA_OPEN_ALWAYS)); - return f_open(&(fp->handle), filename, fp->mode); + if (f_open(&(fp->handle), filename, fp->mode)) + return NULL; + + fp->is_open = 1; + + return fp; } void fclose(FILE* fp) { f_close(&(fp->handle)); + + memset(fp, 0, sizeof(FILE)); } void fseek(FILE* fp, int64_t offset, int whence) { @@ -78,19 +111,27 @@ size_t fread(void *buffer, size_t elementSize, size_t elementCnt, FILE* fp) { } size_t write_file(void* data, char* path, size_t size) { - FILE temp; - fopen(&temp, path, "w"); - size_t written = fwrite(data, 1, size, &temp); - fclose(&temp); - return written; + FILE* temp = fopen(path, "w"); + + if (!temp) + return 0; + + size_t wrote = fwrite(data, 1, size, temp); + + fclose(temp); + + return wrote; } size_t read_file(void* data, char* path, size_t size) { - FILE temp; - fopen(&temp, path, "r"); + FILE* temp = fopen(path, "r"); + + if (!temp) + return 0; + + size_t read = fread(data, 1, size, temp); - size_t read = fread(data, 1, size, &temp); - fclose(&temp); + fclose(temp); return read; } diff --git a/source/std/fs.h b/source/std/fs.h index 16f6f47..b53fc34 100644 --- a/source/std/fs.h +++ b/source/std/fs.h @@ -5,12 +5,15 @@ #include "memory.h" #include "../fatfs/ff.h" +#define MAX_FILES_OPEN 64 + typedef struct { FIL handle; uint32_t mode; size_t size; size_t at; -} FILE; + uint8_t is_open; +} __attribute__((packed)) FILE; #define SEEK_SET 0 #define SEEK_CUR 1 @@ -19,7 +22,7 @@ typedef struct { int fmount (void); int fumount (void); -int fopen (FILE* fp, const char *filename, const char *mode); +FILE* fopen (const char *filename, const char *mode); void fclose (FILE* fp);