Implement a PIN-checking system.
Idea and original code by @reworks
This commit is contained in:
parent
e4ed713fce
commit
709aefba5d
@ -28,7 +28,7 @@
|
||||
|
||||
#define BUTTON_R1 (1 << 8)
|
||||
#define BUTTON_L1 (1 << 9)
|
||||
#define BUTTON_A 1
|
||||
#define BUTTON_A (1 << 0)
|
||||
#define BUTTON_B (1 << 1)
|
||||
#define BUTTON_X (1 << 10)
|
||||
#define BUTTON_Y (1 << 11)
|
||||
@ -42,4 +42,5 @@
|
||||
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
|
||||
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y)
|
||||
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_SELECT)
|
||||
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
|
||||
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
|
||||
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | BUTTON_START)
|
@ -25,13 +25,11 @@
|
||||
#include "screen.h"
|
||||
#include "draw.h"
|
||||
#include "fs.h"
|
||||
#include "i2c.h"
|
||||
#include "buttons.h"
|
||||
|
||||
void configureCFW(const char *configPath)
|
||||
{
|
||||
bool needToDeinit = initScreens();
|
||||
|
||||
clearScreens();
|
||||
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
|
||||
drawString("Press A to select, START to save", 10, 30, COLOR_WHITE);
|
||||
|
||||
@ -44,7 +42,8 @@ void configureCFW(const char *configPath)
|
||||
"( ) Enable region/language emu. and ext. .code",
|
||||
"( ) Show current NAND in System Settings",
|
||||
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||
"( ) Enable splash screen with no screen-init" };
|
||||
"( ) Enable splash screen with no screen-init",
|
||||
"( ) Use a PIN" };
|
||||
|
||||
struct multiOption {
|
||||
int posXs[4];
|
||||
@ -202,12 +201,4 @@ void configureCFW(const char *configPath)
|
||||
|
||||
//Wait for the pressed buttons to change
|
||||
while(HID_PAD == BUTTON_START);
|
||||
|
||||
if(needToDeinit)
|
||||
{
|
||||
//Turn off backlight
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x16);
|
||||
deinitScreens();
|
||||
PDN_GPU_CNT = 1;
|
||||
}
|
||||
}
|
@ -294,16 +294,16 @@ static void sha(void *res, const void *src, u32 size, u32 mode)
|
||||
* NAND/FIRM crypto
|
||||
****************************************************************/
|
||||
|
||||
static u8 nandCTR[0x10],
|
||||
nandSlot;
|
||||
static u8 __attribute__((aligned(4))) nandCTR[0x10];
|
||||
static u8 nandSlot;
|
||||
|
||||
static u32 fatStart;
|
||||
|
||||
//Initialize the CTRNAND crypto
|
||||
void ctrNandInit(void)
|
||||
{
|
||||
u8 cid[0x10];
|
||||
u8 shaSum[0x20];
|
||||
u8 __attribute__((aligned(4))) cid[0x10];
|
||||
u8 __attribute__((aligned(4))) shaSum[0x20];
|
||||
|
||||
sdmmc_get_cid(1, (u32 *)cid);
|
||||
sha(shaSum, cid, 0x10, SHA_256_MODE);
|
||||
@ -311,7 +311,7 @@ void ctrNandInit(void)
|
||||
|
||||
if(isN3DS)
|
||||
{
|
||||
u8 keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
|
||||
u8 __attribute__((aligned(4))) 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;
|
||||
@ -326,7 +326,7 @@ void ctrNandInit(void)
|
||||
//Read and decrypt from the selected CTRNAND
|
||||
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
|
||||
{
|
||||
u8 tmpCTR[0x10];
|
||||
u8 __attribute__((aligned(4))) tmpCTR[0x10];
|
||||
memcpy(tmpCTR, nandCTR, 0x10);
|
||||
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
@ -350,8 +350,8 @@ u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
|
||||
//Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY
|
||||
void setRSAMod0DerivedKeys(void)
|
||||
{
|
||||
const u8 keyX0x25[0x10] = {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3},
|
||||
keyY0x2F[0x10] = {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16};
|
||||
const u8 __attribute__((aligned(4))) keyX0x25[0x10] = {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3};
|
||||
const u8 __attribute__((aligned(4))) keyY0x2F[0x10] = {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16};
|
||||
|
||||
aes_setkey(0x25, keyX0x25, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_setkey(0x2F, keyY0x2F, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
@ -394,9 +394,9 @@ void arm9Loader(u8 *arm9Section)
|
||||
}
|
||||
|
||||
//Firm keys
|
||||
u8 keyY[0x10],
|
||||
arm9BinCTR[0x10],
|
||||
arm9BinSlot = a9lVersion ? 0x16 : 0x15;
|
||||
u8 __attribute__((aligned(4))) keyY[0x10];
|
||||
u8 __attribute__((aligned(4))) arm9BinCTR[0x10];
|
||||
u8 arm9BinSlot = a9lVersion ? 0x16 : 0x15;
|
||||
|
||||
//Setup keys needed for arm9bin decryption
|
||||
memcpy(keyY, arm9Section + 0x10, 0x10);
|
||||
@ -410,9 +410,9 @@ void arm9Loader(u8 *arm9Section)
|
||||
|
||||
if(a9lVersion)
|
||||
{
|
||||
const u8 key1[0x10] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8},
|
||||
key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
||||
u8 keyX[0x10];
|
||||
const u8 __attribute__((aligned(4))) key1[0x10] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8};
|
||||
const u8 __attribute__((aligned(4))) key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
|
||||
u8 __attribute__((aligned(4))) keyX[0x10];
|
||||
|
||||
aes_setkey(0x11, a9lVersion == 2 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
aes_use_keyslot(0x11);
|
||||
@ -430,8 +430,8 @@ void arm9Loader(u8 *arm9Section)
|
||||
//Set >=9.6 KeyXs
|
||||
if(a9lVersion == 2)
|
||||
{
|
||||
u8 keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98},
|
||||
decKey[0x10];
|
||||
u8 __attribute__((aligned(4))) keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
|
||||
u8 __attribute__((aligned(4))) decKey[0x10];
|
||||
|
||||
//Set keys 0x19..0x1F keyXs
|
||||
aes_use_keyslot(0x11);
|
||||
@ -442,4 +442,16 @@ void arm9Loader(u8 *arm9Section)
|
||||
keyData[0xF] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void computePINHash(u8 out[32], u8 *in, u32 blockCount)
|
||||
{
|
||||
u8 __attribute__((aligned(4))) cid[0x10];
|
||||
u8 __attribute__((aligned(4))) cipherText[0x10];
|
||||
sdmmc_get_cid(1, (u32 *)cid);
|
||||
|
||||
aes_use_keyslot(4); // console-unique keyslot which keys are set by the Arm9 bootROM
|
||||
aes(cipherText, in, blockCount, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||
|
||||
sha(out, cipherText, 0x10, SHA_256_MODE);
|
||||
}
|
@ -107,4 +107,6 @@ void ctrNandInit(void);
|
||||
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
||||
void setRSAMod0DerivedKeys(void);
|
||||
void decryptExeFs(u8 *inbuf);
|
||||
void arm9Loader(u8 *arm9Section);
|
||||
void arm9Loader(u8 *arm9Section);
|
||||
|
||||
void computePINHash(u8 out[32], u8 *in, u32 blockCount);
|
@ -32,6 +32,8 @@
|
||||
#include "draw.h"
|
||||
#include "screen.h"
|
||||
#include "buttons.h"
|
||||
#include "pin.h"
|
||||
#include "i2c.h"
|
||||
#include "../build/injector.h"
|
||||
|
||||
static firmHeader *const firm = (firmHeader *)0x24000000;
|
||||
@ -44,6 +46,8 @@ bool isN3DS;
|
||||
|
||||
FirmwareSource firmSource;
|
||||
|
||||
PINData pin;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
bool isFirmlaunch,
|
||||
@ -67,6 +71,7 @@ void main(void)
|
||||
|
||||
//Attempt to read the configuration file
|
||||
needConfig = fileRead(&config, configPath) ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
|
||||
bool pinExists = CONFIG(7) && readPin(&pin);
|
||||
|
||||
//Determine if this is a firmlaunch boot
|
||||
if(*(vu8 *)0x23F00005)
|
||||
@ -123,10 +128,19 @@ void main(void)
|
||||
}
|
||||
|
||||
//If no configuration file exists or SELECT is held, load configuration menu
|
||||
if(needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1)))
|
||||
bool loadConfigurationMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
|
||||
bool needToDeinit = false;
|
||||
if(CFG_BOOTENV == 0 || loadConfigurationMenu)
|
||||
{
|
||||
if(loadConfigurationMenu || pinExists) needToDeinit = initScreens();
|
||||
if(pinExists) verifyPin(&pin, true);
|
||||
}
|
||||
if(loadConfigurationMenu)
|
||||
{
|
||||
configureCFW(configPath);
|
||||
|
||||
if(!pinExists && CONFIG(7)) pin = newPin();
|
||||
|
||||
//Zero the last booted FIRM flag
|
||||
CFG_BOOTENV = 0;
|
||||
|
||||
@ -137,6 +151,13 @@ void main(void)
|
||||
//Update pressed buttons
|
||||
pressed = HID_PAD;
|
||||
}
|
||||
if(needToDeinit)
|
||||
{
|
||||
//Turn off backlight
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x16);
|
||||
deinitScreens();
|
||||
PDN_GPU_CNT = 1;
|
||||
}
|
||||
|
||||
if(isA9lh && !CFG_BOOTENV && pressed == SAFE_MODE)
|
||||
{
|
||||
@ -294,7 +315,7 @@ static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32
|
||||
//Apply anti-anti-DG patches
|
||||
patchTitleInstallMinVersionCheck(process9Offset, process9Size);
|
||||
|
||||
//Restore SVCBackdoor
|
||||
//Restore svcBackdoor
|
||||
reimplementSvcBackdoor((u8 *)firm + section[1].offset, section[1].size);
|
||||
}
|
||||
}
|
||||
|
181
source/pin.c
Normal file
181
source/pin.c
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* pin.c
|
||||
* Code to manage pin locking for 3ds. By reworks.
|
||||
*/
|
||||
|
||||
#include "draw.h"
|
||||
#include "screen.h"
|
||||
#include "utils.h"
|
||||
#include "memory.h"
|
||||
#include "buttons.h"
|
||||
#include "fs.h"
|
||||
#include "i2c.h"
|
||||
#include "pin.h"
|
||||
#include "crypto.h"
|
||||
|
||||
bool readPin(PINData *out)
|
||||
{
|
||||
u8 __attribute__((aligned(4))) zeroes[16] = {0};
|
||||
u8 __attribute__((aligned(4))) tmp[32] = {0};
|
||||
if(fileRead(out, "/luma/pin.bin") != sizeof(PINData)) return false;
|
||||
else if(memcmp(out->magic, "PINF", 4) != 0) return false;
|
||||
|
||||
computePINHash(tmp, zeroes, 1);
|
||||
fileWrite(tmp, "/luma/testhash.bin", 32);
|
||||
return memcmp(out->testHash, tmp, 32) == 0; //test vector verification (SD card has (or hasn't) been used on another console)
|
||||
}
|
||||
|
||||
static inline char PINKeyToLetter(u32 pressed)
|
||||
{
|
||||
const char keys[] = "AB--------XY";
|
||||
|
||||
u32 i;
|
||||
__asm__ volatile("clz %[i], %[pressed]" : [i] "=r" (i) : [pressed] "r" (pressed));
|
||||
|
||||
return keys[31 - i];
|
||||
}
|
||||
|
||||
PINData newPin(void)
|
||||
{
|
||||
clearScreens();
|
||||
|
||||
drawString("Enter your NEW PIN (4 keys): ", 10, 10, COLOR_WHITE);
|
||||
|
||||
u32 pressed = 0;
|
||||
|
||||
// Set the default value as 0x00 so we can check if there are any unentered characters.
|
||||
u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0}; // pad to AES block length
|
||||
|
||||
int charDrawPos = 29 * SPACING_X;
|
||||
int cnt = 0;
|
||||
|
||||
while(true)
|
||||
{
|
||||
do
|
||||
{
|
||||
pressed = waitInput();
|
||||
}
|
||||
while(!(pressed & PIN_BUTTONS & ~BUTTON_START));
|
||||
|
||||
pressed &= PIN_BUTTONS & ~BUTTON_START;
|
||||
|
||||
if(!pressed) continue;
|
||||
char key = PINKeyToLetter(pressed);
|
||||
enteredPassword[cnt++] = (u8)key; // add character to password.
|
||||
|
||||
// visualize character on screen.
|
||||
drawCharacter(key, 10 + charDrawPos, 10, COLOR_WHITE);
|
||||
charDrawPos += 2 * SPACING_X;
|
||||
|
||||
// we leave the rest of the array zeroed out.
|
||||
if (cnt >= PIN_LENGTH)
|
||||
{
|
||||
|
||||
PINData pin = {0};
|
||||
u8 __attribute__((aligned(4))) tmp[32] = {0};
|
||||
u8 __attribute__((aligned(4))) zeroes[16] = {0};
|
||||
|
||||
memcpy(pin.magic, "PINF", 4);
|
||||
pin.formatVersionMajor = 1;
|
||||
pin.formatVersionMinor = 0;
|
||||
|
||||
computePINHash(tmp, zeroes, 1);
|
||||
memcpy(pin.testHash, tmp, 32);
|
||||
|
||||
computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
|
||||
memcpy(pin.hash, tmp, 32);
|
||||
|
||||
fileWrite(&pin, "/luma/pin.bin", sizeof(PINData));
|
||||
return pin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void verifyPin(PINData *in, bool allowQuit)
|
||||
{
|
||||
clearScreens();
|
||||
|
||||
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
|
||||
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||
|
||||
u32 pressed = 0;
|
||||
|
||||
// Set the default characters as 0x00 so we can check if there are any unentered characters.
|
||||
u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0};
|
||||
|
||||
bool unlock;
|
||||
int charDrawPos = 5 * SPACING_X, cnt = 0;
|
||||
|
||||
while(true)
|
||||
{
|
||||
do
|
||||
{
|
||||
pressed = waitInput();
|
||||
}
|
||||
while(!(pressed & PIN_BUTTONS));
|
||||
|
||||
pressed &= PIN_BUTTONS;// & ~BUTTON_START;
|
||||
if(!allowQuit) pressed &= ~BUTTON_START;
|
||||
if(!pressed) continue;
|
||||
|
||||
if(pressed & BUTTON_START)
|
||||
{
|
||||
clearScreens();
|
||||
mcuPowerOff();
|
||||
}
|
||||
|
||||
char key = PINKeyToLetter(pressed);
|
||||
enteredPassword[cnt++] = (u8)key; // add character to password.
|
||||
|
||||
// visualize character on screen.
|
||||
drawCharacter(key, 10 + charDrawPos, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||
charDrawPos += 2 * SPACING_X;
|
||||
|
||||
if(cnt >= PIN_LENGTH)
|
||||
{
|
||||
u8 __attribute__((aligned(4))) tmp[32] = {0};
|
||||
|
||||
computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
|
||||
unlock = memcmp(in->hash, tmp, 32) == 0;
|
||||
|
||||
if (!unlock)
|
||||
{
|
||||
// re zero out all 16 just in case.
|
||||
memset32(enteredPassword, 0, 16);
|
||||
|
||||
pressed = 0;
|
||||
charDrawPos = 5 * SPACING_X;
|
||||
cnt = 0;
|
||||
|
||||
clearScreens();
|
||||
|
||||
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
|
||||
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||
drawString("Wrong pin! Try again!", 10, 10 + 3 * SPACING_Y, COLOR_RED);
|
||||
}
|
||||
else return;
|
||||
}
|
||||
}
|
||||
}
|
46
source/pin.h
Normal file
46
source/pin.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016 Aurora Wright, TuxSH
|
||||
*
|
||||
* 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/>.
|
||||
*
|
||||
* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||
* reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* pin.h
|
||||
*
|
||||
* Code to manage pin locking for 3ds. By reworks.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define PIN_LENGTH 4
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
char magic[4];
|
||||
u16 formatVersionMajor, formatVersionMinor;
|
||||
|
||||
u8 testHash[32];
|
||||
u8 hash[32];
|
||||
} PINData;
|
||||
|
||||
bool readPin(PINData* out);
|
||||
|
||||
PINData newPin(void);
|
||||
void verifyPin(PINData *in, bool allowQuit);
|
@ -59,7 +59,15 @@ void mcuReboot(void)
|
||||
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
|
||||
while(1);
|
||||
while(true);
|
||||
}
|
||||
|
||||
void mcuPowerOff(void)
|
||||
{
|
||||
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
|
||||
while(true);
|
||||
}
|
||||
|
||||
//TODO: add support for TIMER IRQ
|
||||
@ -102,15 +110,12 @@ void stopChrono(void)
|
||||
void error(const char *message)
|
||||
{
|
||||
initScreens();
|
||||
clearScreens();
|
||||
|
||||
drawString("An error has occurred:", 10, 10, COLOR_RED);
|
||||
int posY = drawString(message, 10, 30, COLOR_WHITE);
|
||||
drawString("Press any button to shutdown", 10, posY + 2 * SPACING_Y, COLOR_WHITE);
|
||||
|
||||
waitInput();
|
||||
|
||||
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1);
|
||||
while(1);
|
||||
mcuPowerOff();
|
||||
}
|
@ -30,6 +30,8 @@
|
||||
|
||||
u32 waitInput(void);
|
||||
void mcuReboot(void);
|
||||
void mcuPowerOff(void);
|
||||
|
||||
void chrono(u32 seconds);
|
||||
void stopChrono(void);
|
||||
void error(const char *message);
|
Reference in New Issue
Block a user