Use iomemcpy for registers (thanks @profi200)

This commit is contained in:
d0k3 2019-04-17 00:08:43 +02:00
parent afd2c6593c
commit 151e6389ac
10 changed files with 167 additions and 31 deletions

View File

@ -0,0 +1,32 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2017 derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !__ASSEMBLER__
#error Only include this in assembly files!
#endif
.macro ASM_FUNC name
.section .text.\name, "ax", %progbits
.global \name
.type \name %function
.align 2
\name:
.endm

26
arm9/source/common/mmio.h Normal file
View File

@ -0,0 +1,26 @@
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 Aurora Wright, TuxSH, derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Based on https://github.com/AuroraWright/Luma3DS/blob/master/arm9/source/alignedseqmemcpy.s
#include "common.h"
void iomemcpy(vu32 *restrict dst, const vu32 *restrict src, u32 size);
void iomemset(vu32 *ptr, u32 value, u32 size);

87
arm9/source/common/mmio.s Normal file
View File

@ -0,0 +1,87 @@
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 Aurora Wright, TuxSH, derrek, profi200
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@ Based on https://github.com/AuroraWright/Luma3DS/blob/master/arm9/source/alignedseqmemcpy.s
#include "asmfunc.h"
.arm
.cpu arm946e-s
.fpu softvfp
@ void iomemcpy(vu32 *restrict dst, const vu32 *restrict src, u32 size)
ASM_FUNC iomemcpy
bics r12, r2, #31
beq iomemcpy_test_words
stmfd sp!, {r4-r10}
iomemcpy_blocks_lp:
ldmia r1!, {r3-r10}
stmia r0!, {r3-r10}
subs r12, #32
bne iomemcpy_blocks_lp
ldmfd sp!, {r4-r10}
iomemcpy_test_words:
ands r12, r2, #28
beq iomemcpy_halfword_byte
iomemcpy_words_lp:
ldr r3, [r1], #4
str r3, [r0], #4
subs r12, #4
bne iomemcpy_words_lp
iomemcpy_halfword_byte:
tst r2, #2
ldrneh r3, [r1], #2
strneh r3, [r0], #2
tst r2, #1
ldrneb r3, [r1]
strneb r3, [r0]
bx lr
@ void iomemset(vu32 *ptr, u32 value, u32 size)
ASM_FUNC iomemset
bics r12, r2, #31
beq iomemset_test_words
stmfd sp!, {r4-r9}
mov r3, r1
mov r4, r1
mov r5, r1
mov r6, r1
mov r7, r1
mov r8, r1
mov r9, r1
iomemset_blocks_lp:
stmia r0!, {r1, r3-r9}
subs r12, #32
bne iomemset_blocks_lp
ldmfd sp!, {r4-r9}
iomemset_test_words:
ands r12, r2, #28
beq iomemset_halfword_byte
iomemset_words_lp:
str r1, [r0], #4
subs r12, #4
bne iomemset_words_lp
iomemset_halfword_byte:
tst r2, #2
strneh r1, [r0], #2
tst r2, #1
strneb r1, [r0]
bx lr

View File

