First commit of the AuReiNand rewrite!
- Gotten rid of the patched FIRMs, AuReiNand now finds and loads all the FIRMs from CTRNAND by default. If you are booting an emuNAND, the FIRMs will be loaded from its CTRNAND. This also applies to AGB and TWL FIRM, and allows for a very fast boot with no firmware files on the SD card. - If for some reason (like using NTR) you do not want to use the CTRNAND FIRM, you can place a firmware.bin in the aurei folder and it will be loaded just for the default NAND. - The way AuReiNand works has changed. Now you can specify to autoboot SysNAND or not, and a NAND is no more tied to a FIRM (since 9.0 FIRM is autodetected). If you press nothing the default NAND is booted with its own FIRM, L boots the non-default NAND with its own FIRM, R boots EmuNAND with the SysNAND FIRM if you picked "Updated SysNAND", and vice-versa. - In order for AuReiNand to handle FIRM reboots, the .bin path needs to be hardcoded in the program. The default is /arm9loaderhax.bin (the AuReiNand.dat is also supported for 9.0 people). A PC tool was written to make changing the path easier. - Bug fixes and stuff I forgot. - Gelex is a saint.
This commit is contained in:
parent
4180261f1f
commit
7dbded99a2
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
out
|
||||
build
|
||||
loader/build
|
||||
screeninit/build
|
||||
injector/build
|
||||
*.bin
|
||||
*.3dsx
|
||||
|
10
Makefile
10
Makefile
@ -42,6 +42,9 @@ ninjhax: $(dir_out)/3ds/$(name)
|
||||
.PHONY: release
|
||||
release: $(dir_out)/$(name).zip
|
||||
|
||||
.PHONY: pathchanger
|
||||
pathchanger: $(dir_out)/pathchanger
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@$(MAKE) $(FLAGS) -C $(dir_mset) clean
|
||||
@ -54,6 +57,9 @@ clean:
|
||||
$(dir_out):
|
||||
@mkdir -p "$(dir_out)/aurei/payloads"
|
||||
|
||||
$(dir_out)/pathchanger: $(dir_out)
|
||||
@cc pathchanger/pathchanger.c -o out/pathchanger
|
||||
|
||||
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
|
||||
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
||||
@dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
|
||||
@ -108,9 +114,9 @@ $(dir_build)/%.o: $(dir_source)/%.s
|
||||
|
||||
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.c) -mthumb -mthumb-interwork -Wno-unused-function $(OUTPUT_OPTION) $<
|
||||
$(COMPILE.c) -Wno-unused-function $(OUTPUT_OPTION) $<
|
||||
|
||||
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.s) -mthumb -mthumb-interwork $(OUTPUT_OPTION) $<
|
||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||
include $(call rwildcard, $(dir_build), *.d)
|
||||
|
@ -187,18 +187,18 @@ void patchCode(u64 progId, u8 *code, u32 size)
|
||||
case 0x0004001000027000LL: // KOR MSET
|
||||
case 0x0004001000028000LL: // TWN MSET
|
||||
{
|
||||
if(R_SUCCEEDED(loadConfig()) && ((config >> 5) & 1))
|
||||
if(R_SUCCEEDED(loadConfig()) && ((config >> 4) & 1))
|
||||
{
|
||||
static const u16 verPattern[] = u"Ver.";
|
||||
const u32 currentFirm = ((config >> 12) & 1);
|
||||
const u32 currentNand = ((config >> 13) & 3);
|
||||
const u32 currentNand = ((config >> 16) & 3);
|
||||
const u32 matchingFirm = ((config >> 18) & 1) == (currentNand != 0);
|
||||
|
||||
//Patch Ver. string
|
||||
patchMemory(code, size,
|
||||
verPattern,
|
||||
sizeof(verPattern) - sizeof(u16), 0,
|
||||
currentNand ? ((currentNand == 1) ? ((currentFirm == 1) ? u" Emu" : u"Emu9") : u"Emu2") :
|
||||
((currentFirm == 1) ? u" Sys" : u"Sys9"),
|
||||
!currentNand ? ((matchingFirm) ? u" Sys" : u"SysA") :
|
||||
((currentNand == 1) ? (matchingFirm ? u" Emu" : u"EmuA") : ((matchingFirm) ? u"Emu2" : u"Em2A")),
|
||||
sizeof(verPattern) - sizeof(u16), 1
|
||||
);
|
||||
}
|
||||
|
128
patches/reboot.s
128
patches/reboot.s
@ -1,7 +1,7 @@
|
||||
.arm.little
|
||||
|
||||
firm_addr equ 0x24000000 ; Temporary location where we'll load the FIRM to
|
||||
firm_maxsize equ 0x200000 ; Random value that's bigger than any of the currently known firm's sizes.
|
||||
payload_addr equ 0x23F00000 ; Brahma payload address.
|
||||
payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
|
||||
|
||||
.create "reboot.bin", 0
|
||||
.arm
|
||||
@ -21,80 +21,43 @@ firm_maxsize equ 0x200000 ; Random value that's bigger than any of the currentl
|
||||
cmp r0, r2
|
||||
bne pxi_wait_recv
|
||||
|
||||
; Convert 2 bytes of the path string
|
||||
; This will be the method of getting the lower 2 bytes of the title ID
|
||||
; until someone bothers figuring out where the value is derived from.
|
||||
mov r0, #0 ; Result
|
||||
add r1, sp, #0x3A8 - 0x70
|
||||
add r1, #0x22 ; The significant bytes
|
||||
mov r2, #4 ; Maximum loops (amount of bytes * 2)
|
||||
|
||||
hex_string_to_int_loop:
|
||||
ldr r3, [r1], #2 ; 2 because it's a utf-16 string.
|
||||
and r3, #0xFF
|
||||
|
||||
; Check if it"s a number
|
||||
cmp r3, #'0'
|
||||
blo hex_string_to_int_end
|
||||
sub r3, #'0'
|
||||
cmp r3, #9
|
||||
bls hex_string_to_int_calc
|
||||
|
||||
; Check if it"s a capital letter
|
||||
cmp r3, #'A' - '0'
|
||||
blo hex_string_to_int_end
|
||||
sub r3, #'A' - '0' - 0xA ; Make the correct value: 0xF >= al >= 0xA
|
||||
cmp r3, #0xF
|
||||
bls hex_string_to_int_calc
|
||||
|
||||
; Incorrect value: x > "A"
|
||||
bhi hex_string_to_int_end
|
||||
|
||||
hex_string_to_int_calc:
|
||||
orr r0, r3, r0, lsl #4
|
||||
subs r2, #1
|
||||
bne hex_string_to_int_loop
|
||||
hex_string_to_int_end:
|
||||
|
||||
; Get the FIRM path
|
||||
cmp r0, #0x0002 ; NATIVE_FIRM
|
||||
adreq r1, firm_fname
|
||||
beq load_firm
|
||||
ldr r5, =0x0102 ; TWL_FIRM
|
||||
cmp r0, r5
|
||||
adreq r1, twlfirm_fname
|
||||
beq load_firm
|
||||
ldr r5, =0x0202 ; AGB_FIRM
|
||||
cmp r0, r5
|
||||
adreq r1, agbfirm_fname
|
||||
beq load_firm
|
||||
bne fallback ; TODO: Stubbed
|
||||
mov r4, #0
|
||||
adr r1, bin_fname
|
||||
b open_payload
|
||||
|
||||
fallback:
|
||||
; Fallback: Load specified FIRM from exefs
|
||||
add r1, sp, #0x3A8-0x70 ; Location of exefs string.
|
||||
b load_firm
|
||||
mov r4, #1
|
||||
adr r1, dat_fname
|
||||
|
||||
load_firm:
|
||||
open_payload:
|
||||
; Open file
|
||||
add r0, r7, #8
|
||||
mov r2, #1
|
||||
ldr r6, [fopen]
|
||||
orr r6, 1
|
||||
blx r6
|
||||
cmp r0, #0
|
||||
bne fallback ; If the .bin is not found, try the .dat.
|
||||
|
||||
cmp r0, #0 ; Check if we were able to load the FIRM
|
||||
bne fallback ; Otherwise, try again with the FIRM from exefs.
|
||||
; This will loop indefinitely if the exefs FIRM fails to load, but whatever.
|
||||
|
||||
read_payload:
|
||||
; Read file
|
||||
mov r0, r7
|
||||
adr r1, bytes_read
|
||||
mov r2, firm_addr
|
||||
mov r3, firm_maxsize
|
||||
ldr r2, =payload_addr
|
||||
cmp r4, #0
|
||||
movne r3, #0x12000 ; Skip the first 0x12000 bytes.
|
||||
moveq r3, payload_maxsize
|
||||
ldr r6, [sp, #0x3A8-0x198]
|
||||
ldr r6, [r6, #0x28]
|
||||
blx r6
|
||||
cmp r4, #0
|
||||
movne r4, #0
|
||||
bne read_payload ; Go read the real payload.
|
||||
|
||||
add r0, sp, #0x3A8 - 0x70
|
||||
ldr r0, [r0, #0x27]
|
||||
ldr r1, =payload_addr + 4
|
||||
str r0, [r1] ; Copy the last digits of the wanted firm to the 5th byte of the payload.
|
||||
|
||||
; Set kernel state
|
||||
mov r0, #0
|
||||
@ -115,13 +78,9 @@ firm_maxsize equ 0x200000 ; Random value that's bigger than any of the currentl
|
||||
bytes_read: .word 0
|
||||
fopen: .ascii "OPEN"
|
||||
.pool
|
||||
firm_fname: .dcw "sdmc:/aurei/patched_firmware_sys.bin"
|
||||
.word 0
|
||||
.pool
|
||||
twlfirm_fname: .dcw "sdmc:/aurei/patched_firmware_twl.bin"
|
||||
.word 0
|
||||
.pool
|
||||
agbfirm_fname: .dcw "sdmc:/aurei/patched_firmware_agb.bin"
|
||||
bin_fname: .dcw "sdmc:/arm9loaderhax.bin"
|
||||
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
dat_fname: .dcw "sdmc:/AuReiNand.dat"
|
||||
.word 0
|
||||
|
||||
.align 4
|
||||
@ -157,23 +116,6 @@ agbfirm_fname: .dcw "sdmc:/aurei/patched_firmware_agb.bin"
|
||||
mcr p15, 0, r1, c2, c0, 1 ; icacheable
|
||||
mcr p15, 0, r2, c3, c0, 0 ; write bufferable
|
||||
|
||||
; Copy the firmware
|
||||
mov r4, firm_addr
|
||||
add r5, r4, #0x40 ; Start of loop
|
||||
add r6, r5, #0x30 * 3 ; End of loop (scan 4 entries)
|
||||
|
||||
copy_firm_loop:
|
||||
ldr r0, [r5]
|
||||
cmp r0, #0
|
||||
addne r0, r4 ; src
|
||||
ldrne r1, [r5, #4] ; dest
|
||||
ldrne r2, [r5, #8] ; size
|
||||
blne memcpy32
|
||||
|
||||
cmp r5, r6
|
||||
addlo r5, #0x30
|
||||
blo copy_firm_loop
|
||||
|
||||
; Flush cache
|
||||
mov r2, #0
|
||||
mov r1, r2
|
||||
@ -197,22 +139,10 @@ agbfirm_fname: .dcw "sdmc:/aurei/patched_firmware_agb.bin"
|
||||
mcr p15, 0, r1, c7, c5, 0 ; flush dcache
|
||||
mcr p15, 0, r1, c7, c6, 0 ; flush icache
|
||||
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
|
||||
mov r0, firm_addr
|
||||
|
||||
; Boot FIRM
|
||||
mov r1, #0x1FFFFFFC
|
||||
ldr r2, [r0, #8] ; arm11 entry
|
||||
str r2, [r1]
|
||||
ldr r0, [r0, #0xC] ; arm9 entry
|
||||
; Jump to payload
|
||||
ldr r0, =payload_addr
|
||||
bx r0
|
||||
.pool
|
||||
|
||||
memcpy32: ; memcpy32(void *src, void *dst, unsigned int size)
|
||||
add r2, r0
|
||||
memcpy32_loop:
|
||||
ldmia r0!, {r3}
|
||||
stmia r1!, {r3}
|
||||
cmp r0, r2
|
||||
blo memcpy32_loop
|
||||
bx lr
|
||||
.pool
|
||||
.close
|
||||
|
98
pathchanger/pathchanger.c
Normal file
98
pathchanger/pathchanger.c
Normal file
@ -0,0 +1,98 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
|
||||
static u8 *memsearch(u8 *startPos, const void *pattern, int size, int patternSize)
|
||||
{
|
||||
const u8 *patternc = (const u8 *)pattern;
|
||||
|
||||
//Preprocessing
|
||||
int table[256];
|
||||
|
||||
int i;
|
||||
for(i = 0; i < 256; ++i)
|
||||
table[i] = patternSize + 1;
|
||||
for(i = 0; i < patternSize; ++i)
|
||||
table[patternc[i]] = patternSize - i;
|
||||
|
||||
//Searching
|
||||
int j = 0;
|
||||
|
||||
while(j <= size - patternSize)
|
||||
{
|
||||
if(memcmp(patternc, startPos + j, patternSize) == 0)
|
||||
return startPos + j;
|
||||
j += table[startPos[j + patternSize]];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int fsize(FILE *fp)
|
||||
{
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int size = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void error(FILE *payload, const char *message)
|
||||
{
|
||||
fclose(payload);
|
||||
printf("%s, are you sure you're using an AuReiNand payload?\n", message);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if(argc == 1)
|
||||
{
|
||||
printf("Usage: %s <AuReiNand payload path>\n", argv[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
FILE *payload;
|
||||
size_t size;
|
||||
|
||||
payload = fopen(argv[1], "rb+");
|
||||
size = fsize(payload);
|
||||
if(size > 0x20000)
|
||||
error(payload, "The input file is too large");
|
||||
|
||||
u8 *buffer = (u8 *)malloc(size);
|
||||
fread(buffer, 1, size, payload);
|
||||
|
||||
u8 pattern[] = {'s', 0, 'd', 0, 'm', 0, 'c', 0, ':', 0, '/', 0};
|
||||
|
||||
u8 *found = memsearch(buffer, pattern, size, sizeof(pattern));
|
||||
|
||||
if(found == NULL)
|
||||
{
|
||||
free(buffer);
|
||||
error(payload, "Pattern not found");
|
||||
}
|
||||
|
||||
u8 input[37] = {0};
|
||||
u8 payloadname[2 * sizeof(input)] = {0};
|
||||
|
||||
printf("Enter the payload's path (37 characters max): ");
|
||||
scanf("%37s", input);
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(input); i++)
|
||||
payloadname[2 * i] = input[i];
|
||||
|
||||
memcpy(found + 12, payloadname, sizeof(payloadname));
|
||||
|
||||
rewind(payload);
|
||||
fwrite(buffer, 1, size, payload);
|
||||
|
||||
free(buffer);
|
||||
fclose(payload);
|
||||
|
||||
exit(0);
|
||||
}
|
@ -12,7 +12,7 @@
|
||||
#include "i2c.h"
|
||||
#include "buttons.h"
|
||||
|
||||
void configureCFW(const char *configPath, const char *patchedFirms[])
|
||||
void configureCFW(const char *configPath)
|
||||
{
|
||||
initScreens();
|
||||
|
||||
@ -20,10 +20,9 @@ void configureCFW(const char *configPath, const char *patchedFirms[])
|
||||
drawString("Press A to select, START to save and reboot", 10, 30, COLOR_WHITE);
|
||||
|
||||
const char *optionsText[] = { "Screen-init brightness: 4( ) 3( ) 2( ) 1( )",
|
||||
"( ) Autoboot SysNAND",
|
||||
"( ) Updated SysNAND mode (A9LH-only)",
|
||||
"( ) Use pre-patched FIRMs",
|
||||
"( ) Force A9LH detection",
|
||||
"( ) Use 9.0 FIRM as default",
|
||||
"( ) Use second EmuNAND as default",
|
||||
"( ) Show current NAND in System Settings",
|
||||
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||
@ -37,8 +36,8 @@ void configureCFW(const char *configPath, const char *patchedFirms[])
|
||||
} options[optionsAmount];
|
||||
|
||||
//Parse the existing configuration
|
||||
options[0].enabled = CONFIG(10, 3);
|
||||
for(u32 i = optionsAmount; i; i--)
|
||||
options[0].enabled = CONFIG(14, 3);
|
||||
for(u32 i = optionsAmount - 1; i; i--)
|
||||
options[i].enabled = CONFIG((i - 1), 1);
|
||||
|
||||
//Pre-select the first configuration option
|
||||
@ -55,7 +54,9 @@ void configureCFW(const char *configPath, const char *patchedFirms[])
|
||||
//Display all the normal options in white, brightness will be displayed later
|
||||
for(u32 i = 1; i < optionsAmount; i++)
|
||||
{
|
||||
options[i].posY = drawString(optionsText[i], 10, options[i - 1].posY + SPACING_Y + (!(1 - i) * 7), COLOR_WHITE);
|
||||
static int endPos = 59;
|
||||
options[i].posY = endPos + SPACING_Y;
|
||||
endPos = drawString(optionsText[i], 10, options[i].posY, COLOR_WHITE);
|
||||
if(options[i].enabled) drawCharacter(selected, 10 + SPACING_X, options[i].posY, COLOR_WHITE);
|
||||
}
|
||||
|
||||
@ -129,18 +130,12 @@ void configureCFW(const char *configPath, const char *patchedFirms[])
|
||||
if(pressed == BUTTON_START) break;
|
||||
}
|
||||
|
||||
//If the user has been using A9LH and the "Updated SysNAND" setting changed, delete the patched 9.0 FIRM
|
||||
if(CONFIG(16, 1) && (CONFIG(0, 1) != options[1].enabled)) fileDelete(patchedFirms[3]);
|
||||
|
||||
//If the "Show GBA boot screen in patched AGB_FIRM" setting changed, delete the patched AGB_FIRM
|
||||
if(CONFIG(6, 1) != options[7].enabled) fileDelete(patchedFirms[5]);
|
||||
|
||||
//Preserve the last-used boot options (last 12 bits)
|
||||
config &= 0xFFF000;
|
||||
config &= 0xFF0000;
|
||||
|
||||
//Parse and write the new configuration
|
||||
config |= options[0].enabled << 10;
|
||||
for(u32 i = optionsAmount; i; i--)
|
||||
config |= options[0].enabled << 14;
|
||||
for(u32 i = optionsAmount - 1; i; i--)
|
||||
config |= options[i].enabled << (i - 1);
|
||||
|
||||
fileWrite(&config, configPath, 3);
|
||||
|
@ -11,6 +11,6 @@
|
||||
#define CFG_BOOTENV (*(vu32 *)0x10010000)
|
||||
#define CONFIG(a, b) ((config >> a) & b)
|
||||
|
||||
u32 config;
|
||||
extern u32 config;
|
||||
|
||||
void configureCFW(const char *configPath, const char *patchedFirms[]);
|
||||
void configureCFW(const char *configPath);
|
171
source/crypto.c
171
source/crypto.c
@ -229,47 +229,154 @@ static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode,
|
||||
}
|
||||
}
|
||||
|
||||
static void sha_wait_idle()
|
||||
{
|
||||
while(*REG_SHA_CNT & 1);
|
||||
}
|
||||
|
||||
static void sha(void *res, const void *src, u32 size, u32 mode)
|
||||
{
|
||||
sha_wait_idle();
|
||||
*REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
|
||||
|
||||
const u32 *src32 = (const u32 *)src;
|
||||
int i;
|
||||
while(size >= 0x40)
|
||||
{
|
||||
sha_wait_idle();
|
||||
for(i = 0; i < 4; ++i)
|
||||
{
|
||||
*REG_SHA_INFIFO = *src32++;
|
||||
*REG_SHA_INFIFO = *src32++;
|
||||
*REG_SHA_INFIFO = *src32++;
|
||||
*REG_SHA_INFIFO = *src32++;
|
||||
}
|
||||
|
||||
size -= 0x40;
|
||||
}
|
||||
|
||||
sha_wait_idle();
|
||||
memcpy((void *)REG_SHA_INFIFO, src32, size);
|
||||
|
||||
*REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
|
||||
|
||||
while(*REG_SHA_CNT & SHA_FINAL_ROUND);
|
||||
sha_wait_idle();
|
||||
|
||||
u32 hashSize = SHA_256_HASH_SIZE;
|
||||
if(mode == SHA_224_MODE)
|
||||
hashSize = SHA_224_HASH_SIZE;
|
||||
else if(mode == SHA_1_MODE)
|
||||
hashSize = SHA_1_HASH_SIZE;
|
||||
|
||||
memcpy(res, (void *)REG_SHA_HASH, hashSize);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
* Nand/FIRM Crypto stuff
|
||||
****************************************************************/
|
||||
|
||||
//Nand key#2 (0x12C10)
|
||||
static const u8 key2[0x10] = {
|
||||
0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0
|
||||
};
|
||||
static u8 nandCTR[0x10],
|
||||
nandSlot;
|
||||
|
||||
//Get Nand CTR key
|
||||
static void getNandCTR(u8 *buf, u32 console)
|
||||
static u32 fatStart;
|
||||
|
||||
//Initialize the CTRNAND crypto
|
||||
void ctrNandInit(void)
|
||||
{
|
||||
u8 *addr = (console ? (u8 *)0x080D8BBC : (u8 *)0x080D797C) + 0x0F;
|
||||
for(u8 keyLen = 0x10; keyLen; keyLen--)
|
||||
*(buf++) = *(addr--);
|
||||
u8 nandCid[0x10];
|
||||
u8 shaSum[0x20];
|
||||
|
||||
sdmmc_get_cid(1, (u32 *)nandCid);
|
||||
sha(shaSum, nandCid, 0x10, SHA_256_MODE);
|
||||
memcpy(nandCTR, shaSum, 0x10);
|
||||
|
||||
if(console)
|
||||
{
|
||||
u8 keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
|
||||
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
nandSlot = 0x05;
|
||||
fatStart = 0x5CAD7;
|
||||
}
|
||||
else
|
||||
{
|
||||
nandSlot = 0x04;
|
||||
fatStart = 0x5CAE5;
|
||||
}
|
||||
}
|
||||
|
||||
//Read firm0 from NAND and write to buffer
|
||||
void nandFirm0(u8 *outbuf, u32 size, u32 console)
|
||||
//Read and decrypt from the selected CTRNAND
|
||||
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
|
||||
{
|
||||
u8 CTR[0x10];
|
||||
getNandCTR(CTR, console);
|
||||
u8 tmpCTR[0x10];
|
||||
memcpy(tmpCTR, nandCTR, 0x10);
|
||||
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
sdmmc_nand_readsectors(0x0B130000 / 0x200, size / 0x200, outbuf);
|
||||
//Read
|
||||
u32 result;
|
||||
if(!firmSource)
|
||||
result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
|
||||
else
|
||||
{
|
||||
sector += emuOffset;
|
||||
result = sdmmc_sdcard_readsectors(sector + fatStart, sectorCount, outbuf);
|
||||
}
|
||||
|
||||
aes_advctr(CTR, 0x0B130000/0x10, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x06);
|
||||
aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
//Decrypt
|
||||
aes_use_keyslot(nandSlot);
|
||||
aes(outbuf, outbuf, (sectorCount * 0x200) / AES_BLOCK_SIZE, tmpCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//Decrypts the N3DS arm9bin
|
||||
void decryptArm9Bin(u8 *arm9Section, u32 mode)
|
||||
//Encrypt and write to the selected CTRNAND
|
||||
u32 ctrNandWrite(u32 sector, u32 sectorCount, u8 *inbuf)
|
||||
{
|
||||
u8 tmpCTR[0x10];
|
||||
memcpy(tmpCTR, nandCTR, 0x10);
|
||||
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
//Encrypt
|
||||
aes_use_keyslot(nandSlot);
|
||||
aes(inbuf, inbuf, (sectorCount * 0x200) / AES_BLOCK_SIZE, tmpCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
//Write
|
||||
if(!firmSource)
|
||||
return sdmmc_nand_writesectors(sector + fatStart, sectorCount, inbuf);
|
||||
|
||||
sector += emuOffset;
|
||||
return sdmmc_sdcard_writesectors(sector + fatStart, sectorCount, inbuf);
|
||||
}
|
||||
|
||||
//Decrypt a FIRM ExeFS
|
||||
void decryptExeFs(u8 *inbuf)
|
||||
{
|
||||
u32 exeFsOffset = (u32)inbuf + *(u32 *)(inbuf + 0x1A0) * 0x200;
|
||||
u32 exeFsSize = *(u32 *)(inbuf + 0x1A4) * 0x200;
|
||||
u8 ncchCTR[0x10];
|
||||
|
||||
memset(ncchCTR, 0, 0x10);
|
||||
for(u32 i=0; i<8; i++)
|
||||
ncchCTR[7-i] = *(inbuf + 0x108 + i);
|
||||
ncchCTR[8] = 2;
|
||||
|
||||
aes_setkey(0x2C, inbuf, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setiv(ncchCTR, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x2C);
|
||||
aes(inbuf - 0x200, (void *)exeFsOffset, exeFsSize/AES_BLOCK_SIZE, ncchCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
|
||||
//ARM9Loader replacement
|
||||
void arm9Loader(u8 *arm9Section, u32 mode)
|
||||
{
|
||||
//Firm keys
|
||||
u8 keyY[0x10];
|
||||
u8 CTR[0x10];
|
||||
u8 slot = mode ? 0x16 : 0x15;
|
||||
u8 arm9BinCTR[0x10];
|
||||
u8 arm9BinSlot = mode ? 0x16 : 0x15;
|
||||
|
||||
//Setup keys needed for arm9bin decryption
|
||||
memcpy(keyY, arm9Section + 0x10, 0x10);
|
||||
memcpy(CTR, arm9Section + 0x20, 0x10);
|
||||
memcpy(arm9BinCTR, arm9Section + 0x20, 0x10);
|
||||
|
||||
//Calculate the size of the ARM9 binary
|
||||
u32 size = 0;
|
||||
@ -279,31 +386,30 @@ void decryptArm9Bin(u8 *arm9Section, u32 mode)
|
||||
|
||||
if(mode)
|
||||
{
|
||||
const u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
||||
u8 keyX[0x10];
|
||||
|
||||
//Set 0x11 to key2 for the arm9bin and misc keys
|
||||
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x11);
|
||||
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||
aes_setkey(slot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
|
||||
aes_setkey(slot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setiv(CTR, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(slot);
|
||||
aes_setkey(arm9BinSlot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setiv(arm9BinCTR, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(arm9BinSlot);
|
||||
|
||||
//Decrypt arm9bin
|
||||
aes(arm9Section + 0x800, arm9Section + 0x800, size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
}
|
||||
aes(arm9Section + 0x800, arm9Section + 0x800, size/AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
//Sets the N3DS 9.6 KeyXs
|
||||
void setKeyXs(u8 *arm9Section)
|
||||
{
|
||||
//Set >=9.6 KeyXs
|
||||
if(mode)
|
||||
{
|
||||
u8 *keyData = arm9Section + 0x89814;
|
||||
u8 *decKey = keyData + 0x10;
|
||||
|
||||
//Set keys 0x19..0x1F keyXs
|
||||
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x11);
|
||||
for(u8 slot = 0x19; slot < 0x20; slot++)
|
||||
{
|
||||
@ -311,4 +417,5 @@ void setKeyXs(u8 *arm9Section)
|
||||
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
*(keyData + 0xF) += 1;
|
||||
}
|
||||
}
|
||||
}
|
@ -53,7 +53,38 @@
|
||||
#define AES_KEYX 1
|
||||
#define AES_KEYY 2
|
||||
|
||||
//NAND/FIRM stuff
|
||||
void nandFirm0(u8 *outbuf, u32 size, u32 console);
|
||||
void decryptArm9Bin(u8 *arm9Section, u32 mode);
|
||||
void setKeyXs(u8 *arm9Section);
|
||||
/**************************SHA****************************/
|
||||
#define REG_SHA_CNT ((vu32 *)0x1000A000)
|
||||
#define REG_SHA_BLKCNT ((vu32 *)0x1000A004)
|
||||
#define REG_SHA_HASH ((vu32 *)0x1000A040)
|
||||
#define REG_SHA_INFIFO ((vu32 *)0x1000A080)
|
||||
|
||||
#define SHA_CNT_STATE 0x00000003
|
||||
#define SHA_CNT_UNK2 0x00000004
|
||||
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008
|
||||
#define SHA_CNT_MODE 0x00000030
|
||||
#define SHA_CNT_ENABLE 0x00010000
|
||||
#define SHA_CNT_ACTIVE 0x00020000
|
||||
|
||||
#define SHA_HASH_READY 0x00000000
|
||||
#define SHA_NORMAL_ROUND 0x00000001
|
||||
#define SHA_FINAL_ROUND 0x00000002
|
||||
|
||||
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
|
||||
#define SHA_OUTPUT_LE 0
|
||||
|
||||
#define SHA_256_MODE 0
|
||||
#define SHA_224_MODE 0x00000010
|
||||
#define SHA_1_MODE 0x00000020
|
||||
|
||||
#define SHA_256_HASH_SIZE (256 / 8)
|
||||
#define SHA_224_HASH_SIZE (224 / 8)
|
||||
#define SHA_1_HASH_SIZE (160 / 8)
|
||||
|
||||
extern u32 emuOffset, console, firmSource;
|
||||
|
||||
void ctrNandInit(void);
|
||||
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
||||
u32 ctrNandWrite(u32 sector, u32 sectorCount, u8 *inbuf);
|
||||
void decryptExeFs(u8 *inbuf);
|
||||
void arm9Loader(u8 *arm9Section, u32 mode);
|
@ -8,7 +8,7 @@
|
||||
#include "memory.h"
|
||||
#include "fatfs/sdmmc/sdmmc.h"
|
||||
|
||||
u32 getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
|
||||
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
|
||||
{
|
||||
u8 *const temp = (u8 *)0x24300000;
|
||||
|
||||
@ -40,13 +40,9 @@ u32 getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
|
||||
{
|
||||
(*emuNAND)--;
|
||||
if(*emuNAND) getEmunandSect(off, head, emuNAND);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
u32 getSDMMC(u8 *pos, u32 size)
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#define NCSD_MAGIC (0x4453434E)
|
||||
|
||||
u32 getEmunandSect(u32 *off, u32 *head, u32 *emuNAND);
|
||||
void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND);
|
||||
u32 getSDMMC(u8 *pos, u32 size);
|
||||
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff);
|
||||
u32 *getMPU(u8 *pos, u32 size);
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include "diskio.h" /* FatFs lower layer API */
|
||||
#include "sdmmc/sdmmc.h"
|
||||
|
||||
/* Definitions of physical drive number for each media */
|
||||
#define SDCARD 0
|
||||
#define CTRNAND 1
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Drive Status */
|
||||
@ -34,7 +37,16 @@ DSTATUS disk_initialize (
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
switch(pdrv)
|
||||
{
|
||||
case SDCARD:
|
||||
sdmmc_sdcard_init();
|
||||
break;
|
||||
case CTRNAND:
|
||||
ctrNandInit();
|
||||
break;
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
}
|
||||
|
||||
@ -52,8 +64,16 @@ DRESULT disk_read (
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
if (sdmmc_sdcard_readsectors(sector, count, buff)) {
|
||||
switch(pdrv)
|
||||
{
|
||||
case SDCARD:
|
||||
if(sdmmc_sdcard_readsectors(sector, count, (BYTE *)buff))
|
||||
return RES_PARERR;
|
||||
break;
|
||||
case CTRNAND:
|
||||
if(ctrNandRead(sector, count, (BYTE *)buff))
|
||||
return RES_PARERR;
|
||||
break;
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
@ -74,8 +94,16 @@ DRESULT disk_write (
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) {
|
||||
switch(pdrv)
|
||||
{
|
||||
case SDCARD:
|
||||
if(sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff))
|
||||
return RES_PARERR;
|
||||
break;
|
||||
case CTRNAND:
|
||||
if(ctrNandWrite(sector, count, (BYTE *)buff))
|
||||
return RES_PARERR;
|
||||
break;
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
|
552
source/fatfs/ff.c
Normal file → Executable file
552
source/fatfs/ff.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
6
source/fatfs/ff.h
Normal file → Executable file
6
source/fatfs/ff.h
Normal file → Executable file
@ -1,5 +1,5 @@
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015
|
||||
/ FatFs - FAT file system module include R0.11a (C)ChaN, 2015
|
||||
/----------------------------------------------------------------------------/
|
||||
/ FatFs module is a free software that opened under license policy of
|
||||
/ following conditions.
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
|
||||
#ifndef _FATFS
|
||||
#define _FATFS 32020 /* Revision ID */
|
||||
#define _FATFS 64180 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -200,7 +200,7 @@ typedef enum {
|
||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
|
||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
|
||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||
} FRESULT;
|
||||
|
||||
|
49
source/fatfs/ffconf.h
Normal file → Executable file
49
source/fatfs/ffconf.h
Normal file → Executable file
@ -1,21 +1,13 @@
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015
|
||||
/ FatFs - FAT file system module configuration file R0.11a (C)ChaN, 2015
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FFCONF 32020 /* Revision ID */
|
||||
#define _FFCONF 64180 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Functions and Buffer Configurations
|
||||
/ Function Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FS_TINY 0
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
|
||||
/ bytes. Instead of private sector buffer eliminated from the file object,
|
||||
/ common sector buffer in the file system object (FATFS) is used for the file
|
||||
/ data transfer. */
|
||||
|
||||
|
||||
#define _FS_READONLY 0
|
||||
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
||||
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
||||
@ -23,7 +15,7 @@
|
||||
/ and optional writing functions as well. */
|
||||
|
||||
|
||||
#define _FS_MINIMIZE 0
|
||||
#define _FS_MINIMIZE 1
|
||||
/* This option defines minimization level to remove some basic API functions.
|
||||
/
|
||||
/ 0: All basic functions are enabled.
|
||||
@ -77,19 +69,24 @@
|
||||
/ 437 - U.S.
|
||||
/ 720 - Arabic
|
||||
/ 737 - Greek
|
||||
/ 771 - KBL
|
||||
/ 775 - Baltic
|
||||
/ 850 - Multilingual Latin 1
|
||||
/ 850 - Latin 1
|
||||
/ 852 - Latin 2
|
||||
/ 855 - Cyrillic
|
||||
/ 857 - Turkish
|
||||
/ 858 - Multilingual Latin 1 + Euro
|
||||
/ 860 - Portuguese
|
||||
/ 861 - Icelandic
|
||||
/ 862 - Hebrew
|
||||
/ 863 - Canadian French
|
||||
/ 864 - Arabic
|
||||
/ 865 - Nordic
|
||||
/ 866 - Russian
|
||||
/ 874 - Thai
|
||||
/ 932 - Japanese Shift_JIS (DBCS)
|
||||
/ 936 - Simplified Chinese GBK (DBCS)
|
||||
/ 869 - Greek 2
|
||||
/ 932 - Japanese (DBCS)
|
||||
/ 936 - Simplified Chinese (DBCS)
|
||||
/ 949 - Korean (DBCS)
|
||||
/ 950 - Traditional Chinese Big5 (DBCS)
|
||||
/ 950 - Traditional Chinese (DBCS)
|
||||
*/
|
||||
|
||||
|
||||
@ -115,7 +112,7 @@
|
||||
/ to 1. This option also affects behavior of string I/O functions. */
|
||||
|
||||
|
||||
#define _STRF_ENCODE 0
|
||||
#define _STRF_ENCODE 3
|
||||
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
|
||||
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
||||
/
|
||||
@ -141,7 +138,7 @@
|
||||
/ Drive/Volume Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _VOLUMES 1
|
||||
#define _VOLUMES 2
|
||||
/* Number of volumes (logical drives) to be used. */
|
||||
|
||||
|
||||
@ -195,8 +192,16 @@
|
||||
/ System Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FS_TINY 0
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
|
||||
/ bytes. Instead of private sector buffer eliminated from the file object,
|
||||
/ common sector buffer in the file system object (FATFS) is used for the file
|
||||
/ data transfer. */
|
||||
|
||||
|
||||
#define _FS_NORTC 1
|
||||
#define _NORTC_MON 2
|
||||
#define _NORTC_MON 1
|
||||
#define _NORTC_MDAY 1
|
||||
#define _NORTC_YEAR 2015
|
||||
/* The _FS_NORTC option switches timestamp feature. If the system does not have
|
||||
@ -253,7 +258,7 @@
|
||||
/ * Byte order on the memory is little-endian.
|
||||
/
|
||||
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
|
||||
/ Following table shows allowable settings of some processor types.
|
||||
/ Following table shows allowable settings of some type of processors.
|
||||
/
|
||||
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
|
||||
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1
|
||||
|
10
source/fatfs/integer.h
Normal file → Executable file
10
source/fatfs/integer.h
Normal file → Executable file
@ -5,26 +5,26 @@
|
||||
#ifndef _FF_INTEGER
|
||||
#define _FF_INTEGER
|
||||
|
||||
#ifdef _WIN32 /* FatFs development platform */
|
||||
#ifdef _WIN32 /* Development platform */
|
||||
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#else /* Embedded platform */
|
||||
|
||||
/* This type MUST be 8 bit */
|
||||
/* This type MUST be 8-bit */
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
/* These types MUST be 16 bit */
|
||||
/* These types MUST be 16-bit */
|
||||
typedef short SHORT;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned short WCHAR;
|
||||
|
||||
/* These types MUST be 16 bit or 32 bit */
|
||||
/* These types MUST be 16-bit or 32-bit */
|
||||
typedef int INT;
|
||||
typedef unsigned int UINT;
|
||||
|
||||
/* These types MUST be 32 bit */
|
||||
/* These types MUST be 32-bit */
|
||||
typedef long LONG;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
|
348
source/fatfs/option/ccsbcs.c
Executable file
348
source/fatfs/option/ccsbcs.c
Executable file
@ -0,0 +1,348 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */
|
||||
/* (SBCS code pages) */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* 437 U.S.
|
||||
/ 720 Arabic
|
||||
/ 737 Greek
|
||||
/ 771 KBL
|
||||
/ 775 Baltic
|
||||
/ 850 Latin 1
|
||||
/ 852 Latin 2
|
||||
/ 855 Cyrillic
|
||||
/ 857 Turkish
|
||||
/ 860 Portuguese
|
||||
/ 861 Icelandic
|
||||
/ 862 Hebrew
|
||||
/ 863 Canadian French
|
||||
/ 864 Arabic
|
||||
/ 865 Nordic
|
||||
/ 866 Russian
|
||||
/ 869 Greek 2
|
||||
*/
|
||||
|
||||
#include "../ff.h"
|
||||
|
||||
|
||||
#if _CODE_PAGE == 437
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 720
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */
|
||||
0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
|
||||
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
|
||||
0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 737
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */
|
||||
0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
|
||||
0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
|
||||
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
|
||||
0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 771
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */
|
||||
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
|
||||
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
|
||||
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D,
|
||||
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
|
||||
0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 775
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */
|
||||
0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
|
||||
0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
|
||||
0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
|
||||
0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
|
||||
0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 850
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||
0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
|
||||
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
|
||||
0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 852
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
|
||||
0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||
0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
|
||||
0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
|
||||
0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 855
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */
|
||||
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
|
||||
0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
|
||||
0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||
0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
|
||||
0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
|
||||
0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 857
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
|
||||
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||
0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
|
||||
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
|
||||
0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 860
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,
|
||||
0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 861
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,
|
||||
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 862
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */
|
||||
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
|
||||
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 863
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,
|
||||
0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,
|
||||
0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 864
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */
|
||||
0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,
|
||||
0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,
|
||||
0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,
|
||||
0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F,
|
||||
0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
|
||||
0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9,
|
||||
0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1,
|
||||
0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 865
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||
0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 866
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */
|
||||
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
|
||||
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
|
||||
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
|
||||
0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 869
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */
|
||||
0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
|
||||
0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,
|
||||
0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3,
|
||||
0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580,
|
||||
0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384,
|
||||
0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if !_TBLDEF || !_USE_LFN
|
||||
#error This file is not needed at current configuration. Remove from the project.
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
WCHAR ff_convert ( /* Converted character, Returns zero on error */
|
||||
WCHAR chr, /* Character code to be converted */
|
||||
UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */
|
||||
)
|
||||
{
|
||||
WCHAR c;
|
||||
|
||||
|
||||
if (chr < 0x80) { /* ASCII */
|
||||
c = chr;
|
||||
|
||||
} else {
|
||||
if (dir) { /* OEM code to Unicode */
|
||||
c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80];
|
||||
|
||||
} else { /* Unicode to OEM code */
|
||||
for (c = 0; c < 0x80; c++) {
|
||||
if (chr == Tbl[c]) break;
|
||||
}
|
||||
c = (c + 0x80) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
WCHAR ff_wtoupper ( /* Returns upper converted character */
|
||||
WCHAR chr /* Unicode character to be upper converted */
|
||||
)
|
||||
{
|
||||
static const WCHAR lower[] = { /* Lower case characters to be converted */
|
||||
/* Latin Supplement */ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
|
||||
/* Latin Extended-A */ 0x101,0x103,0x105,0x107,0x109,0x10B,0x10D,0x10F,0x111,0x113,0x115,0x117,0x119,0x11B,0x11D,0x11F,0x121,0x123,0x125,0x127,0x129,0x12B,0x12D,0x12F,0x131,0x133,0x135,0x137,0x13A,0x13C,0x13E,0x140,0x142,0x144,0x146,0x148,0x14B,0x14D,0x14F,0x151,0x153,0x155,0x157,0x159,0x15B,0x15D,0x15F,0x161,0x163,0x165,0x167,0x169,0x16B,0x16D,0x16F,0x171,0x173,0x175,0x177,0x17A,0x17C,0x17E,
|
||||
/* Latin Extended-B */ 0x183,0x185,0x188,0x18C,0x192,0x199,0x1A1,0x1A3,0x1A8,0x1AD,0x1B0,0x1B4,0x1B6,0x1B9,0x1BD,0x1C6,0x1C9,0x1CC,0x1CE,0x1D0,0x1D2,0x1D4,0x1D6,0x1D8,0x1DA,0x1DC,0x1DD,0x1DF,0x1E1,0x1E3,0x1E5,0x1E7,0x1E9,0x1EB,0x1ED,0x1EF,0x1F3,0x1F5,0x1FB,0x1FD,0x1FF,0x201,0x203,0x205,0x207,0x209,0x20B,0x20D,0x20F,0x211,0x213,0x215,0x217,
|
||||
/* Greek, Coptic */ 0x3B1,0x3B2,0x3B3,0x3B4,0x3B5,0x3B6,0x3B7,0x3B8,0x3B9,0x3BA,0x3BB,0x3BC,0x3BD,0x3BE,0x3BF,0x3C0,0x3C1,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CA,0x3CB,0x3CC,0x3CD,0x3CE,0x3E3,0x3E5,0x3E7,0x3E9,0x3EB,
|
||||
/* Cyrillic */ 0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43A,0x43B,0x43C,0x43D,0x43E,0x43F,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,0x44A,0x44B,0x44C,0x44D,0x44E,0x44F,0x452,0x453,0x454,0x455,0x456,0x457,0x458,0x459,0x45A,0x45B,0x45C,0x45E,0x45F,0x461,0x463,0x465,0x467,0x469,0x46B,0x46D,0x46F,0x471,0x473,0x475,0x477,0x479,0x47B,0x47D,0x47F,0x481,0x491,0x493,0x495,0x497,0x499,0x49B,0x49D,0x49F,0x4A1,0x4A3,0x4A5,0x4A7,0x4A9,0x4AB,0x4AD,0x4AF,0x4B1,0x4B3,0x4B5,0x4B7,0x4B9,0x4BB,0x4BD,0x4BF,0x4C2,0x4C4,0x4C8,0x4D1,0x4D3,0x4D5,0x4D7,0x4D9,0x4DB,0x4DD,0x4DF,0x4E1,0x4E3,0x4E5,0x4E7,0x4E9,0x4EB,0x4ED,0x4EF,0x4F1,0x4F3,0x4F5,0x4F9,
|
||||
/* Armenian */ 0x561,0x562,0x563,0x564,0x565,0x566,0x567,0x568,0x569,0x56A,0x56B,0x56C,0x56D,0x56E,0x56F,0x570,0x571,0x572,0x573,0x574,0x575,0x576,0x577,0x578,0x579,0x57A,0x57B,0x57C,0x57D,0x57E,0x57F,0x580,0x581,0x582,0x583,0x584,0x585,0x586,
|
||||
/* Latin Extended Additional */ 0x1E01,0x1E03,0x1E05,0x1E07,0x1E09,0x1E0B,0x1E0D,0x1E0F,0x1E11,0x1E13,0x1E15,0x1E17,0x1E19,0x1E1B,0x1E1D,0x1E1F,0x1E21,0x1E23,0x1E25,0x1E27,0x1E29,0x1E2B,0x1E2D,0x1E2F,0x1E31,0x1E33,0x1E35,0x1E37,0x1E39,0x1E3B,0x1E3D,0x1E3F,0x1E41,0x1E43,0x1E45,0x1E47,0x1E49,0x1E4B,0x1E4D,0x1E4F,0x1E51,0x1E53,0x1E55,0x1E57,0x1E59,0x1E5B,0x1E5D,0x1E5F,0x1E61,0x1E63,0x1E65,0x1E67,0x1E69,0x1E6B,0x1E6D,0x1E6F,0x1E71,0x1E73,0x1E75,0x1E77,0x1E79,0x1E7B,0x1E7D,0x1E7F,0x1E81,0x1E83,0x1E85,0x1E87,0x1E89,0x1E8B,0x1E8D,0x1E8F,0x1E91,0x1E93,0x1E95,0x1E97,0x1E99,0x1E9B,0x1E9D,0x1E9F,0x1EA1,0x1EA3,0x1EA5,0x1EA7,0x1EA9,0x1EAB,0x1EAD,0x1EAF,0x1EB1,0x1EB3,0x1EB5,0x1EB7,0x1EB9,0x1EBB,0x1EBD,0x1EBF,0x1EC1,0x1EC3,0x1EC5,0x1EC7,0x1EC9,0x1ECB,0x1ECD,0x1ECF,0x1ED1,0x1ED3,0x1ED5,0x1ED7,0x1ED9,0x1EDB,0x1EDD,0x1EDF,0x1EE1,0x1EE3,0x1EE5,0x1EE7,0x1EE9,0x1EEB,0x1EED,0x1EEF,0x1EF1,0x1EF3,0x1EF5,0x1EF7,0x1EF9,
|
||||
/* Number forms */ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,0x217A,0x217B,0x217C,0x217D,0x217E,0x217F,
|
||||
/* Full-width */ 0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,0xFF58,0xFF59,0xFF5A
|
||||
};
|
||||
static const WCHAR upper[] = { /* Upper case characters correspond to lower[] */
|
||||
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x178,
|
||||
0x100,0x102,0x104,0x106,0x108,0x10A,0x10C,0x10E,0x110,0x112,0x114,0x116,0x118,0x11A,0x11C,0x11E,0x120,0x122,0x124,0x126,0x128,0x12A,0x12C,0x12E,0x130,0x132,0x134,0x136,0x139,0x13B,0x13D,0x13F,0x141,0x143,0x145,0x147,0x14A,0x14C,0x14E,0x150,0x152,0x154,0x156,0x158,0x15A,0x15C,0x15E,0x160,0x162,0x164,0x166,0x168,0x16A,0x16C,0x16E,0x170,0x172,0x174,0x176,0x179,0x17B,0x17D,
|
||||
0x182,0x184,0x187,0x18B,0x191,0x198,0x1A0,0x1A2,0x1A7,0x1AC,0x1AF,0x1B3,0x1B5,0x1B8,0x1BC,0x1C4,0x1C7,0x1CA,0x1CD,0x1CF,0x1D1,0x1D3,0x1D5,0x1D7,0x1D9,0x1DB,0x18E,0x1DE,0x1E0,0x1E2,0x1E4,0x1E6,0x1E8,0x1EA,0x1EC,0x1EE,0x1F1,0x1F4,0x1FA,0x1FC,0x1FE,0x200,0x202,0x204,0x206,0x208,0x20A,0x20C,0x20E,0x210,0x212,0x214,0x216,
|
||||
0x391,0x392,0x393,0x394,0x395,0x396,0x397,0x398,0x399,0x39A,0x39B,0x39C,0x39D,0x39E,0x39F,0x3A0,0x3A1,0x3A3,0x3A4,0x3A5,0x3A6,0x3A7,0x3A8,0x3A9,0x3AA,0x3AB,0x38C,0x38E,0x38F,0x3E2,0x3E4,0x3E6,0x3E8,0x3EA,
|
||||
0x410,0x411,0x412,0x413,0x414,0x415,0x416,0x417,0x418,0x419,0x41A,0x41B,0x41C,0x41D,0x41E,0x41F,0x420,0x421,0x422,0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42A,0x42B,0x42C,0x42D,0x42E,0x42F,0x402,0x403,0x404,0x405,0x406,0x407,0x408,0x409,0x40A,0x40B,0x40C,0x40E,0x40F,0x460,0x462,0x464,0x466,0x468,0x46A,0x46C,0x46E,0x470,0x472,0x474,0x476,0x478,0x47A,0x47C,0x47E,0x480,0x490,0x492,0x494,0x496,0x498,0x49A,0x49C,0x49E,0x4A0,0x4A2,0x4A4,0x4A6,0x4A8,0x4AA,0x4AC,0x4AE,0x4B0,0x4B2,0x4B4,0x4B6,0x4B8,0x4BA,0x4BC,0x4BE,0x4C1,0x4C3,0x5C7,0x4D0,0x4D2,0x4D4,0x4D6,0x4D8,0x4DA,0x4DC,0x4DE,0x4E0,0x4E2,0x4E4,0x4E6,0x4E8,0x4EA,0x4EC,0x4EE,0x4F0,0x4F2,0x4F4,0x4F8,
|
||||
0x531,0x532,0x533,0x534,0x535,0x536,0x537,0x538,0x539,0x53A,0x53B,0x53C,0x53D,0x53E,0x53F,0x540,0x541,0x542,0x543,0x544,0x545,0x546,0x547,0x548,0x549,0x54A,0x54B,0x54C,0x54D,0x54E,0x54F,0x550,0x551,0x552,0x553,0x554,0x555,0x556,
|
||||
0x1E00,0x1E02,0x1E04,0x1E06,0x1E08,0x1E0A,0x1E0C,0x1E0E,0x1E10,0x1E12,0x1E14,0x1E16,0x1E18,0x1E1A,0x1E1C,0x1E1E,0x1E20,0x1E22,0x1E24,0x1E26,0x1E28,0x1E2A,0x1E2C,0x1E2E,0x1E30,0x1E32,0x1E34,0x1E36,0x1E38,0x1E3A,0x1E3C,0x1E3E,0x1E40,0x1E42,0x1E44,0x1E46,0x1E48,0x1E4A,0x1E4C,0x1E4E,0x1E50,0x1E52,0x1E54,0x1E56,0x1E58,0x1E5A,0x1E5C,0x1E5E,0x1E60,0x1E62,0x1E64,0x1E66,0x1E68,0x1E6A,0x1E6C,0x1E6E,0x1E70,0x1E72,0x1E74,0x1E76,0x1E78,0x1E7A,0x1E7C,0x1E7E,0x1E80,0x1E82,0x1E84,0x1E86,0x1E88,0x1E8A,0x1E8C,0x1E8E,0x1E90,0x1E92,0x1E94,0x1E96,0x1E98,0x1E9A,0x1E9C,0x1E9E,0x1EA0,0x1EA2,0x1EA4,0x1EA6,0x1EA8,0x1EAA,0x1EAC,0x1EAE,0x1EB0,0x1EB2,0x1EB4,0x1EB6,0x1EB8,0x1EBA,0x1EBC,0x1EBE,0x1EC0,0x1EC2,0x1EC4,0x1EC6,0x1EC8,0x1ECA,0x1ECC,0x1ECE,0x1ED0,0x1ED2,0x1ED4,0x1ED6,0x1ED8,0x1EDA,0x1EDC,0x1EDE,0x1EE0,0x1EE2,0x1EE4,0x1EE6,0x1EE8,0x1EEA,0x1EEC,0x1EEE,0x1EF0,0x1EF2,0x1EF4,0x1EF6,0x1EF8,
|
||||
0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216A,0x216B,0x216C,0x216D,0x216E,0x216F,
|
||||
0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,0xFF3A
|
||||
};
|
||||
UINT i, n, hi, li;
|
||||
|
||||
|
||||
if (chr < 0x80) { /* ASCII characters (acceleration) */
|
||||
if (chr >= 0x61 && chr <= 0x7A) chr -= 0x20;
|
||||
|
||||
} else { /* Non ASCII characters (table search) */
|
||||
n = 12; li = 0; hi = sizeof lower / sizeof lower[0];
|
||||
do {
|
||||
i = li + (hi - li) / 2;
|
||||
if (chr == lower[i]) break;
|
||||
if (chr > lower[i]) li = i; else hi = i;
|
||||
} while (--n);
|
||||
if (n) chr = upper[i];
|
||||
}
|
||||
|
||||
return chr;
|
||||
}
|
||||
|
@ -2,3 +2,4 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "../../types.h"
|
||||
#include "../../crypto.h"
|
@ -402,3 +402,44 @@ int sdmmc_sdcard_init()
|
||||
return result | SD_Init();
|
||||
}
|
||||
|
||||
int sdmmc_get_cid( int isNand, uint32_t *info)
|
||||
{
|
||||
struct mmcdevice *device;
|
||||
if(isNand)
|
||||
device = &handleNAND;
|
||||
else
|
||||
device = &handleSD;
|
||||
|
||||
inittarget(device);
|
||||
// use cmd7 to put sd card in standby mode
|
||||
// CMD7
|
||||
{
|
||||
sdmmc_send_command(device,0x10507,0);
|
||||
//if((device->error & 0x4)) return -1;
|
||||
}
|
||||
|
||||
// get sd card info
|
||||
// use cmd10 to read CID
|
||||
{
|
||||
sdmmc_send_command(device,0x1060A,device->initarg << 0x10);
|
||||
//if((device->error & 0x4)) return -2;
|
||||
|
||||
for( int i = 0; i < 4; ++i ) {
|
||||
info[i] = device->ret[i];
|
||||
}
|
||||
}
|
||||
|
||||
// put sd card back to transfer mode
|
||||
// CMD7
|
||||
{
|
||||
sdmmc_send_command(device,0x10507,device->initarg << 0x10);
|
||||
//if((device->error & 0x4)) return -3;
|
||||
}
|
||||
|
||||
if(isNand)
|
||||
{
|
||||
inittarget(&handleSD);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -122,6 +122,7 @@ int sdmmc_sdcard_init();
|
||||
u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
|
||||
u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
|
||||
mmcdevice *getMMCDevice(int drive);
|
||||
int sdmmc_get_cid( int isNand, uint32_t *info);
|
||||
|
||||
u32 sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
|
||||
u32 sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
|
438
source/firm.c
438
source/firm.c
@ -18,46 +18,36 @@
|
||||
#include "buttons.h"
|
||||
#include "../build/patches.h"
|
||||
|
||||
//FIRM patches version
|
||||
#define PATCH_VER 4
|
||||
|
||||
static firmHeader *const firm = (firmHeader *)0x24000000;
|
||||
static const firmSectionHeader *section;
|
||||
static u8 *arm9Section;
|
||||
static const char *patchedFirms[] = { "/aurei/patched_firmware_sys.bin",
|
||||
"/aurei/patched_firmware_emu.bin",
|
||||
"/aurei/patched_firmware_em2.bin",
|
||||
"/aurei/patched_firmware90.bin",
|
||||
"/aurei/patched_firmware_twl.bin",
|
||||
"/aurei/patched_firmware_agb.bin" };
|
||||
u32 config;
|
||||
static u32 firmSize,
|
||||
|
||||
static const char *firmFolders[3][2] = {{ "00000002", "20000002" },
|
||||
{ "00000102", "20000102" },
|
||||
{ "00000202", "20000202" }};
|
||||
u32 config,
|
||||
console,
|
||||
mode,
|
||||
emuNAND,
|
||||
a9lhSetup,
|
||||
selectedFirm,
|
||||
usePatchedFirm,
|
||||
emuOffset,
|
||||
emuHeader;
|
||||
firmSource;
|
||||
|
||||
void setupCFW(void)
|
||||
void main(void)
|
||||
{
|
||||
//Determine if booting with A9LH
|
||||
u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0;
|
||||
|
||||
//Retrieve the last booted FIRM
|
||||
u32 previousFirm = CFG_BOOTENV;
|
||||
u32 bootType,
|
||||
firmType,
|
||||
nandType,
|
||||
a9lhInstalled,
|
||||
updatedSys,
|
||||
needConfig,
|
||||
newConfig,
|
||||
emuHeader;
|
||||
|
||||
//Detect the console being used
|
||||
console = (PDN_MPCORE_CFG == 1) ? 0 : 1;
|
||||
|
||||
//Get pressed buttons
|
||||
u32 pressed = HID_PAD;
|
||||
//Mount filesystems. CTRNAND will be mounted only if/when needed
|
||||
mountFs();
|
||||
|
||||
//Attempt to read the configuration file
|
||||
const char configPath[] = "/aurei/config.bin";
|
||||
u32 needConfig;
|
||||
if(fileRead(&config, configPath, 3)) needConfig = 1;
|
||||
else
|
||||
{
|
||||
@ -65,26 +55,54 @@ void setupCFW(void)
|
||||
needConfig = 2;
|
||||
}
|
||||
|
||||
//Determine if A9LH is installed and the user has an updated sysNAND
|
||||
u32 updatedSys;
|
||||
//Determine if this is a firmlaunch boot
|
||||
if(*(vu8 *)0x23F00005)
|
||||
{
|
||||
bootType = 1;
|
||||
|
||||
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
|
||||
firmType = *(vu8 *)0x23F00005 - 0x2F;
|
||||
|
||||
nandType = CONFIG(16, 3);
|
||||
firmSource = CONFIG(18, 1);
|
||||
a9lhInstalled = CONFIG(19, 1);
|
||||
updatedSys = (a9lhInstalled && CONFIG(1, 1)) ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bootType = 0;
|
||||
firmType = 1;
|
||||
|
||||
//Determine if booting with A9LH
|
||||
u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0;
|
||||
|
||||
//Retrieve the last booted FIRM
|
||||
u32 previousFirm = CFG_BOOTENV;
|
||||
|
||||
//Get pressed buttons
|
||||
u32 pressed = HID_PAD;
|
||||
|
||||
//Determine if we need to autoboot sysNAND
|
||||
u32 autoBootSys = CONFIG(0, 1);
|
||||
|
||||
//Determine if A9LH is installed and the user has an updated sysNAND
|
||||
if(a9lhBoot || CONFIG(2, 1))
|
||||
{
|
||||
if(pressed == SAFE_MODE)
|
||||
error("Using Safe Mode would brick you, or remove A9LH!");
|
||||
|
||||
a9lhSetup = 1;
|
||||
a9lhInstalled = 1;
|
||||
|
||||
//Check setting for > 9.2 sysNAND
|
||||
updatedSys = CONFIG(0, 1);
|
||||
updatedSys = CONFIG(1, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
a9lhSetup = 0;
|
||||
a9lhInstalled = 0;
|
||||
updatedSys = 0;
|
||||
}
|
||||
|
||||
u32 tempConfig = (PATCH_VER << 17) | (a9lhSetup << 16);
|
||||
newConfig = a9lhInstalled << 19;
|
||||
|
||||
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists,
|
||||
try to force boot options */
|
||||
@ -93,19 +111,19 @@ void setupCFW(void)
|
||||
//Always force a sysNAND boot when quitting AGB_FIRM
|
||||
if(previousFirm == 7)
|
||||
{
|
||||
mode = updatedSys ? 1 : CONFIG(12, 1);
|
||||
emuNAND = 0;
|
||||
nandType = 0;
|
||||
firmSource = updatedSys ? 0 : CONFIG(18, 1);
|
||||
needConfig = 0;
|
||||
|
||||
//Flag to prevent multiple boot options-forcing
|
||||
tempConfig |= 1 << 15;
|
||||
newConfig |= 1 << 20;
|
||||
}
|
||||
/* Else, force the last used boot options unless a payload button or A/L/R are pressed
|
||||
or the no-forcing flag is set */
|
||||
else if(!(pressed & OVERRIDE_BUTTONS) && !CONFIG(15, 1))
|
||||
else if(!(pressed & OVERRIDE_BUTTONS) && !CONFIG(20, 1))
|
||||
{
|
||||
mode = CONFIG(12, 1);
|
||||
emuNAND = CONFIG(13, 3);
|
||||
nandType = CONFIG(16, 3);
|
||||
firmSource = CONFIG(18, 1);
|
||||
needConfig = 0;
|
||||
}
|
||||
}
|
||||
@ -121,187 +139,147 @@ void setupCFW(void)
|
||||
|
||||
//If no configuration file exists or SELECT is held, load configuration menu
|
||||
if(needConfig == 2 || (pressed & BUTTON_SELECT))
|
||||
configureCFW(configPath, patchedFirms);
|
||||
configureCFW(configPath);
|
||||
|
||||
//If screens are inited or the corresponding option is set, load splash screen
|
||||
if(PDN_GPU_CNT != 1 || CONFIG(7, 1)) loadSplash();
|
||||
if(PDN_GPU_CNT != 1 || CONFIG(6, 1)) loadSplash();
|
||||
|
||||
/* If L is pressed, or L or R are not pressed when it is the default FIRM,
|
||||
boot 9.0 FIRM */
|
||||
mode = CONFIG(3, 1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) :
|
||||
((pressed & BUTTON_L1) ? 0 : 1);
|
||||
//Determine if we need to boot an emuNAND or sysNAND
|
||||
nandType = (pressed & BUTTON_L1) ? autoBootSys : ((pressed & BUTTON_R1) ? updatedSys : !autoBootSys);
|
||||
|
||||
/* If L or R aren't pressed on a 9.0/9.2 sysNAND, or the 9.0 FIRM is selected
|
||||
or R is pressed on a > 9.2 sysNAND, boot emuNAND */
|
||||
if((updatedSys && (!mode || (pressed & BUTTON_R1))) || (!updatedSys && mode && !(pressed & BUTTON_R1)))
|
||||
/* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
|
||||
or vice-versa, boot the second emuNAND */
|
||||
if(nandType && ((!(pressed & BUTTON_B)) == CONFIG(3, 1))) nandType++;
|
||||
|
||||
//Determine the NAND we should take the FIRM from
|
||||
firmSource = (pressed & BUTTON_R1) ? !nandType : (nandType != 0);
|
||||
}
|
||||
}
|
||||
|
||||
//If we need to boot emuNAND, make sure it exists
|
||||
if(nandType)
|
||||
{
|
||||
/* If not 9.0 FIRM and the second emuNAND is set as default and B isn't pressed, or vice-versa,
|
||||
attempt to boot it */
|
||||
emuNAND = (mode && ((!(pressed & BUTTON_B)) == CONFIG(4, 1))) ? 2 : 1;
|
||||
}
|
||||
else emuNAND = 0;
|
||||
|
||||
/* If tha FIRM patches version is different or user switched to/from A9LH,
|
||||
delete all patched FIRMs */
|
||||
if((tempConfig & 0xFF0000) != (config & 0xFF0000))
|
||||
deleteFirms(patchedFirms, sizeof(patchedFirms) / sizeof(char *));
|
||||
getEmunandSect(&emuOffset, &emuHeader, &nandType);
|
||||
if(!nandType) firmSource = 0;
|
||||
}
|
||||
|
||||
u32 usePatchedFirmSet = CONFIG(1, 1);
|
||||
//Same if we're using emuNAND as the FIRM source
|
||||
else if(firmSource)
|
||||
getEmunandSect(&emuOffset, &emuHeader, &firmSource);
|
||||
|
||||
while(1)
|
||||
if(!bootType)
|
||||
{
|
||||
/* Determine which patched FIRM we need to write or attempt to use (if any).
|
||||
Patched 9.0 FIRM is only needed if "Use pre-patched FIRMs" is set */
|
||||
selectedFirm = mode ? (emuNAND ? (emuNAND == 1 ? 2 : 3) : 1) :
|
||||
(usePatchedFirmSet ? 4 : 0);
|
||||
|
||||
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it
|
||||
if(usePatchedFirmSet && fileExists(patchedFirms[selectedFirm - 1]))
|
||||
usePatchedFirm = 1;
|
||||
|
||||
/* If the user is booting EmuNAND but the chosen one is not found,
|
||||
force 9.6/10.x FIRM and re-detect the patched FIRMs */
|
||||
else if(emuNAND && !getEmunandSect(&emuOffset, &emuHeader, &emuNAND))
|
||||
{
|
||||
mode = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
tempConfig |= (emuNAND << 13) | (mode << 12);
|
||||
newConfig |= (nandType << 16) | (firmSource << 18);
|
||||
|
||||
/* If the boot configuration is different from previously, overwrite it.
|
||||
Just the no-forcing flag being set is not enough */
|
||||
if((tempConfig & 0xFF7000) != (config & 0xFFF000))
|
||||
if((newConfig & 0xEF0000) != (config & 0xFF0000))
|
||||
{
|
||||
//Preserve user settings (first 12 bits)
|
||||
tempConfig |= config & 0xFFF;
|
||||
//Preserve user settings (first 2 bytes)
|
||||
newConfig |= config & 0xFFFF;
|
||||
|
||||
fileWrite(&tempConfig, configPath, 3);
|
||||
fileWrite(&newConfig, configPath, 3);
|
||||
}
|
||||
}
|
||||
|
||||
loadFirm(firmType, firmType == 1 && (nandType == 2 || updatedSys == !nandType));
|
||||
|
||||
if(firmType == 1) patchNativeFirm(firmType, nandType, emuHeader, a9lhInstalled);
|
||||
else patchTwlAgbFirm(firmType);
|
||||
|
||||
launchFirm(bootType);
|
||||
}
|
||||
|
||||
//Load FIRM into FCRAM
|
||||
void loadFirm(void)
|
||||
static inline void loadFirm(u32 firmType, u32 externalFirm)
|
||||
{
|
||||
//If not using an A9LH setup or the patched FIRM, load 9.0 FIRM from NAND
|
||||
if(!usePatchedFirm && !a9lhSetup && !mode)
|
||||
{
|
||||
//Read FIRM from NAND and write to FCRAM
|
||||
firmSize = console ? 0xF2000 : 0xE9000;
|
||||
nandFirm0((u8 *)firm, firmSize, console);
|
||||
|
||||
//Check for correct decryption
|
||||
if(memcmp(firm, "FIRM", 4) != 0)
|
||||
error("Couldn't decrypt NAND FIRM0 (O3DS not on 9.x?)");
|
||||
}
|
||||
|
||||
//Load FIRM from SD
|
||||
else
|
||||
{
|
||||
const char *path = usePatchedFirm ? patchedFirms[selectedFirm - 1] :
|
||||
(mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin");
|
||||
firmSize = fileSize(path);
|
||||
if(!firmSize) error(mode ? "aurei/firmware.bin doesn't exist" :
|
||||
"aurei/firmware90.bin doesn't exist");
|
||||
fileRead(firm, path, firmSize);
|
||||
}
|
||||
u32 firmSize;
|
||||
|
||||
section = firm->section;
|
||||
|
||||
if(externalFirm)
|
||||
{
|
||||
const char *path = "/aurei/firmware.bin";
|
||||
firmSize = fileSize(path);
|
||||
|
||||
if(firmSize)
|
||||
{
|
||||
fileRead(firm, path, firmSize);
|
||||
|
||||
//Check that the loaded FIRM matches the console
|
||||
if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68))
|
||||
error(mode ? "aurei/firmware.bin doesn't match this console,\nor it's encrypted" :
|
||||
"aurei/firmware90.bin doesn't match this console,\nor it's encrypted");
|
||||
error("aurei/firmware.bin doesn't match this console,\nor it's encrypted");
|
||||
}
|
||||
}
|
||||
else firmSize = 0;
|
||||
|
||||
arm9Section = (u8 *)firm + section[2].offset;
|
||||
|
||||
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||
if(console && !usePatchedFirm)
|
||||
if(!firmSize)
|
||||
{
|
||||
decryptArm9Bin(arm9Section, mode);
|
||||
firm->arm9Entry = (u8 *)0x801B01C;
|
||||
firmRead((u8 *)firm, firmFolders[firmType - 1][console]);
|
||||
decryptExeFs((u8 *)firm);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void patchTwlAgb(u32 whichFirm)
|
||||
static inline void patchNativeFirm(u32 firmType, u32 nandType, u32 emuHeader, u32 a9lhInstalled)
|
||||
{
|
||||
static firmHeader *const twlAgbFirm = (firmHeader *)0x25000000;
|
||||
u8 *arm9Section = (u8 *)firm + section[2].offset;
|
||||
|
||||
const char *path = whichFirm ? "/aurei/firmware_agb.bin" : "/aurei/firmware_twl.bin";
|
||||
u32 size = fileSize(path);
|
||||
|
||||
//Skip patching if the file doesn't exist
|
||||
if(!size) return;
|
||||
|
||||
fileRead(twlAgbFirm, path, size);
|
||||
|
||||
static const firmSectionHeader *twlAgbSection = twlAgbFirm->section;
|
||||
|
||||
//Check that the loaded FIRM matches the console
|
||||
if((((u32)twlAgbSection[3].address >> 8) & 0xFF) != (console ? 0x60 : 0x68))
|
||||
error(whichFirm ? "aurei/firmware_agb.bin doesn't match this\nconsole, or it's encrypted" :
|
||||
"aurei/firmware_twl.bin doesn't match this\nconsole, or it's encrypted");
|
||||
|
||||
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||
if(console)
|
||||
{
|
||||
decryptArm9Bin((u8 *)twlAgbFirm + twlAgbSection[3].offset, 0);
|
||||
twlAgbFirm->arm9Entry = (u8 *)0x801301C;
|
||||
//Determine if we're booting the 9.0 FIRM
|
||||
if(arm9Section[0x51] == 0xFF) firmType--;
|
||||
|
||||
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||
arm9Loader((u8 *)firm + section[2].offset, firmType);
|
||||
firm->arm9Entry = (u8 *)0x801B01C;
|
||||
}
|
||||
|
||||
static const patchData twlPatches[] = {
|
||||
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
||||
{{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1},
|
||||
{{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2},
|
||||
{{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2},
|
||||
{{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2},
|
||||
{{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2},
|
||||
{{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2},
|
||||
{{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1},
|
||||
{{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1}
|
||||
},
|
||||
agbPatches[] = {
|
||||
{{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
||||
{{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1}
|
||||
};
|
||||
|
||||
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
|
||||
if the matching option was enabled (keep it as last) */
|
||||
u32 numPatches = whichFirm ? (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(6, 1)) :
|
||||
(sizeof(twlPatches) / sizeof(patchData));
|
||||
const patchData *patches = whichFirm ? agbPatches : twlPatches;
|
||||
|
||||
//Patch
|
||||
for(u32 i = 0; i < numPatches; i++)
|
||||
else
|
||||
{
|
||||
switch(patches[i].type)
|
||||
{
|
||||
case 0:
|
||||
memcpy((u8 *)twlAgbFirm + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
|
||||
break;
|
||||
case 2:
|
||||
*(u16 *)((u8 *)twlAgbFirm + patches[i].offset[console] + 2) = 0;
|
||||
case 1:
|
||||
*(u16 *)((u8 *)twlAgbFirm + patches[i].offset[console]) = patches[i].patch.type1;
|
||||
break;
|
||||
}
|
||||
//Determine if we're booting the 9.0 FIRM
|
||||
u8 firm90Hash[0x10] = {0x27, 0x2D, 0xFE, 0xEB, 0xAF, 0x3F, 0x6B, 0x3B, 0xF5, 0xDE, 0x4C, 0x41, 0xDE, 0x95, 0x27, 0x6A};
|
||||
if(memcmp(section[2].hash, firm90Hash, 0x10) == 0) firmType--;
|
||||
}
|
||||
|
||||
fileWrite(twlAgbFirm, whichFirm ? patchedFirms[5] : patchedFirms[4], size);
|
||||
if(firmType == 1 || nandType)
|
||||
{
|
||||
//Find the Process9 NCCH location
|
||||
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
|
||||
|
||||
//Apply emuNAND patches
|
||||
if(nandType) patchEmuNAND(arm9Section, proc9Offset, emuHeader);
|
||||
|
||||
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
|
||||
if(firmType == 1) patchReboots(arm9Section, proc9Offset);
|
||||
}
|
||||
|
||||
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
|
||||
if(a9lhInstalled && !nandType)
|
||||
{
|
||||
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
|
||||
*writeOffset = writeBlock[0];
|
||||
*(writeOffset + 1) = writeBlock[1];
|
||||
}
|
||||
|
||||
//Apply signature checks patches
|
||||
u32 sigOffset,
|
||||
sigOffset2;
|
||||
|
||||
getSigChecks(arm9Section, section[2].size, &sigOffset, &sigOffset2);
|
||||
*(u16 *)sigOffset = sigPatch[0];
|
||||
*(u16 *)sigOffset2 = sigPatch[0];
|
||||
*((u16 *)sigOffset2 + 1) = sigPatch[1];
|
||||
|
||||
//Replace the FIRM loader with the injector
|
||||
injectLoader();
|
||||
}
|
||||
|
||||
//NAND redirection
|
||||
static inline void patchEmuNAND(u8 *proc9Offset)
|
||||
static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader)
|
||||
{
|
||||
//Copy emuNAND code
|
||||
//Copy nandType code
|
||||
void *emuCodeOffset = getEmuCode(proc9Offset);
|
||||
memcpy(emuCodeOffset, emunand, emunand_size);
|
||||
|
||||
//Add the data of the found emuNAND
|
||||
//Add the data of the found nandType
|
||||
u32 *pos_offset = (u32 *)memsearch(emuCodeOffset, "NAND", emunand_size, 4);
|
||||
u32 *pos_header = (u32 *)memsearch(emuCodeOffset, "NCSD", emunand_size, 4);
|
||||
*pos_offset = emuOffset;
|
||||
@ -334,7 +312,7 @@ static inline void patchEmuNAND(u8 *proc9Offset)
|
||||
*(mpuOffset + 9) = mpuPatch[2];
|
||||
}
|
||||
|
||||
static inline void patchReboots(u8 *proc9Offset)
|
||||
static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset)
|
||||
{
|
||||
//Calculate offset for the firmlaunch code
|
||||
void *rebootOffset = getReboot(arm9Section, section[2].size);
|
||||
@ -348,13 +326,6 @@ static inline void patchReboots(u8 *proc9Offset)
|
||||
//Put the fOpen offset in the right location
|
||||
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
|
||||
*pos_fopen = fOpenOffset;
|
||||
|
||||
//Patch path for emuNAND-patched FIRM
|
||||
if(emuNAND)
|
||||
{
|
||||
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4);
|
||||
memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void injectLoader(void)
|
||||
@ -376,71 +347,70 @@ static inline void injectLoader(void)
|
||||
}
|
||||
}
|
||||
|
||||
//Patches
|
||||
void patchFirm(void)
|
||||
static inline void patchTwlAgbFirm(u32 firmType)
|
||||
{
|
||||
if(mode)
|
||||
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
|
||||
if(console)
|
||||
{
|
||||
//Only patch AGB_FIRM/TWL_FIRM if the patched ones don't already exist
|
||||
if(!fileExists(patchedFirms[4])) patchTwlAgb(0);
|
||||
if(!fileExists(patchedFirms[5])) patchTwlAgb(1);
|
||||
arm9Loader((u8 *)firm + section[3].offset, 0);
|
||||
firm->arm9Entry = (u8 *)0x801301C;
|
||||
}
|
||||
|
||||
//Skip patching
|
||||
if(usePatchedFirm) return;
|
||||
static const patchData twlPatches[] = {
|
||||
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
||||
{{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1},
|
||||
{{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2},
|
||||
{{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2},
|
||||
{{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2},
|
||||
{{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2},
|
||||
{{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2},
|
||||
{{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1},
|
||||
{{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1}
|
||||
},
|
||||
agbPatches[] = {
|
||||
{{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
|
||||
{{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1}
|
||||
};
|
||||
|
||||
if(mode || emuNAND)
|
||||
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
|
||||
if the matching option was enabled (keep it as last) */
|
||||
u32 numPatches = firmType == 2 ? (sizeof(twlPatches) / sizeof(patchData)) : (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(5, 1));
|
||||
const patchData *patches = firmType == 2 ? twlPatches : agbPatches;
|
||||
|
||||
//Patch
|
||||
for(u32 i = 0; i < numPatches; i++)
|
||||
{
|
||||
//Find the Process9 NCCH location
|
||||
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
|
||||
|
||||
//Apply emuNAND patches
|
||||
if(emuNAND) patchEmuNAND(proc9Offset);
|
||||
|
||||
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
|
||||
if(mode) patchReboots(proc9Offset);
|
||||
}
|
||||
|
||||
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
|
||||
if(a9lhSetup && !emuNAND)
|
||||
switch(patches[i].type)
|
||||
{
|
||||
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
|
||||
*writeOffset = writeBlock[0];
|
||||
*(writeOffset + 1) = writeBlock[1];
|
||||
case 0:
|
||||
memcpy((u8 *)firm + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
|
||||
break;
|
||||
case 2:
|
||||
*(u16 *)((u8 *)firm + patches[i].offset[console] + 2) = 0;
|
||||
case 1:
|
||||
*(u16 *)((u8 *)firm + patches[i].offset[console]) = patches[i].patch.type1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Apply signature checks patches
|
||||
u32 sigOffset,
|
||||
sigOffset2;
|
||||
|
||||
getSigChecks(arm9Section, section[2].size, &sigOffset, &sigOffset2);
|
||||
*(u16 *)sigOffset = sigPatch[0];
|
||||
*(u16 *)sigOffset2 = sigPatch[0];
|
||||
*((u16 *)sigOffset2 + 1) = sigPatch[1];
|
||||
|
||||
//Replace the FIRM loader with the injector
|
||||
injectLoader();
|
||||
|
||||
//Write patched FIRM to SD if needed
|
||||
if(selectedFirm)
|
||||
if(!fileWrite(firm, patchedFirms[selectedFirm - 1], firmSize))
|
||||
error("Couldn't write the patched FIRM (no free space?)");
|
||||
}
|
||||
|
||||
void launchFirm(void)
|
||||
static inline void launchFirm(u32 bootType)
|
||||
{
|
||||
if(console && mode) setKeyXs(arm9Section);
|
||||
|
||||
//Copy firm partitions to respective memory locations
|
||||
memcpy(section[0].address, (u8 *)firm + section[0].offset, section[0].size);
|
||||
memcpy(section[1].address, (u8 *)firm + section[1].offset, section[1].size);
|
||||
memcpy(section[2].address, arm9Section, section[2].size);
|
||||
for(u32 i = 0; i < 4 && section[i].size; i++)
|
||||
memcpy(section[i].address, (u8 *)firm + section[i].offset, section[i].size);
|
||||
|
||||
//Fixes N3DS 3D
|
||||
//Determine the ARM11 entry to use
|
||||
vu32 *arm11;
|
||||
if(bootType) arm11 = (u32 *)0x1FFFFFFC;
|
||||
else
|
||||
{
|
||||
deinitScreens();
|
||||
arm11 = (u32 *)0x1FFFFFF8;
|
||||
}
|
||||
|
||||
//Set ARM11 kernel entrypoint
|
||||
*(vu32 *)0x1FFFFFF8 = (u32)firm->arm11Entry;
|
||||
*arm11 = (u32)firm->arm11Entry;
|
||||
|
||||
//Final jump to arm9 kernel
|
||||
((void (*)())firm->arm9Entry)();
|
||||
|
@ -38,7 +38,10 @@ typedef struct patchData {
|
||||
u32 type;
|
||||
} patchData;
|
||||
|
||||
void setupCFW(void);
|
||||
void loadFirm(void);
|
||||
void patchFirm(void);
|
||||
void launchFirm(void);
|
||||
static inline void loadFirm(u32 firmType, u32 externalFirm);
|
||||
static inline void patchNativeFirm(u32 firmType, u32 emuNAND, u32 emuHeader, u32 a9lhSetup);
|
||||
static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader);
|
||||
static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset);
|
||||
static inline void injectLoader(void);
|
||||
static inline void patchTwlAgbFirm(u32 firmType);
|
||||
static inline void launchFirm(u32 bootType);
|
64
source/fs.c
64
source/fs.c
@ -5,13 +5,16 @@
|
||||
*/
|
||||
|
||||
#include "fs.h"
|
||||
#include "memory.h"
|
||||
#include "fatfs/ff.h"
|
||||
|
||||
static FATFS fs;
|
||||
static FATFS sdFs,
|
||||
nandFs;
|
||||
|
||||
u32 mountSD(void)
|
||||
u32 mountFs(void)
|
||||
{
|
||||
if(f_mount(&fs, "0:", 1) != FR_OK) return 0;
|
||||
if(f_mount(&sdFs, "0:", 1) != FR_OK) return 0;
|
||||
f_mount(&nandFs, "1:", 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -68,7 +71,58 @@ u32 fileExists(const char *path)
|
||||
return exists;
|
||||
}
|
||||
|
||||
void fileDelete(const char *path)
|
||||
void firmRead(u8 *dest, const char *firmFolder)
|
||||
{
|
||||
f_unlink(path);
|
||||
char path[48] = "1:/title/00040138/00000000/content";
|
||||
memcpy(&path[18], firmFolder, 8);
|
||||
|
||||
DIR dir;
|
||||
FILINFO info = { .lfname = NULL };
|
||||
|
||||
f_opendir(&dir, path);
|
||||
|
||||
u32 id = 0;
|
||||
|
||||
//Parse the target directory
|
||||
while(f_readdir(&dir, &info) == FR_OK)
|
||||
{
|
||||
//We've parsed the whole folder
|
||||
if(!info.fname[0]) break;
|
||||
|
||||
//Not a cxi
|
||||
if(info.fname[9] != 'a' && info.fname[9] != 'A') continue;
|
||||
|
||||
//Convert the .app name to an integer
|
||||
u32 tempId = 0;
|
||||
for(char *tmp = info.fname; (*tmp) != '.'; tmp++)
|
||||
{
|
||||
if((*tmp) > '9') tempId = (tempId << 4) + ((*tmp) - 'A') + 9;
|
||||
else tempId = (tempId << 4) + (*tmp) - '0';
|
||||
}
|
||||
|
||||
//Found a newer cxi
|
||||
if(tempId > id) id = tempId;
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
//Complete the string with the .app name
|
||||
memcpy(&path[34], "/00000000.app", 14);
|
||||
|
||||
//Last digit of the .app
|
||||
u32 i = 42;
|
||||
|
||||
//Convert back the .app name from integer to array
|
||||
while(id > 15)
|
||||
{
|
||||
u32 remainder = (id % 16);
|
||||
if(remainder > 9) path[i] = remainder - 9 + 'A';
|
||||
else path[i] = remainder + '0';
|
||||
id /= 16;
|
||||
i--;
|
||||
}
|
||||
if(id > 9) path[i] = id - 9 + 'A';
|
||||
else path[i] = id + '0';
|
||||
|
||||
fileRead(dest, path, 0);
|
||||
}
|
@ -8,9 +8,9 @@
|
||||
|
||||
#include "types.h"
|
||||
|
||||
u32 mountSD(void);
|
||||
u32 mountFs(void);
|
||||
u32 fileRead(void *dest, const char *path, u32 size);
|
||||
u32 fileWrite(const void *buffer, const char *path, u32 size);
|
||||
u32 fileSize(const char *path);
|
||||
u32 fileExists(const char *path);
|
||||
void fileDelete(const char *path);
|
||||
void firmRead(u8 *dest, const char *firmFolder);
|
@ -1,19 +0,0 @@
|
||||
/*
|
||||
* main.c
|
||||
* by Reisyukaku / Aurora Wright
|
||||
* Copyright (c) 2016 All Rights Reserved
|
||||
*
|
||||
* Minimalist CFW for (N)3DS
|
||||
*/
|
||||
|
||||
#include "fs.h"
|
||||
#include "firm.h"
|
||||
|
||||
void main(void)
|
||||
{
|
||||
mountSD();
|
||||
setupCFW();
|
||||
loadFirm();
|
||||
patchFirm();
|
||||
launchFirm();
|
||||
}
|
@ -16,7 +16,7 @@
|
||||
|
||||
#define SCREENINIT_ADDRESS 0x24F03000
|
||||
|
||||
static vu32 *const arm11 = (u32 *)0x1FFFFFF8;
|
||||
vu32 *arm11Entry = (u32 *)0x1FFFFFF8;
|
||||
|
||||
void deinitScreens(void)
|
||||
{
|
||||
@ -26,7 +26,7 @@ void deinitScreens(void)
|
||||
__asm(".word 0xF10C01C0");
|
||||
|
||||
//Clear ARM11 entry offset
|
||||
*arm11 = 0;
|
||||
*arm11Entry = 0;
|
||||
|
||||
//Shutdown LCDs
|
||||
*(vu32 *)0x10202A44 = 0;
|
||||
@ -34,16 +34,16 @@ void deinitScreens(void)
|
||||
*(vu32 *)0x10202014 = 0;
|
||||
|
||||
//Wait for the entry to be set
|
||||
while(!*arm11);
|
||||
while(!*arm11Entry);
|
||||
|
||||
//Jump to it
|
||||
((void (*)())*arm11)();
|
||||
((void (*)())*arm11Entry)();
|
||||
}
|
||||
|
||||
if(PDN_GPU_CNT != 1)
|
||||
{
|
||||
*arm11 = (u32)ARM11;
|
||||
while(*arm11);
|
||||
*arm11Entry = (u32)ARM11;
|
||||
while(*arm11Entry);
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,10 +54,10 @@ void initScreens(void)
|
||||
memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size);
|
||||
|
||||
//Write brightness level for the stub to pick up
|
||||
*(vu32 *)(SCREENINIT_ADDRESS + 8) = CONFIG(10, 3);
|
||||
*(vu32 *)(SCREENINIT_ADDRESS + 8) = CONFIG(14, 3);
|
||||
|
||||
*arm11 = SCREENINIT_ADDRESS;
|
||||
while(*arm11);
|
||||
*arm11Entry = SCREENINIT_ADDRESS;
|
||||
while(*arm11Entry);
|
||||
|
||||
//Turn on backlight
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
||||
|
@ -2,15 +2,20 @@
|
||||
.align 4
|
||||
.global _start
|
||||
_start:
|
||||
b start
|
||||
|
||||
.word 0
|
||||
|
||||
start:
|
||||
@ Change the stack pointer
|
||||
mov sp, #0x27000000
|
||||
|
||||
@ Give read/write access to all the memory regions
|
||||
ldr r0, =0x33333333
|
||||
mcr p15, 0, r0, c5, c0, 2 @ write data access
|
||||
mcr p15, 0, r0, c5, c0, 3 @ write instruction access
|
||||
ldr r5, =0x33333333
|
||||
mcr p15, 0, r5, c5, c0, 2 @ write data access
|
||||
mcr p15, 0, r5, c5, c0, 3 @ write instruction access
|
||||
|
||||
@ Set MPU permissions and cache settings
|
||||
@ Sets MPU permissions and cache settings
|
||||
ldr r0, =0xFFFF001D @ ffff0000 32k
|
||||
ldr r1, =0x01FF801D @ 01ff8000 32k
|
||||
ldr r2, =0x08000027 @ 08000000 1M
|
||||
@ -28,16 +33,16 @@ _start:
|
||||
mcr p15, 0, r6, c6, c6, 0
|
||||
mcr p15, 0, r7, c6, c7, 0
|
||||
mov r0, #0x25
|
||||
mcr p15, 0, r0, c2, c0, 0 @ data cacheable
|
||||
mcr p15, 0, r0, c2, c0, 1 @ instruction cacheable
|
||||
mcr p15, 0, r0, c3, c0, 0 @ data bufferable
|
||||
mcr p15, 0, r0, c3, c0, 0 @ Write bufferable 0, 2, 5
|
||||
mcr p15, 0, r0, c2, c0, 0 @ Data cacheable 0, 2, 5
|
||||
mcr p15, 0, r0, c2, c0, 1 @ Inst cacheable 0, 2, 5
|
||||
|
||||
@ Enable caches
|
||||
mrc p15, 0, r0, c1, c0, 0 @ read control register
|
||||
orr r0, r0, #(1<<12) @ - instruction cache enable
|
||||
orr r0, r0, #(1<<2) @ - data cache enable
|
||||
orr r0, r0, #(1<<0) @ - mpu enable
|
||||
mcr p15, 0, r0, c1, c0, 0 @ write control register
|
||||
mrc p15, 0, r4, c1, c0, 0 @ read control register
|
||||
orr r4, r4, #(1<<12) @ - instruction cache enable
|
||||
orr r4, r4, #(1<<2) @ - data cache enable
|
||||
orr r4, r4, #(1<<0) @ - mpu enable
|
||||
mcr p15, 0, r4, c1, c0, 0 @ write control register
|
||||
|
||||
@ Flush caches
|
||||
mov r0, #0
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "utils.h"
|
||||
#include "screeninit.h"
|
||||
#include "draw.h"
|
||||
#include "fs.h"
|
||||
#include "i2c.h"
|
||||
#include "buttons.h"
|
||||
|
||||
@ -37,15 +36,6 @@ u32 waitInput(void)
|
||||
return key;
|
||||
}
|
||||
|
||||
void deleteFirms(const char *firmPaths[], u32 firms)
|
||||
{
|
||||
while(firms)
|
||||
{
|
||||
fileDelete(firmPaths[firms - 1]);
|
||||
firms--;
|
||||
}
|
||||
}
|
||||
|
||||
void error(const char *message)
|
||||
{
|
||||
initScreens();
|
||||
|
@ -9,5 +9,4 @@
|
||||
#include "types.h"
|
||||
|
||||
u32 waitInput(void);
|
||||
void deleteFirms(const char *firmPaths[], u32 firms);
|
||||
void error(const char *message);
|
Reference in New Issue
Block a user