Merge branch 'master' into developer
Conflicts: source/config.c source/fs.h source/patches.c
This commit is contained in:
commit
24ddf5ca3d
@ -29,7 +29,8 @@
|
|||||||
|
|
||||||
void configureCFW(const char *configPath)
|
void configureCFW(const char *configPath)
|
||||||
{
|
{
|
||||||
clearScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
|
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
|
||||||
drawString("Press A to select, START to save", 10, 30, COLOR_WHITE);
|
drawString("Press A to select, START to save", 10, 30, COLOR_WHITE);
|
||||||
|
|
||||||
@ -204,4 +205,6 @@ void configureCFW(const char *configPath)
|
|||||||
|
|
||||||
//Wait for the pressed buttons to change
|
//Wait for the pressed buttons to change
|
||||||
while(HID_PAD == BUTTON_START);
|
while(HID_PAD == BUTTON_START);
|
||||||
|
|
||||||
|
chrono(2);
|
||||||
}
|
}
|
@ -311,11 +311,8 @@ void ctrNandInit(void)
|
|||||||
|
|
||||||
if(isN3DS)
|
if(isN3DS)
|
||||||
{
|
{
|
||||||
if(!isDevUnit)
|
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);
|
||||||
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;
|
nandSlot = 0x05;
|
||||||
fatStart = 0x5CAD7;
|
fatStart = 0x5CAD7;
|
||||||
@ -364,8 +361,7 @@ void setRSAMod0DerivedKeys(void)
|
|||||||
|
|
||||||
/* [3dbrew] The first 0x10-bytes are checked by the v6.0/v7.0 NATIVE_FIRM keyinit function,
|
/* [3dbrew] The first 0x10-bytes are checked by the v6.0/v7.0 NATIVE_FIRM keyinit function,
|
||||||
when non-zero it clears this block and continues to do the key generation.
|
when non-zero it clears this block and continues to do the key generation.
|
||||||
Otherwise when this block was already all-zero, it immediately returns.
|
Otherwise when this block was already all-zero, it immediately returns. */
|
||||||
*/
|
|
||||||
memset32((void *)0x01FFCD00, 0, 0x10);
|
memset32((void *)0x01FFCD00, 0, 0x10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -408,7 +404,7 @@ void arm9Loader(u8 *arm9Section)
|
|||||||
|
|
||||||
//Firm keys
|
//Firm keys
|
||||||
u8 __attribute__((aligned(4))) keyY[0x10];
|
u8 __attribute__((aligned(4))) keyY[0x10];
|
||||||
u8 __attribute__((aligned(4))) arm9BinCTR[0x10];
|
u8 __attribute__((aligned(4))) arm9BinCTR[0x10];
|
||||||
u8 arm9BinSlot = a9lVersion ? 0x16 : 0x15;
|
u8 arm9BinSlot = a9lVersion ? 0x16 : 0x15;
|
||||||
|
|
||||||
//Setup keys needed for arm9bin decryption
|
//Setup keys needed for arm9bin decryption
|
||||||
@ -453,11 +449,10 @@ void arm9Loader(u8 *arm9Section)
|
|||||||
|
|
||||||
//Set keys 0x19..0x1F keyXs
|
//Set keys 0x19..0x1F keyXs
|
||||||
aes_use_keyslot(0x11);
|
aes_use_keyslot(0x11);
|
||||||
for(u8 slot = 0x19; slot < 0x20; slot++)
|
for(u8 slot = 0x19; slot < 0x20; slot++, keyData[0xF]++)
|
||||||
{
|
{
|
||||||
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
|
||||||
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
|
||||||
keyData[0xF] += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,8 @@ bool loadSplash(void)
|
|||||||
fileRead(fb->top_left, "/luma/splash.bin");
|
fileRead(fb->top_left, "/luma/splash.bin");
|
||||||
fileRead(fb->bottom, "/luma/splashbottom.bin");
|
fileRead(fb->bottom, "/luma/splashbottom.bin");
|
||||||
|
|
||||||
|
chrono(3);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,8 +57,7 @@ void main(void)
|
|||||||
isA9lh;
|
isA9lh;
|
||||||
|
|
||||||
u32 newConfig,
|
u32 newConfig,
|
||||||
emuHeader,
|
emuHeader;
|
||||||
nbChronoStarted = 0;
|
|
||||||
|
|
||||||
FirmwareType firmType;
|
FirmwareType firmType;
|
||||||
FirmwareSource nandType;
|
FirmwareSource nandType;
|
||||||
@ -138,41 +137,22 @@ void main(void)
|
|||||||
//Boot options aren't being forced
|
//Boot options aren't being forced
|
||||||
if(needConfig != DONT_CONFIGURE)
|
if(needConfig != DONT_CONFIGURE)
|
||||||
{
|
{
|
||||||
//If no configuration file exists or SELECT is held, load configuration menu
|
|
||||||
bool shouldLoadConfigurationMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
|
|
||||||
bool pinExists = CONFIG(7) && readPin(&pin);
|
bool pinExists = CONFIG(7) && readPin(&pin);
|
||||||
|
|
||||||
if(pinExists || shouldLoadConfigurationMenu)
|
//If we get here we should check the PIN (if it exists) in all cases
|
||||||
|
if(pinExists) verifyPin(&pin, true);
|
||||||
|
|
||||||
|
//If no configuration file exists or SELECT is held, load configuration menu
|
||||||
|
bool shouldLoadConfigurationMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
|
||||||
|
|
||||||
|
if(shouldLoadConfigurationMenu)
|
||||||
{
|
{
|
||||||
bool needToDeinit = initScreens();
|
configureCFW(configPath);
|
||||||
|
|
||||||
//If we get here we should check the PIN (if it exists) in all cases
|
if(!pinExists && CONFIG(7)) pin = newPin();
|
||||||
if(pinExists) verifyPin(&pin, true);
|
|
||||||
|
|
||||||
if(shouldLoadConfigurationMenu)
|
//Update pressed buttons
|
||||||
{
|
pressed = HID_PAD;
|
||||||
configureCFW(configPath);
|
|
||||||
|
|
||||||
if(!pinExists && CONFIG(7)) pin = newPin();
|
|
||||||
|
|
||||||
//Zero the last booted FIRM flag
|
|
||||||
CFG_BOOTENV = 0;
|
|
||||||
|
|
||||||
nbChronoStarted = 1;
|
|
||||||
chrono(0);
|
|
||||||
chrono(2);
|
|
||||||
|
|
||||||
//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)
|
if(isA9lh && !CFG_BOOTENV && pressed == SAFE_MODE)
|
||||||
@ -182,28 +162,15 @@ void main(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if(CONFIG(6) && loadSplash()) pressed = HID_PAD;
|
||||||
|
|
||||||
/* If L and R/A/Select or one of the single payload buttons are pressed,
|
/* If L and R/A/Select or one of the single payload buttons are pressed,
|
||||||
chainload an external payload (the PIN, if any, has been verified)*/
|
chainload an external payload (the PIN, if any, has been verified)*/
|
||||||
|
|
||||||
if(CONFIG(6) && loadSplash())
|
|
||||||
{
|
|
||||||
nbChronoStarted = 2;
|
|
||||||
chrono(0);
|
|
||||||
chrono(3);
|
|
||||||
nbChronoStarted = 0;
|
|
||||||
pressed = HID_PAD;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool shouldLoadPayload = (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS));
|
bool shouldLoadPayload = (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS));
|
||||||
|
|
||||||
if(shouldLoadPayload)
|
if(shouldLoadPayload) loadPayload(pressed);
|
||||||
loadPayload(pressed, nbChronoStarted != 2);
|
|
||||||
|
|
||||||
if(!CONFIG(6) && loadSplash())
|
if(!CONFIG(6)) loadSplash();
|
||||||
{
|
|
||||||
nbChronoStarted = 2;
|
|
||||||
chrono(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
|
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
|
||||||
if(pressed & BUTTON_R1)
|
if(pressed & BUTTON_R1)
|
||||||
@ -270,12 +237,6 @@ void main(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(nbChronoStarted)
|
|
||||||
{
|
|
||||||
if(nbChronoStarted == 2) chrono(3);
|
|
||||||
stopChrono();
|
|
||||||
}
|
|
||||||
|
|
||||||
launchFirm(firmType, isFirmlaunch);
|
launchFirm(firmType, isFirmlaunch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ void createDirectory(const char *path)
|
|||||||
f_mkdir(path);
|
f_mkdir(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadPayload(u32 pressed, bool needToInitScreens)
|
void loadPayload(u32 pressed)
|
||||||
{
|
{
|
||||||
const char *pattern;
|
const char *pattern;
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ void loadPayload(u32 pressed, bool needToInitScreens)
|
|||||||
|
|
||||||
if(result == FR_OK && info.fname[0])
|
if(result == FR_OK && info.fname[0])
|
||||||
{
|
{
|
||||||
if(needToInitScreens) initScreens();
|
initScreens();
|
||||||
|
|
||||||
u32 *const loaderAddress = (u32 *)0x24FFFF00;
|
u32 *const loaderAddress = (u32 *)0x24FFFF00;
|
||||||
|
|
||||||
|
@ -34,5 +34,4 @@ u32 getFileSize(const char *path);
|
|||||||
bool fileWrite(const void *buffer, const char *path, u32 size);
|
bool fileWrite(const void *buffer, const char *path, u32 size);
|
||||||
void createDirectory(const char *path);
|
void createDirectory(const char *path);
|
||||||
void findDumpFile(const char *path, char *fileName);
|
void findDumpFile(const char *path, char *fileName);
|
||||||
void loadPayload(u32 pressed, bool needToInitScreens);
|
void loadPayload(u32 pressed);u32 firmRead(void *dest, u32 firmType);
|
||||||
u32 firmRead(void *dest, u32 firmType);
|
|
33
source/pin.c
33
source/pin.c
@ -39,8 +39,9 @@ bool readPin(PINData *out)
|
|||||||
{
|
{
|
||||||
u8 __attribute__((aligned(4))) zeroes[16] = {0};
|
u8 __attribute__((aligned(4))) zeroes[16] = {0};
|
||||||
u8 __attribute__((aligned(4))) tmp[32] = {0};
|
u8 __attribute__((aligned(4))) tmp[32] = {0};
|
||||||
|
|
||||||
if(fileRead(out, "/luma/pin.bin") != sizeof(PINData)) return false;
|
if(fileRead(out, "/luma/pin.bin") != sizeof(PINData)) return false;
|
||||||
else if(memcmp(out->magic, "PINF", 4) != 0) return false;
|
if(memcmp(out->magic, "PINF", 4) != 0) return false;
|
||||||
|
|
||||||
computePINHash(tmp, zeroes, 1);
|
computePINHash(tmp, zeroes, 1);
|
||||||
return memcmp(out->testHash, tmp, 32) == 0; //test vector verification (SD card has (or hasn't) been used on another console)
|
return memcmp(out->testHash, tmp, 32) == 0; //test vector verification (SD card has (or hasn't) been used on another console)
|
||||||
@ -62,16 +63,15 @@ PINData newPin(void)
|
|||||||
|
|
||||||
drawString("Enter your NEW PIN: ", 10, 10, COLOR_WHITE);
|
drawString("Enter your NEW PIN: ", 10, 10, COLOR_WHITE);
|
||||||
|
|
||||||
u32 pressed = 0;
|
|
||||||
|
|
||||||
// Set the default value as 0x00 so we can check if there are any unentered characters.
|
// 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
|
u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0}; // pad to AES block length
|
||||||
|
|
||||||
|
u32 cnt = 0;
|
||||||
int charDrawPos = 20 * SPACING_X;
|
int charDrawPos = 20 * SPACING_X;
|
||||||
int cnt = 0;
|
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
|
u32 pressed;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
pressed = waitInput();
|
pressed = waitInput();
|
||||||
@ -89,9 +89,8 @@ PINData newPin(void)
|
|||||||
charDrawPos += 2 * SPACING_X;
|
charDrawPos += 2 * SPACING_X;
|
||||||
|
|
||||||
// we leave the rest of the array zeroed out.
|
// we leave the rest of the array zeroed out.
|
||||||
if (cnt >= PIN_LENGTH)
|
if(cnt >= PIN_LENGTH)
|
||||||
{
|
{
|
||||||
|
|
||||||
PINData pin = {0};
|
PINData pin = {0};
|
||||||
u8 __attribute__((aligned(4))) tmp[32] = {0};
|
u8 __attribute__((aligned(4))) tmp[32] = {0};
|
||||||
u8 __attribute__((aligned(4))) zeroes[16] = {0};
|
u8 __attribute__((aligned(4))) zeroes[16] = {0};
|
||||||
@ -114,21 +113,21 @@ PINData newPin(void)
|
|||||||
|
|
||||||
void verifyPin(PINData *in, bool allowQuit)
|
void verifyPin(PINData *in, bool allowQuit)
|
||||||
{
|
{
|
||||||
clearScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
|
drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
|
||||||
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, 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.
|
// 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};
|
u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0};
|
||||||
|
|
||||||
|
u32 cnt = 0;
|
||||||
bool unlock;
|
bool unlock;
|
||||||
int charDrawPos = 5 * SPACING_X, cnt = 0;
|
int charDrawPos = 5 * SPACING_X;
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
|
u32 pressed;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
pressed = waitInput();
|
pressed = waitInput();
|
||||||
@ -139,11 +138,7 @@ void verifyPin(PINData *in, bool allowQuit)
|
|||||||
if(!allowQuit) pressed &= ~BUTTON_START;
|
if(!allowQuit) pressed &= ~BUTTON_START;
|
||||||
if(!pressed) continue;
|
if(!pressed) continue;
|
||||||
|
|
||||||
if(pressed & BUTTON_START)
|
if(pressed & BUTTON_START) mcuPowerOff();
|
||||||
{
|
|
||||||
clearScreens();
|
|
||||||
mcuPowerOff();
|
|
||||||
}
|
|
||||||
|
|
||||||
char key = PINKeyToLetter(pressed);
|
char key = PINKeyToLetter(pressed);
|
||||||
enteredPassword[cnt++] = (u8)key; // add character to password.
|
enteredPassword[cnt++] = (u8)key; // add character to password.
|
||||||
@ -159,12 +154,8 @@ void verifyPin(PINData *in, bool allowQuit)
|
|||||||
computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
|
computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
|
||||||
unlock = memcmp(in->hash, tmp, 32) == 0;
|
unlock = memcmp(in->hash, tmp, 32) == 0;
|
||||||
|
|
||||||
if (!unlock)
|
if(!unlock)
|
||||||
{
|
{
|
||||||
// re zero out all 16 just in case.
|
|
||||||
memset32(enteredPassword, 0, 16);
|
|
||||||
|
|
||||||
pressed = 0;
|
|
||||||
charDrawPos = 5 * SPACING_X;
|
charDrawPos = 5 * SPACING_X;
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
|
|
||||||
@ -174,7 +165,7 @@ void verifyPin(PINData *in, bool allowQuit)
|
|||||||
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
|
||||||
drawString("Wrong pin! Try again!", 10, 10 + 3 * SPACING_Y, COLOR_RED);
|
drawString("Wrong pin! Try again!", 10, 10 + 3 * SPACING_Y, COLOR_RED);
|
||||||
}
|
}
|
||||||
else return;
|
else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -140,10 +140,8 @@ void clearScreens(void)
|
|||||||
invokeArm11Function(ARM11);
|
invokeArm11Function(ARM11);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool initScreens(void)
|
void initScreens(void)
|
||||||
{
|
{
|
||||||
bool needToInit = PDN_GPU_CNT == 1;
|
|
||||||
|
|
||||||
void __attribute__((naked)) ARM11(void)
|
void __attribute__((naked)) ARM11(void)
|
||||||
{
|
{
|
||||||
//Disable interrupts
|
//Disable interrupts
|
||||||
@ -242,18 +240,20 @@ bool initScreens(void)
|
|||||||
WAIT_FOR_ARM9();
|
WAIT_FOR_ARM9();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(needToInit)
|
if(PDN_GPU_CNT == 1)
|
||||||
{
|
{
|
||||||
flushDCacheRange(&config, 4);
|
flushDCacheRange(&config, 4);
|
||||||
flushDCacheRange((void *)fb, sizeof(struct fb));
|
flushDCacheRange((void *)fb, sizeof(struct fb));
|
||||||
invokeArm11Function(ARM11);
|
invokeArm11Function(ARM11);
|
||||||
|
|
||||||
|
clearScreens();
|
||||||
|
|
||||||
//Turn on backlight
|
//Turn on backlight
|
||||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
||||||
}
|
}
|
||||||
else updateBrightness(MULTICONFIG(0));
|
else
|
||||||
|
{
|
||||||
clearScreens();
|
clearScreens();
|
||||||
|
updateBrightness(MULTICONFIG(0));
|
||||||
return needToInit;
|
}
|
||||||
}
|
}
|
@ -42,4 +42,4 @@ static volatile struct fb {
|
|||||||
void deinitScreens(void);
|
void deinitScreens(void);
|
||||||
void updateBrightness(u32 brightnessIndex);
|
void updateBrightness(u32 brightnessIndex);
|
||||||
void clearScreens(void);
|
void clearScreens(void);
|
||||||
bool initScreens(void);
|
void initScreens(void);
|
@ -56,6 +56,8 @@ u32 waitInput(void)
|
|||||||
|
|
||||||
void mcuReboot(void)
|
void mcuReboot(void)
|
||||||
{
|
{
|
||||||
|
if(PDN_GPU_CNT != 1) clearScreens();
|
||||||
|
|
||||||
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||||
|
|
||||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
|
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
|
||||||
@ -64,6 +66,8 @@ void mcuReboot(void)
|
|||||||
|
|
||||||
void mcuPowerOff(void)
|
void mcuPowerOff(void)
|
||||||
{
|
{
|
||||||
|
if(PDN_GPU_CNT != 1) clearScreens();
|
||||||
|
|
||||||
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||||
|
|
||||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
|
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
|
||||||
@ -84,14 +88,19 @@ static inline void startChrono(u64 initialTicks)
|
|||||||
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 0x84; //Count-up; enabled
|
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 0x84; //Count-up; enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void stopChrono(void)
|
||||||
|
{
|
||||||
|
for(u32 i = 0; i < 4; i++) REG_TIMER_CNT(i) &= ~0x80;
|
||||||
|
}
|
||||||
|
|
||||||
void chrono(u32 seconds)
|
void chrono(u32 seconds)
|
||||||
{
|
{
|
||||||
static u64 startingTicks = 0;
|
startChrono(0);
|
||||||
|
|
||||||
if(!startingTicks) startChrono(0);
|
u64 startingTicks = 0;
|
||||||
|
for(u32 i = 0; i < 4; i++) startingTicks |= REG_TIMER_VAL(i) << (16 * i);
|
||||||
|
|
||||||
u64 res;
|
u64 res;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
res = 0;
|
res = 0;
|
||||||
@ -99,18 +108,12 @@ void chrono(u32 seconds)
|
|||||||
}
|
}
|
||||||
while(res - startingTicks < seconds * TICKS_PER_SEC);
|
while(res - startingTicks < seconds * TICKS_PER_SEC);
|
||||||
|
|
||||||
if(!seconds) startingTicks = res;
|
stopChrono();
|
||||||
}
|
|
||||||
|
|
||||||
void stopChrono(void)
|
|
||||||
{
|
|
||||||
for(u32 i = 0; i < 4; i++) REG_TIMER_CNT(i) &= ~0x80;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void error(const char *message)
|
void error(const char *message)
|
||||||
{
|
{
|
||||||
initScreens();
|
initScreens();
|
||||||
clearScreens();
|
|
||||||
|
|
||||||
drawString("An error has occurred:", 10, 10, COLOR_RED);
|
drawString("An error has occurred:", 10, 10, COLOR_RED);
|
||||||
int posY = drawString(message, 10, 30, COLOR_WHITE);
|
int posY = drawString(message, 10, 30, COLOR_WHITE);
|
||||||
|
@ -31,7 +31,5 @@
|
|||||||
u32 waitInput(void);
|
u32 waitInput(void);
|
||||||
void mcuReboot(void);
|
void mcuReboot(void);
|
||||||
void mcuPowerOff(void);
|
void mcuPowerOff(void);
|
||||||
|
|
||||||
void chrono(u32 seconds);
|
void chrono(u32 seconds);
|
||||||
void stopChrono(void);
|
|
||||||
void error(const char *message);
|
void error(const char *message);
|
Reference in New Issue
Block a user