@ -16,15 +16,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/*
* To ensure correct functionality, the builtin memcpy should perform a sequential copy.
* If not, it should be replaced with a different reimplementation that does for sure act sequential.
* Or alternatively, it's own memcpy with it's own name, say perhaps seqmemcpy, and memcpy calls replaced.
*/
#include "common.h" #include "common.h"
#include "rsa.h" #include "rsa.h"
#include "sha.h" #include "sha.h"
#include "mmio.h"
@ -40,9 +35,9 @@
#define REGs_RSA_SLOT2 ((vu32*)(RSA_REGS_BASE + 0x120)) #define REGs_RSA_SLOT2 ((vu32*)(RSA_REGS_BASE + 0x120))
#define REGs_RSA_SLOT3 ((vu32*)(RSA_REGS_BASE + 0x130)) #define REGs_RSA_SLOT3 ((vu32*)(RSA_REGS_BASE + 0x130))
#define rsaSlots ((RsaSlot*)(RSA_REGS_BASE + 0x100)) #define rsaSlots ((RsaSlot*)(RSA_REGS_BASE + 0x100))
#define REG_RSA_EXP ((vu32*)(RSA_REGS_BASE + 0x200)) #define REGs_RSA_EXP ((vu32*)(RSA_REGS_BASE + 0x200))
#define REG_RSA_MOD ( (RSA_REGS_BASE + 0x400)) #define REGs_RSA_MOD ((vu32*)(RSA_REGS_BASE + 0x400))
#define REG_RSA_TXT ( (RSA_REGS_BASE + 0x800)) #define REGs_RSA_TXT ((vu32*)(RSA_REGS_BASE + 0x800))
typedef struct typedef struct
{ {
@ -69,7 +64,7 @@ void RSA_selectKeyslot(u8 keyslot)
REG_RSA_CNT = (REG_RSA_CNT & ~RSA_KEYSLOT(0xFu)) | RSA_KEYSLOT(keyslot); REG_RSA_CNT = (REG_RSA_CNT & ~RSA_KEYSLOT(0xFu)) | RSA_KEYSLOT(keyslot);
} }
bool RSA_setKey2048(u8 keyslot, const u8 *const mod, u32 exp) bool RSA_setKey2048(u8 keyslot, const u32 *const mod, u32 exp)
{ {
RsaSlot *slot = &rsaSlots[keyslot]; RsaSlot *slot = &rsaSlots[keyslot];
rsaWaitBusy(); rsaWaitBusy();
@ -78,35 +73,35 @@ bool RSA_setKey2048(u8 keyslot, const u8 *const mod, u32 exp)
if(!(slot->REG_RSA_SLOTCNT & RSA_KEY_UNK_BIT31)) slot->REG_RSA_SLOTCNT &= ~RSA_KEY_STAT_SET; if(!(slot->REG_RSA_SLOTCNT & RSA_KEY_UNK_BIT31)) slot->REG_RSA_SLOTCNT &= ~RSA_KEY_STAT_SET;
REG_RSA_CNT = RSA_INPUT_NORMAL | RSA_INPUT_BIG | RSA_KEYSLOT(keyslot); REG_RSA_CNT = RSA_INPUT_NORMAL | RSA_INPUT_BIG | RSA_KEYSLOT(keyslot);
memset((void*)REG_RSA_EXP, 0, 0x100 - 4); iomemset(REGs_RSA_EXP, 0, 0x100 - 4);
REG_RSA_EXP[(0x100>>2) - 1] = exp; REGs_RSA_EXP[(0x100>>2) - 1] = exp;
if(slot->REG_RSA_SLOTSIZE != RSA_SLOTSIZE_2048) return false; if(slot->REG_RSA_SLOTSIZE != RSA_SLOTSIZE_2048) return false;
memcpy((void*)REG_RSA_MOD, mod, 0x100); iomemcpy(REGs_RSA_MOD, mod, 0x100);
return true; return true;
} }
bool RSA_decrypt2048(void *const decSig, const void *const encSig) bool RSA_decrypt2048(u32 *const decSig, const u32 *const encSig)
{ {
const u8 keyslot = RSA_GET_KEYSLOT; const u8 keyslot = RSA_GET_KEYSLOT;
rsaWaitBusy(); rsaWaitBusy();
if(!(rsaSlots[keyslot].REG_RSA_SLOTCNT & RSA_KEY_STAT_SET)) return false; if(!(rsaSlots[keyslot].REG_RSA_SLOTCNT & RSA_KEY_STAT_SET)) return false;
REG_RSA_CNT |= RSA_INPUT_NORMAL | RSA_INPUT_BIG; REG_RSA_CNT |= RSA_INPUT_NORMAL | RSA_INPUT_BIG;
memcpy((void*)REG_RSA_TXT, encSig, 0x100); iomemcpy(REGs_RSA_TXT, encSig, 0x100);
REG_RSA_CNT |= RSA_ENABLE; REG_RSA_CNT |= RSA_ENABLE;
rsaWaitBusy(); rsaWaitBusy();
memcpy(decSig, (void*)REG_RSA_TXT, 0x100); iomemcpy(decSig, REGs_RSA_TXT, 0x100);
return true; return true;
} }
bool RSA_verify2048(const u32 *const encSig, const u32 *const data, u32 size) bool RSA_verify2048(const u32 *const encSig, const u32 *const data, u32 size)
{ {
u8 decSig[0x100]; alignas(4) u8 decSig[0x100];
if(!RSA_decrypt2048(decSig, encSig)) return false; if(!RSA_decrypt2048((u32*)(void*)decSig, encSig)) return false;
if(decSig[0] != 0x00 || decSig[1] != 0x01) return false; if(decSig[0] != 0x00 || decSig[1] != 0x01) return false;

View File

@ -66,7 +66,7 @@ void RSA_selectKeyslot(u8 keyslot);
* *
* @return Returns true on success, false otherwise. * @return Returns true on success, false otherwise.
*/ */
bool RSA_setKey2048(u8 keyslot, const u8 *const mod, u32 exp); bool RSA_setKey2048(u8 keyslot, const u32 *const mod, u32 exp);
/** /**
* @brief Decrypts a RSA 2048 signature. * @brief Decrypts a RSA 2048 signature.
@ -76,7 +76,7 @@ bool RSA_setKey2048(u8 keyslot, const u8 *const mod, u32 exp);
* *
* @return Returns true on success, false otherwise. * @return Returns true on success, false otherwise.
*/ */
bool RSA_decrypt2048(void *const decSig, const void *const encSig); bool RSA_decrypt2048(u32 *const decSig, const u32 *const encSig);
/** /**
* @brief Verifies a RSA 2048 SHA 256 signature. * @brief Verifies a RSA 2048 SHA 256 signature.

View File

@ -1,9 +1,5 @@
/*
* To ensure correct functionality, the builtin memcpy should perform a sequential copy.
* If not, it should be replaced with a different reimplementation that does for sure act sequential.
* Or alternatively, it's own memcpy with it's own name, say perhaps seqmemcpy, and memcpy calls replaced, as well the line "*((_sha_block*)REG_SHAINFIFO) = *((const _sha_block*)src32);" inside sha_update, to call explicitly seqmemcpy like, "seqmemcpy(REG_SHAINFIFO, src32, 0x40);".
*/
#include "sha.h" #include "sha.h"
#include "mmio.h"
typedef struct typedef struct
{ {
@ -27,7 +23,7 @@ void sha_update(const void* src, u32 size)
size -= 0x40; size -= 0x40;
} }
while(*REG_SHACNT & 1); while(*REG_SHACNT & 1);
if(size) memcpy((void*)REG_SHAINFIFO, src32, size); if(size) iomemcpy((void*)REG_SHAINFIFO, src32, size);
} }
void sha_get(void* res) { void sha_get(void* res) {
@ -36,7 +32,7 @@ void sha_get(void* res) {
*REG_SHACNT = (*REG_SHACNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND; *REG_SHACNT = (*REG_SHACNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
while(*REG_SHACNT & SHA_FINAL_ROUND); while(*REG_SHACNT & SHA_FINAL_ROUND);
while(*REG_SHACNT & 1); while(*REG_SHACNT & 1);
if (hash_size) memcpy(res, (void*)REG_SHAHASH, hash_size); if (hash_size) iomemcpy(res, (void*)REG_SHAHASH, hash_size);
} }
void sha_quick(void* res, const void* src, u32 size, u32 mode) { void sha_quick(void* res, const void* src, u32 size, u32 mode) {

View File

@ -1,7 +1,7 @@
#include "cert.h" #include "cert.h"
#include "ff.h" #include "ff.h"
u32 LoadCertFromCertDb(u64 offset, Certificate* cert, u8* mod, u32* exp) { u32 LoadCertFromCertDb(u64 offset, Certificate* cert, u32* mod, u32* exp) {
Certificate cert_local; Certificate cert_local;
FIL db; FIL db;
UINT bytes_read; UINT bytes_read;

View File

@ -19,4 +19,4 @@ typedef struct {
u8 padding1[0x34]; u8 padding1[0x34];
} __attribute__((packed)) Certificate; } __attribute__((packed)) Certificate;
u32 LoadCertFromCertDb(u64 offset, Certificate* cert, u8* mod, u32* exp); u32 LoadCertFromCertDb(u64 offset, Certificate* cert, u32* mod, u32* exp);

View File

@ -17,7 +17,7 @@ u32 ValidateTicket(Ticket* ticket) {
u32 ValidateTicketSignature(Ticket* ticket) { u32 ValidateTicketSignature(Ticket* ticket) {
static bool got_modexp = false; static bool got_modexp = false;
static u8 mod[0x100] = { 0 }; static u32 mod[0x100 / 0x4] = { 0 };
static u32 exp = 0; static u32 exp = 0;
if (!got_modexp) { if (!got_modexp) {

View File

@ -16,7 +16,7 @@ u32 ValidateTmd(TitleMetaData* tmd) {
u32 ValidateTmdSignature(TitleMetaData* tmd) { u32 ValidateTmdSignature(TitleMetaData* tmd) {
static bool got_modexp = false; static bool got_modexp = false;
static u8 mod[0x100] = { 0 }; static u32 mod[0x100 / 4] = { 0 };
static u32 exp = 0; static u32 exp = 0;
if (!got_modexp) { if (!got_modexp) {