diff --git a/arm11/Makefile b/arm11/Makefile index 7019e35..0eb2e68 100644 --- a/arm11/Makefile +++ b/arm11/Makefile @@ -15,7 +15,7 @@ # all directories are relative to this makefile #--------------------------------------------------------------------------------- BUILD := build -SOURCES := ../source ../source/arm11 +SOURCES := ../source ../source/arm11 ../source/arm11/hardware INCLUDES := ../include DEFINES := -DARM11 -D_3DS -DVERS_STRING=\"$(VERS_STRING)\" \ -DVERS_MAJOR=$(VERS_MAJOR) -DVERS_MINOR=$(VERS_MINOR) diff --git a/arm9/Makefile b/arm9/Makefile index 6af9faf..ecbe23f 100644 --- a/arm9/Makefile +++ b/arm9/Makefile @@ -15,7 +15,7 @@ # all directories are relative to this makefile #--------------------------------------------------------------------------------- BUILD := build -SOURCES := ../source ../source/arm9 ../source/arm9/gui ../thirdparty/fatfs +SOURCES := ../source ../source/arm9 ../source/arm9/gui ../source/arm9/hardware ../thirdparty/fatfs INCLUDES := ../include ../thirdparty DEFINES := -DARM9 -D_3DS -DVERS_STRING=\"$(VERS_STRING)\" \ -DVERS_MAJOR=$(VERS_MAJOR) -DVERS_MINOR=$(VERS_MINOR) diff --git a/include/arm11/gpio.h b/include/arm11/gpio.h deleted file mode 100644 index 538365f..0000000 --- a/include/arm11/gpio.h +++ /dev/null @@ -1,39 +0,0 @@ -#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 . - */ - -#include "types.h" - - - -/** - * @brief Sets a bit in the specified GPIO register. - * - * @param[in] reg The register number. - * @param[in] bitNum The bit number. - */ -void GPIO_setBit(u16 reg, u8 bitNum); - -/** - * @brief Clears a bit in the specified GPIO register. - * - * @param[in] reg The register number. - * @param[in] bitNum The bit number. - */ -void GPIO_clearBit(u16 reg, u8 bitNum); diff --git a/include/arm11/hardware.h b/include/arm11/hardware.h deleted file mode 100644 index 9fa3d6b..0000000 --- a/include/arm11/hardware.h +++ /dev/null @@ -1,24 +0,0 @@ -#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 . - */ - - - -void hardwareInit(void); -//void hardwareDeinit(void); diff --git a/include/arm11/hardware/gpio.h b/include/arm11/hardware/gpio.h new file mode 100644 index 0000000..538365f --- /dev/null +++ b/include/arm11/hardware/gpio.h @@ -0,0 +1,39 @@ +#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 . + */ + +#include "types.h" + + + +/** + * @brief Sets a bit in the specified GPIO register. + * + * @param[in] reg The register number. + * @param[in] bitNum The bit number. + */ +void GPIO_setBit(u16 reg, u8 bitNum); + +/** + * @brief Clears a bit in the specified GPIO register. + * + * @param[in] reg The register number. + * @param[in] bitNum The bit number. + */ +void GPIO_clearBit(u16 reg, u8 bitNum); diff --git a/include/arm11/hardware/hardware.h b/include/arm11/hardware/hardware.h new file mode 100644 index 0000000..9fa3d6b --- /dev/null +++ b/include/arm11/hardware/hardware.h @@ -0,0 +1,24 @@ +#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 . + */ + + + +void hardwareInit(void); +//void hardwareDeinit(void); diff --git a/include/arm11/hardware/hid.h b/include/arm11/hardware/hid.h new file mode 100644 index 0000000..3e09acb --- /dev/null +++ b/include/arm11/hardware/hid.h @@ -0,0 +1,57 @@ +#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 . + */ + +/* + * Based on code from https://github.com/smealum/ctrulib + */ + +#include "types.h" + + +#define HID_KEY_MASK_ALL ((KEY_SHELL << 1) - 1) +#define HID_VERBOSE_MODE_BUTTONS (KEY_SELECT | KEY_START) + +enum +{ + KEY_A = (1), + KEY_B = (1<<1), + KEY_SELECT = (1<<2), + KEY_START = (1<<3), + KEY_DRIGHT = (1<<4), + KEY_DLEFT = (1<<5), + KEY_DUP = (1<<6), + KEY_DDOWN = (1<<7), + KEY_R = (1<<8), + KEY_L = (1<<9), + KEY_X = (1<<10), + KEY_Y = (1<<11), + KEY_HOME = (1<<21), + KEY_SHELL = (1<<22) +}; + + + +void hidInit(void); +u32 hidGetPowerButton(void); +u32 hidGetWifiButton(void); +void hidScanInput(void); +u32 hidKeysHeld(void); +u32 hidKeysDown(void); +u32 hidKeysUp(void); diff --git a/include/arm11/hardware/i2c.h b/include/arm11/hardware/i2c.h new file mode 100644 index 0000000..4550f98 --- /dev/null +++ b/include/arm11/hardware/i2c.h @@ -0,0 +1,115 @@ +#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 . + */ + +#include "types.h" + + +#define I2C_STOP (1u) +#define I2C_START (1u<<1) +#define I2C_ERROR (1u<<2) +#define I2C_ACK (1u<<4) +#define I2C_DIRE_WRITE (0u) +#define I2C_DIRE_READ (1u<<5) +#define I2C_IRQ_ENABLE (1u<<6) +#define I2C_ENABLE (1u<<7) + +#define I2C_GET_ACK(reg) ((bool)((reg)>>4 & 1u)) + + +typedef enum +{ + I2C_DEV_POWER = 0, // Unconfirmed + I2C_DEV_CAMERA = 1, // Unconfirmed + I2C_DEV_CAMERA2 = 2, // Unconfirmed + I2C_DEV_MCU = 3, + I2C_DEV_GYRO = 10, + I2C_DEV_DEBUG_PAD = 12, + I2C_DEV_IR = 13, + I2C_DEV_EEPROM = 14, // Unconfirmed + I2C_DEV_NFC = 15, + I2C_DEV_QTM = 16, + I2C_DEV_N3DS_HID = 17 +} I2cDevice; + + + +/** + * @brief Initializes the I2C buses. Call this only once. + */ +void I2C_init(void); + +/** + * @brief Reads data from a I2C register to a buffer. + * + * @param[in] devId The device ID. Use the enum above. + * @param[in] regAddr The register address. + * @param out The output buffer pointer. + * @param[in] size The read size. + * + * @return Returns true on success and false on failure. + */ +bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size); + +/** + * @brief Writes a buffer to a I2C register. + * + * @param[in] devId The device ID. Use the enum above. + * @param[in] regAddr The register address. + * @param[in] in The input buffer pointer. + * @param[in] size The write size. + * + * @return Returns true on success and false on failure. + */ +bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size); + +/** + * @brief Reads a byte from a I2C register. + * + * @param[in] devId The device ID. Use the enum above. + * @param[in] regAddr The register address. + * + * @return Returns the value read on success otherwise 0xFF. + */ +u8 I2C_readReg(I2cDevice devId, u8 regAddr); + +/** + * @brief Writes a byte to a I2C register. + * + * @param[in] devId The device ID. Use the enum above. + * @param[in] regAddr The register address. + * @param[in] data The data to write. + * + * @return Returns true on success and false on failure. + */ +bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data); + +u8 i2cmcu_readreg_hid_irq(void); +u8 i2cmcu_readreg_hid_held(void); +bool i2cmcu_lcd_poweron(void); +bool i2cmcu_lcd_backlight_poweron(void); +bool i2cmcu_lcd_poweroff(void); + +#define MCU_HID_POWER_BUTTON_PRESSED (1u) +#define MCU_HID_POWER_BUTTON_LONG_PRESSED (1u<<1) +#define MCU_HID_HOME_BUTTON_PRESSED (1u<<2) +#define MCU_HID_HOME_BUTTON_RELEASED (1u<<3) +#define MCU_HID_HOME_BUTTON_NOT_HELD (1u<<1) +#define MCU_HID_SHELL_GOT_CLOSED (1u<<5) +#define MCU_HID_SHELL_GOT_OPENED (1u<<6) diff --git a/include/arm11/hardware/interrupt.h b/include/arm11/hardware/interrupt.h new file mode 100644 index 0000000..4b0f6c5 --- /dev/null +++ b/include/arm11/hardware/interrupt.h @@ -0,0 +1,133 @@ +#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 . + */ + +#include "types.h" + + +typedef enum +{ + IRQ_MPCORE_SW0 = 0, + IRQ_MPCORE_SW1 = 1, + IRQ_MPCORE_SW2 = 2, + IRQ_MPCORE_SW3 = 3, + IRQ_MPCORE_SW4 = 4, + IRQ_MPCORE_SW5 = 5, + IRQ_MPCORE_SW6 = 6, + IRQ_MPCORE_SW7 = 7, + IRQ_MPCORE_SW8 = 8, + IRQ_MPCORE_SW9 = 9, + IRQ_MPCORE_SW10 = 10, + IRQ_MPCORE_SW11 = 11, + IRQ_MPCORE_SW12 = 12, + IRQ_MPCORE_SW13 = 13, + IRQ_MPCORE_SW14 = 14, + IRQ_MPCORE_SW15 = 15, + IRQ_TIMER = 29, // MPCore timer + IRQ_WATCHDOG = 30, // MPCore watchdog + IRQ_PSC0 = 40, + IRQ_PSC1 = 41, + IRQ_PDC0 = 42, // aka VBlank0 + IRQ_PDC1 = 43, // aka VBlank1 + IRQ_PPF = 44, + IRQ_P3D = 45, // This is a guess + IRQ_PXI_SYNC = 80, + IRQ_PXI_UNK = 81, // Unknown what this is for + IRQ_PXI_NOT_FULL = 82, + IRQ_PXI_NOT_EMPTY = 83, + IRQ_SHELL_OPENED = 96, + IRQ_SHELL_CLOSED = 98, + IRQ_TOUCHSCREEN = 99, // Triggers on hitting the touchscreen. + IRQ_HEADPH_JACK = 100, // Headphone jack. Triggers on both plugging in and out? GPIO reg 9, bit 8. + IRQ_MCU_HID = 113, // HOME/POWER pressed/released, shell opened/closed and WiFi switch pressed. GPIO reg 19, bit 9. + IRQ_GAMECARD = 117 // Gamecard inserted +} Interrupt; + + +// IRQ handler type. +// intSource: bit 10-12 CPU source ID (0 except for interrupt ID 0-15), +// bit 0-9 interrupt ID +typedef void (*IrqHandler)(u32 intSource); + + + +/** + * @brief Initializes the generic interrupt controller. + */ +void IRQ_init(void); + +/** + * @brief Registers a interrupt handler and enables the specified interrupt. + * + * @param[in] id The interrupt ID. Must be <128. + * @param[in] prio The priority. 0 = highest, 14 = lowest, 15 = disabled + * @param[in] cpuMask The CPU mask. Each of the 4 bits stands for 1 core. 0 means current CPU. + * @param[in] edgeTriggered Set to true to make the interrupt edge triggered. false is level triggered. + * @param[in] handler The interrupt handler to call. + */ +void IRQ_registerHandler(Interrupt id, u8 prio, u8 cpuMask, bool edgeTriggered, IrqHandler handler); + +/** + * @brief Unregisters the interrupt handler and disables the specified interrupt. + * + * @param[in] id The interrupt ID. Must be <128. + */ +void IRQ_unregisterHandler(Interrupt id); + +/** + * @brief Sets the priority of an interrupt. + * + * @param[in] id The interrupt ID. Must be <128. + * @param[in] prio The priority. 0 = highest, 14 = lowest, 15 = disabled + */ +void IRQ_setPriority(Interrupt id, u8 prio); + +/** + * @brief Triggers a software interrupt for the specified CPUs. + * + * @param[in] id The interrupt ID. Must be <16. + * @param[in] cpuMask The CPU mask. Each of the 4 bits stands for 1 core. + */ +void IRQ_softwareInterrupt(Interrupt id, u8 cpuMask); + + +static inline void waitForInterrupt(void) +{ + __asm__ __volatile__("wfi" : :); +} + +static inline void enterCriticalSection(void) +{ + __asm__ __volatile__("cpsid i" : :); +} + +static inline void leaveCriticalSection(void) +{ + __asm__ __volatile__("cpsie i" : :); +} + +static inline void waitForEvent(void) +{ + __asm__ __volatile__("wfe" : :); +} + +static inline void signalEvent(void) +{ + __asm__ __volatile__("sev" : :); +} diff --git a/include/arm11/hardware/timer.h b/include/arm11/hardware/timer.h new file mode 100644 index 0000000..e365370 --- /dev/null +++ b/include/arm11/hardware/timer.h @@ -0,0 +1,66 @@ +#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 . + */ + +#include "types.h" + + +#define TIMER_BASE_FREQ (268111856.0) + +#define TIMER_ENABLE (1u) +#define TIMER_SINGLE_SHOT (0u) +#define TIMER_AUTO_RELOAD (1u<<1) +#define TIMER_IRQ_ENABLE (1u<<2) + +// p is the prescaler value and n the frequence +#define TIMER_FREQ(p, n) (TIMER_BASE_FREQ / 2 / ((p) + 1) / (n)) + + + +/** + * @brief Resets/initializes the timer hardware. Should not be called manually. + */ +void TIMER_init(void); + +/** + * @brief Starts the timer. + * + * @param[in] prescaler The prescaler value. + * @param[in] ticks The initial number of ticks. This is also the + * reload value in auto reload mode. + * @param[in] autoReload Set to true for auto reload. false for single shot. + * @param[in] enableIrq Timer fires IRQs on underflow if true. + */ +void TIMER_start(u8 prescaler, u32 ticks, bool autoReload, bool enableIrq); + +/** + * @brief Stops the timer. + */ +void TIMER_stop(void); + +/** + * @brief Halts the CPU for the specified number of ticks. + * Use the macro below for a milliseconds version. + * + * @param[in] ticks The number of ticks to sleep. + */ +void TIMER_sleepTicks(u32 ticks); + +// Sleeps ms milliseconds. ms can be up to 32000. +#define TIMER_sleepMs(ms) TIMER_sleepTicks(TIMER_FREQ(0, 1000.0) * (ms)) diff --git a/include/arm11/hid.h b/include/arm11/hid.h deleted file mode 100644 index 3e09acb..0000000 --- a/include/arm11/hid.h +++ /dev/null @@ -1,57 +0,0 @@ -#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 . - */ - -/* - * Based on code from https://github.com/smealum/ctrulib - */ - -#include "types.h" - - -#define HID_KEY_MASK_ALL ((KEY_SHELL << 1) - 1) -#define HID_VERBOSE_MODE_BUTTONS (KEY_SELECT | KEY_START) - -enum -{ - KEY_A = (1), - KEY_B = (1<<1), - KEY_SELECT = (1<<2), - KEY_START = (1<<3), - KEY_DRIGHT = (1<<4), - KEY_DLEFT = (1<<5), - KEY_DUP = (1<<6), - KEY_DDOWN = (1<<7), - KEY_R = (1<<8), - KEY_L = (1<<9), - KEY_X = (1<<10), - KEY_Y = (1<<11), - KEY_HOME = (1<<21), - KEY_SHELL = (1<<22) -}; - - - -void hidInit(void); -u32 hidGetPowerButton(void); -u32 hidGetWifiButton(void); -void hidScanInput(void); -u32 hidKeysHeld(void); -u32 hidKeysDown(void); -u32 hidKeysUp(void); diff --git a/include/arm11/i2c.h b/include/arm11/i2c.h deleted file mode 100644 index 4550f98..0000000 --- a/include/arm11/i2c.h +++ /dev/null @@ -1,115 +0,0 @@ -#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 . - */ - -#include "types.h" - - -#define I2C_STOP (1u) -#define I2C_START (1u<<1) -#define I2C_ERROR (1u<<2) -#define I2C_ACK (1u<<4) -#define I2C_DIRE_WRITE (0u) -#define I2C_DIRE_READ (1u<<5) -#define I2C_IRQ_ENABLE (1u<<6) -#define I2C_ENABLE (1u<<7) - -#define I2C_GET_ACK(reg) ((bool)((reg)>>4 & 1u)) - - -typedef enum -{ - I2C_DEV_POWER = 0, // Unconfirmed - I2C_DEV_CAMERA = 1, // Unconfirmed - I2C_DEV_CAMERA2 = 2, // Unconfirmed - I2C_DEV_MCU = 3, - I2C_DEV_GYRO = 10, - I2C_DEV_DEBUG_PAD = 12, - I2C_DEV_IR = 13, - I2C_DEV_EEPROM = 14, // Unconfirmed - I2C_DEV_NFC = 15, - I2C_DEV_QTM = 16, - I2C_DEV_N3DS_HID = 17 -} I2cDevice; - - - -/** - * @brief Initializes the I2C buses. Call this only once. - */ -void I2C_init(void); - -/** - * @brief Reads data from a I2C register to a buffer. - * - * @param[in] devId The device ID. Use the enum above. - * @param[in] regAddr The register address. - * @param out The output buffer pointer. - * @param[in] size The read size. - * - * @return Returns true on success and false on failure. - */ -bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size); - -/** - * @brief Writes a buffer to a I2C register. - * - * @param[in] devId The device ID. Use the enum above. - * @param[in] regAddr The register address. - * @param[in] in The input buffer pointer. - * @param[in] size The write size. - * - * @return Returns true on success and false on failure. - */ -bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size); - -/** - * @brief Reads a byte from a I2C register. - * - * @param[in] devId The device ID. Use the enum above. - * @param[in] regAddr The register address. - * - * @return Returns the value read on success otherwise 0xFF. - */ -u8 I2C_readReg(I2cDevice devId, u8 regAddr); - -/** - * @brief Writes a byte to a I2C register. - * - * @param[in] devId The device ID. Use the enum above. - * @param[in] regAddr The register address. - * @param[in] data The data to write. - * - * @return Returns true on success and false on failure. - */ -bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data); - -u8 i2cmcu_readreg_hid_irq(void); -u8 i2cmcu_readreg_hid_held(void); -bool i2cmcu_lcd_poweron(void); -bool i2cmcu_lcd_backlight_poweron(void); -bool i2cmcu_lcd_poweroff(void); - -#define MCU_HID_POWER_BUTTON_PRESSED (1u) -#define MCU_HID_POWER_BUTTON_LONG_PRESSED (1u<<1) -#define MCU_HID_HOME_BUTTON_PRESSED (1u<<2) -#define MCU_HID_HOME_BUTTON_RELEASED (1u<<3) -#define MCU_HID_HOME_BUTTON_NOT_HELD (1u<<1) -#define MCU_HID_SHELL_GOT_CLOSED (1u<<5) -#define MCU_HID_SHELL_GOT_OPENED (1u<<6) diff --git a/include/arm11/interrupt.h b/include/arm11/interrupt.h deleted file mode 100644 index 4b0f6c5..0000000 --- a/include/arm11/interrupt.h +++ /dev/null @@ -1,133 +0,0 @@ -#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 . - */ - -#include "types.h" - - -typedef enum -{ - IRQ_MPCORE_SW0 = 0, - IRQ_MPCORE_SW1 = 1, - IRQ_MPCORE_SW2 = 2, - IRQ_MPCORE_SW3 = 3, - IRQ_MPCORE_SW4 = 4, - IRQ_MPCORE_SW5 = 5, - IRQ_MPCORE_SW6 = 6, - IRQ_MPCORE_SW7 = 7, - IRQ_MPCORE_SW8 = 8, - IRQ_MPCORE_SW9 = 9, - IRQ_MPCORE_SW10 = 10, - IRQ_MPCORE_SW11 = 11, - IRQ_MPCORE_SW12 = 12, - IRQ_MPCORE_SW13 = 13, - IRQ_MPCORE_SW14 = 14, - IRQ_MPCORE_SW15 = 15, - IRQ_TIMER = 29, // MPCore timer - IRQ_WATCHDOG = 30, // MPCore watchdog - IRQ_PSC0 = 40, - IRQ_PSC1 = 41, - IRQ_PDC0 = 42, // aka VBlank0 - IRQ_PDC1 = 43, // aka VBlank1 - IRQ_PPF = 44, - IRQ_P3D = 45, // This is a guess - IRQ_PXI_SYNC = 80, - IRQ_PXI_UNK = 81, // Unknown what this is for - IRQ_PXI_NOT_FULL = 82, - IRQ_PXI_NOT_EMPTY = 83, - IRQ_SHELL_OPENED = 96, - IRQ_SHELL_CLOSED = 98, - IRQ_TOUCHSCREEN = 99, // Triggers on hitting the touchscreen. - IRQ_HEADPH_JACK = 100, // Headphone jack. Triggers on both plugging in and out? GPIO reg 9, bit 8. - IRQ_MCU_HID = 113, // HOME/POWER pressed/released, shell opened/closed and WiFi switch pressed. GPIO reg 19, bit 9. - IRQ_GAMECARD = 117 // Gamecard inserted -} Interrupt; - - -// IRQ handler type. -// intSource: bit 10-12 CPU source ID (0 except for interrupt ID 0-15), -// bit 0-9 interrupt ID -typedef void (*IrqHandler)(u32 intSource); - - - -/** - * @brief Initializes the generic interrupt controller. - */ -void IRQ_init(void); - -/** - * @brief Registers a interrupt handler and enables the specified interrupt. - * - * @param[in] id The interrupt ID. Must be <128. - * @param[in] prio The priority. 0 = highest, 14 = lowest, 15 = disabled - * @param[in] cpuMask The CPU mask. Each of the 4 bits stands for 1 core. 0 means current CPU. - * @param[in] edgeTriggered Set to true to make the interrupt edge triggered. false is level triggered. - * @param[in] handler The interrupt handler to call. - */ -void IRQ_registerHandler(Interrupt id, u8 prio, u8 cpuMask, bool edgeTriggered, IrqHandler handler); - -/** - * @brief Unregisters the interrupt handler and disables the specified interrupt. - * - * @param[in] id The interrupt ID. Must be <128. - */ -void IRQ_unregisterHandler(Interrupt id); - -/** - * @brief Sets the priority of an interrupt. - * - * @param[in] id The interrupt ID. Must be <128. - * @param[in] prio The priority. 0 = highest, 14 = lowest, 15 = disabled - */ -void IRQ_setPriority(Interrupt id, u8 prio); - -/** - * @brief Triggers a software interrupt for the specified CPUs. - * - * @param[in] id The interrupt ID. Must be <16. - * @param[in] cpuMask The CPU mask. Each of the 4 bits stands for 1 core. - */ -void IRQ_softwareInterrupt(Interrupt id, u8 cpuMask); - - -static inline void waitForInterrupt(void) -{ - __asm__ __volatile__("wfi" : :); -} - -static inline void enterCriticalSection(void) -{ - __asm__ __volatile__("cpsid i" : :); -} - -static inline void leaveCriticalSection(void) -{ - __asm__ __volatile__("cpsie i" : :); -} - -static inline void waitForEvent(void) -{ - __asm__ __volatile__("wfe" : :); -} - -static inline void signalEvent(void) -{ - __asm__ __volatile__("sev" : :); -} diff --git a/include/arm11/timer.h b/include/arm11/timer.h deleted file mode 100644 index e365370..0000000 --- a/include/arm11/timer.h +++ /dev/null @@ -1,66 +0,0 @@ -#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 . - */ - -#include "types.h" - - -#define TIMER_BASE_FREQ (268111856.0) - -#define TIMER_ENABLE (1u) -#define TIMER_SINGLE_SHOT (0u) -#define TIMER_AUTO_RELOAD (1u<<1) -#define TIMER_IRQ_ENABLE (1u<<2) - -// p is the prescaler value and n the frequence -#define TIMER_FREQ(p, n) (TIMER_BASE_FREQ / 2 / ((p) + 1) / (n)) - - - -/** - * @brief Resets/initializes the timer hardware. Should not be called manually. - */ -void TIMER_init(void); - -/** - * @brief Starts the timer. - * - * @param[in] prescaler The prescaler value. - * @param[in] ticks The initial number of ticks. This is also the - * reload value in auto reload mode. - * @param[in] autoReload Set to true for auto reload. false for single shot. - * @param[in] enableIrq Timer fires IRQs on underflow if true. - */ -void TIMER_start(u8 prescaler, u32 ticks, bool autoReload, bool enableIrq); - -/** - * @brief Stops the timer. - */ -void TIMER_stop(void); - -/** - * @brief Halts the CPU for the specified number of ticks. - * Use the macro below for a milliseconds version. - * - * @param[in] ticks The number of ticks to sleep. - */ -void TIMER_sleepTicks(u32 ticks); - -// Sleeps ms milliseconds. ms can be up to 32000. -#define TIMER_sleepMs(ms) TIMER_sleepTicks(TIMER_FREQ(0, 1000.0) * (ms)) diff --git a/include/arm9/console.h b/include/arm9/console.h index 75cf6fc..d956ee7 100644 --- a/include/arm9/console.h +++ b/include/arm9/console.h @@ -22,7 +22,7 @@ */ #include "types.h" -#include "gfx.h" +#include "hardware/gfx.h" #ifdef __cplusplus extern "C" { diff --git a/include/arm9/crypto.h b/include/arm9/crypto.h deleted file mode 100644 index 16c69d6..0000000 --- a/include/arm9/crypto.h +++ /dev/null @@ -1,254 +0,0 @@ -#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 . - */ - -#include "types.h" - - - -////////////////////////////////// -// AES // -////////////////////////////////// - -#define AES_MAX_BLOCKS (0xFFFF) - -#define AES_WRITE_FIFO_COUNT (REG_AESCNT & 0x1F) -#define AES_READ_FIFO_COUNT (REG_AESCNT & 0x3E0) - -#define AES_FLUSH_READ_FIFO (1u<<10) -#define AES_FLUSH_WRITE_FIFO (1u<<11) -#define AES_MAC_SIZE(n) (((n - 2) / 2)<<16) -#define AES_PASS_PAYLOARD (1u<<19) // Passes the associated data to REG_AESRDFIFO -#define AES_MAC_SRC_REG (1u<<20) -#define AES_IS_MAC_VALID ((bool)(REG_AESCNT>>21 & 1u)) - -#define AES_OUTPUT_BIG (1u) -#define AES_OUTPUT_LITTLE (0u) -#define AES_INPUT_BIG (1u) -#define AES_INPUT_LITTLE (0u) -#define AES_OUTPUT_NORMAL (4u) -#define AES_OUTPUT_REVERSED (0u) -#define AES_INPUT_NORMAL (4u) -#define AES_INPUT_REVERSED (0u) - -#define AES_UPDATE_KEYSLOT (1u<<26) -#define AES_IRQ_ENABLE (1u<<30) -#define AES_ENABLE (1u<<31) - -#define AES_MODE_CCM_DECRYPT (0u) -#define AES_MODE_CCM_ENCRYPT (1u<<27) -#define AES_MODE_CTR (2u<<27) -#define AES_MODE_CBC_DECRYPT (4u<<27) -#define AES_MODE_CBC_ENCRYPT (5u<<27) -#define AES_MODE_ECB_DECRYPT (6u<<27) -#define AES_MODE_ECB_ENCRYPT (7u<<27) - - -typedef enum -{ - AES_KEY_NORMAL = 0, - AES_KEY_X = 1, - AES_KEY_Y = 2, -} AesKeyType; - -typedef struct -{ - u32 ctrIvNonceParams; - u32 ctrIvNonce[4]; - u32 aesParams; -} AES_ctx; - - -/** - * @brief Initializes the AES hardware and the NDMA channels used by it. - */ -void AES_init(void); - -/** - * @brief Deinits AES to workaround a K9L bug. - */ -void AES_deinit(void); - -/** - * @brief Sets a AES key in the specified keyslot. - * - * @param[in] keyslot The keyslot this key will be set for. - * @param[in] type The key type. Can be AES_KEY_NORMAL/X/Y. - * @param[in] orderEndianess Word order and endianess bitmask. - * @param[in] twlScrambler Set to true to use the TWL keyscrambler for keyslots > 0x03. - * @param[in] key Pointer to 128-bit AES key data. - */ -void AES_setKey(u8 keyslot, AesKeyType type, u8 orderEndianess, bool twlScrambler, const u32 key[4]); - -/** - * @brief Selects the given keyslot for all following crypto operations. - * - * @param[in] keyslot The keyslot to select. - */ -void AES_selectKeyslot(u8 keyslot); - -/** - * @brief Copies the given nonce into internal state. - * - * @param ctx Pointer to AES_ctx (AES context). - * @param[in] orderEndianess Word order and endianess bitmask. - * @param[in] nonce Pointer to the nonce data. - */ -void AES_setNonce(AES_ctx *const ctx, u8 orderEndianess, const u32 nonce[3]); - -/** - * @brief Copies the given counter/initialization vector into internal state. - * - * @param ctx Pointer to AES_ctx (AES context). - * @param[in] orderEndianess Word order and endianess bitmask. - * @param[in] ctrIv Pointer to the counter/initialization vector data. - */ -void AES_setCtrIv(AES_ctx *const ctx, u8 orderEndianess, const u32 ctrIv[4]); - -/** - * @brief Increments the internal counter with the given value (CTR mode). - * - * @param ctr Pointer to the counter data. - * @param[in] val Value to increment the counter with. - */ -void AES_addCounter(u32 ctr[4], u32 val); - -/** - * @brief Decrements the internal counter with the given value (CTR mode). - * - * @param ctr Pointer to the counter data. - * @param[in] val Value to decrement the counter with. - */ -void AES_subCounter(u32 ctr[4], u32 val); - -/** - * @brief Sets params in the AES context for all following crypto operations. - * - * @param ctx Pointer to AES_ctx (AES context). - * @param[in] inEndianessOrder Input endianess and word order bitmask. - * @param[in] outEndianessOrder Output endianess and word order bitmask. - */ -void AES_setCryptParams(AES_ctx *const ctx, u8 inEndianessOrder, u8 outEndianessOrder); - -/** - * @brief En-/decrypts data with AES CTR. - * - * @param ctx Pointer to AES_ctx (AES context). - * @param[in] in In data pointer. Can be the same as out. - * @param out Out data pointer. Can be the same as in. - * @param[in] blocks Number of blocks to process. 1 block is 16 bytes. - * @param[in] dma Set to true to enable DMA. - */ -void AES_ctr(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool dma); - -/** - * @brief En-/decrypts data with AES CBC. - * @brief Note: With DMA the output buffer must be invalidated - * @brief after this function, not before. - * - * @param ctx Pointer to AES_ctx (AES context). - * @param[in] in In data pointer. Can be the same as out. - * @param out Out data pointer. Can be the same as in. - * @param[in] blocks Number of blocks to process. 1 block is 16 bytes. - * @param[in] enc Set to true to encrypt and false to decrypt. - * @param[in] dma Set to true to enable DMA. - */ -//void AES_cbc(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool enc, bool dma); - -/** - * @brief En-/decrypts data with AES ECB. - * - * @param ctx Pointer to AES_ctx (AES context). - * @param[in] in In data pointer. Can be the same as out. - * @param out Out data pointer. Can be the same as in. - * @param[in] blocks Number of blocks to process. 1 block is 16 bytes. - * @param[in] enc Set to true to encrypt and false to decrypt. - * @param[in] dma Set to true to enable DMA. - */ -void AES_ecb(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool enc, bool dma); - -/** - * @brief En-/decrypts data with AES CCM. - * @brief Note: The AES hardware implements this in a non-standard way - * @brief limiting it to 1 nonce for 1 MB. - * - * @param ctx Pointer to AES_ctx (AES context). - * @param[in] in In data pointer. Can be the same as out. - * @param out Out data pointer. Can be the same as in. - * @param[in] macSize The AES MAC size in bytes. - * @param mac Pointer to in/out AES MAC. The MAC must/will be padded - * with zeros (non-standard). - * @param[in] blocks Number of blocks to process. 1 block is 16 bytes. - * @param[in] enc Set to true to encrypt and false to decrypt. - * - * @return Returns true in decryption mode if the AES MAC is valid. Otherwise true. - */ -bool AES_ccm(const AES_ctx *const ctx, const u32 *const in, u32 *const out, u32 macSize, - u32 mac[4], u16 blocks, bool enc); - - - -////////////////////////////////// -// SHA // -////////////////////////////////// - -#define SHA_ENABLE (1u) // Also used as busy flag -#define SHA_PAD_INPUT (1u<<1) -#define SHA_INPUT_BIG (1u<<3) -#define SHA_INPUT_LITTLE (0u) -#define SHA_OUTPUT_BIG (SHA_INPUT_BIG) -#define SHA_OUTPUT_LITTLE (SHA_INPUT_LITTLE) -#define SHA_MODE_256 (0u) -#define SHA_MODE_224 (1u<<4) -#define SHA_MODE_1 (2u<<4) - - -/** - * @brief Sets input mode, endianess and starts the hash operation. - * - * @param[in] params Mode and input endianess bitmask. - */ -void SHA_start(u8 params); - -/** - * @brief Hashes the data pointed to. - * - * @param[in] data Pointer to data to hash. - * @param[in] size Size of the data to hash. - */ -void SHA_update(const u32 *data, u32 size); - -/** - * @brief Generates the final hash. - * - * @param hash Pointer to memory to copy the hash to. - * @param[in] endianess Endianess bitmask for the hash. - */ -void SHA_finish(u32 *const hash, u8 endianess); - -/** - * @brief Hashes a single block of data and outputs the hash. - * - * @param[in] data Pointer to data to hash. - * @param[in] size Size of the data to hash. - * @param hash Pointer to memory to copy the hash to. - * @param[in] params Mode and input endianess bitmask. - * @param[in] hashEndianess Endianess bitmask for the hash. - */ -void sha(const u32 *data, u32 size, u32 *const hash, u8 params, u8 hashEndianess); diff --git a/include/arm9/gui/splash.h b/include/arm9/gui/splash.h new file mode 100644 index 0000000..339d385 --- /dev/null +++ b/include/arm9/gui/splash.h @@ -0,0 +1,48 @@ +#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 . + */ + +#include "types.h" + + +#define FLAG_ROTATED (1u<<3) +#define FLAG_COMPRESSED (1u<<4) +#define FLAG_SWAPPED (1u<<5) + + +enum +{ + FORMAT_RGB565 = 0, + FORMAT_RGB8 = 1, + FORMAT_RGBA8 = 2, + FORMAT_INVALID = 7 +}; + +typedef struct +{ + u32 magic; + u16 width; + u16 height; + u32 flags; +} SplashHeader; + + + +void getSplashDimensions(const void *const data, u32 *const width, u32 *const height); +bool drawSplashscreen(const void *const data, s32 startX, s32 startY); diff --git a/include/arm9/gui/ui.h b/include/arm9/gui/ui.h index 638a794..f21c1a9 100644 --- a/include/arm9/gui/ui.h +++ b/include/arm9/gui/ui.h @@ -19,7 +19,7 @@ */ #include "arm9/console.h" -#include "arm9/hid.h" +#include "arm9/hardware/hid.h" #define uiPrintInfo(format, ...) uiPrint(format, 0, false, ##__VA_ARGS__) diff --git a/include/arm9/hardware.h b/include/arm9/hardware.h deleted file mode 100644 index 4e01d31..0000000 --- a/include/arm9/hardware.h +++ /dev/null @@ -1,24 +0,0 @@ -#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 . - */ - - - -void hardwareInit(void); -void hardwareDeinit(void); diff --git a/include/arm9/hardware/crypto.h b/include/arm9/hardware/crypto.h new file mode 100644 index 0000000..16c69d6 --- /dev/null +++ b/include/arm9/hardware/crypto.h @@ -0,0 +1,254 @@ +#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 . + */ + +#include "types.h" + + + +////////////////////////////////// +// AES // +////////////////////////////////// + +#define AES_MAX_BLOCKS (0xFFFF) + +#define AES_WRITE_FIFO_COUNT (REG_AESCNT & 0x1F) +#define AES_READ_FIFO_COUNT (REG_AESCNT & 0x3E0) + +#define AES_FLUSH_READ_FIFO (1u<<10) +#define AES_FLUSH_WRITE_FIFO (1u<<11) +#define AES_MAC_SIZE(n) (((n - 2) / 2)<<16) +#define AES_PASS_PAYLOARD (1u<<19) // Passes the associated data to REG_AESRDFIFO +#define AES_MAC_SRC_REG (1u<<20) +#define AES_IS_MAC_VALID ((bool)(REG_AESCNT>>21 & 1u)) + +#define AES_OUTPUT_BIG (1u) +#define AES_OUTPUT_LITTLE (0u) +#define AES_INPUT_BIG (1u) +#define AES_INPUT_LITTLE (0u) +#define AES_OUTPUT_NORMAL (4u) +#define AES_OUTPUT_REVERSED (0u) +#define AES_INPUT_NORMAL (4u) +#define AES_INPUT_REVERSED (0u) + +#define AES_UPDATE_KEYSLOT (1u<<26) +#define AES_IRQ_ENABLE (1u<<30) +#define AES_ENABLE (1u<<31) + +#define AES_MODE_CCM_DECRYPT (0u) +#define AES_MODE_CCM_ENCRYPT (1u<<27) +#define AES_MODE_CTR (2u<<27) +#define AES_MODE_CBC_DECRYPT (4u<<27) +#define AES_MODE_CBC_ENCRYPT (5u<<27) +#define AES_MODE_ECB_DECRYPT (6u<<27) +#define AES_MODE_ECB_ENCRYPT (7u<<27) + + +typedef enum +{ + AES_KEY_NORMAL = 0, + AES_KEY_X = 1, + AES_KEY_Y = 2, +} AesKeyType; + +typedef struct +{ + u32 ctrIvNonceParams; + u32 ctrIvNonce[4]; + u32 aesParams; +} AES_ctx; + + +/** + * @brief Initializes the AES hardware and the NDMA channels used by it. + */ +void AES_init(void); + +/** + * @brief Deinits AES to workaround a K9L bug. + */ +void AES_deinit(void); + +/** + * @brief Sets a AES key in the specified keyslot. + * + * @param[in] keyslot The keyslot this key will be set for. + * @param[in] type The key type. Can be AES_KEY_NORMAL/X/Y. + * @param[in] orderEndianess Word order and endianess bitmask. + * @param[in] twlScrambler Set to true to use the TWL keyscrambler for keyslots > 0x03. + * @param[in] key Pointer to 128-bit AES key data. + */ +void AES_setKey(u8 keyslot, AesKeyType type, u8 orderEndianess, bool twlScrambler, const u32 key[4]); + +/** + * @brief Selects the given keyslot for all following crypto operations. + * + * @param[in] keyslot The keyslot to select. + */ +void AES_selectKeyslot(u8 keyslot); + +/** + * @brief Copies the given nonce into internal state. + * + * @param ctx Pointer to AES_ctx (AES context). + * @param[in] orderEndianess Word order and endianess bitmask. + * @param[in] nonce Pointer to the nonce data. + */ +void AES_setNonce(AES_ctx *const ctx, u8 orderEndianess, const u32 nonce[3]); + +/** + * @brief Copies the given counter/initialization vector into internal state. + * + * @param ctx Pointer to AES_ctx (AES context). + * @param[in] orderEndianess Word order and endianess bitmask. + * @param[in] ctrIv Pointer to the counter/initialization vector data. + */ +void AES_setCtrIv(AES_ctx *const ctx, u8 orderEndianess, const u32 ctrIv[4]); + +/** + * @brief Increments the internal counter with the given value (CTR mode). + * + * @param ctr Pointer to the counter data. + * @param[in] val Value to increment the counter with. + */ +void AES_addCounter(u32 ctr[4], u32 val); + +/** + * @brief Decrements the internal counter with the given value (CTR mode). + * + * @param ctr Pointer to the counter data. + * @param[in] val Value to decrement the counter with. + */ +void AES_subCounter(u32 ctr[4], u32 val); + +/** + * @brief Sets params in the AES context for all following crypto operations. + * + * @param ctx Pointer to AES_ctx (AES context). + * @param[in] inEndianessOrder Input endianess and word order bitmask. + * @param[in] outEndianessOrder Output endianess and word order bitmask. + */ +void AES_setCryptParams(AES_ctx *const ctx, u8 inEndianessOrder, u8 outEndianessOrder); + +/** + * @brief En-/decrypts data with AES CTR. + * + * @param ctx Pointer to AES_ctx (AES context). + * @param[in] in In data pointer. Can be the same as out. + * @param out Out data pointer. Can be the same as in. + * @param[in] blocks Number of blocks to process. 1 block is 16 bytes. + * @param[in] dma Set to true to enable DMA. + */ +void AES_ctr(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool dma); + +/** + * @brief En-/decrypts data with AES CBC. + * @brief Note: With DMA the output buffer must be invalidated + * @brief after this function, not before. + * + * @param ctx Pointer to AES_ctx (AES context). + * @param[in] in In data pointer. Can be the same as out. + * @param out Out data pointer. Can be the same as in. + * @param[in] blocks Number of blocks to process. 1 block is 16 bytes. + * @param[in] enc Set to true to encrypt and false to decrypt. + * @param[in] dma Set to true to enable DMA. + */ +//void AES_cbc(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool enc, bool dma); + +/** + * @brief En-/decrypts data with AES ECB. + * + * @param ctx Pointer to AES_ctx (AES context). + * @param[in] in In data pointer. Can be the same as out. + * @param out Out data pointer. Can be the same as in. + * @param[in] blocks Number of blocks to process. 1 block is 16 bytes. + * @param[in] enc Set to true to encrypt and false to decrypt. + * @param[in] dma Set to true to enable DMA. + */ +void AES_ecb(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool enc, bool dma); + +/** + * @brief En-/decrypts data with AES CCM. + * @brief Note: The AES hardware implements this in a non-standard way + * @brief limiting it to 1 nonce for 1 MB. + * + * @param ctx Pointer to AES_ctx (AES context). + * @param[in] in In data pointer. Can be the same as out. + * @param out Out data pointer. Can be the same as in. + * @param[in] macSize The AES MAC size in bytes. + * @param mac Pointer to in/out AES MAC. The MAC must/will be padded + * with zeros (non-standard). + * @param[in] blocks Number of blocks to process. 1 block is 16 bytes. + * @param[in] enc Set to true to encrypt and false to decrypt. + * + * @return Returns true in decryption mode if the AES MAC is valid. Otherwise true. + */ +bool AES_ccm(const AES_ctx *const ctx, const u32 *const in, u32 *const out, u32 macSize, + u32 mac[4], u16 blocks, bool enc); + + + +////////////////////////////////// +// SHA // +////////////////////////////////// + +#define SHA_ENABLE (1u) // Also used as busy flag +#define SHA_PAD_INPUT (1u<<1) +#define SHA_INPUT_BIG (1u<<3) +#define SHA_INPUT_LITTLE (0u) +#define SHA_OUTPUT_BIG (SHA_INPUT_BIG) +#define SHA_OUTPUT_LITTLE (SHA_INPUT_LITTLE) +#define SHA_MODE_256 (0u) +#define SHA_MODE_224 (1u<<4) +#define SHA_MODE_1 (2u<<4) + + +/** + * @brief Sets input mode, endianess and starts the hash operation. + * + * @param[in] params Mode and input endianess bitmask. + */ +void SHA_start(u8 params); + +/** + * @brief Hashes the data pointed to. + * + * @param[in] data Pointer to data to hash. + * @param[in] size Size of the data to hash. + */ +void SHA_update(const u32 *data, u32 size); + +/** + * @brief Generates the final hash. + * + * @param hash Pointer to memory to copy the hash to. + * @param[in] endianess Endianess bitmask for the hash. + */ +void SHA_finish(u32 *const hash, u8 endianess); + +/** + * @brief Hashes a single block of data and outputs the hash. + * + * @param[in] data Pointer to data to hash. + * @param[in] size Size of the data to hash. + * @param hash Pointer to memory to copy the hash to. + * @param[in] params Mode and input endianess bitmask. + * @param[in] hashEndianess Endianess bitmask for the hash. + */ +void sha(const u32 *data, u32 size, u32 *const hash, u8 params, u8 hashEndianess); diff --git a/include/arm9/hardware/hardware.h b/include/arm9/hardware/hardware.h new file mode 100644 index 0000000..4e01d31 --- /dev/null +++ b/include/arm9/hardware/hardware.h @@ -0,0 +1,24 @@ +#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 . + */ + + + +void hardwareInit(void); +void hardwareDeinit(void); diff --git a/include/arm9/hardware/hid.h b/include/arm9/hardware/hid.h new file mode 100644 index 0000000..e107224 --- /dev/null +++ b/include/arm9/hardware/hid.h @@ -0,0 +1,34 @@ +#pragma once + +/* + * This code is part of ctrulib (https://github.com/smealum/ctrulib) + */ + +#include "types.h" + + +#define HID_KEY_MASK_ALL ((KEY_Y << 1) - 1) +#define HID_VERBOSE_MODE_BUTTONS (KEY_SELECT | KEY_START) + +enum +{ + KEY_A = (1), + KEY_B = (1<<1), + KEY_SELECT = (1<<2), + KEY_START = (1<<3), + KEY_DRIGHT = (1<<4), + KEY_DLEFT = (1<<5), + KEY_DUP = (1<<6), + KEY_DDOWN = (1<<7), + KEY_R = (1<<8), + KEY_L = (1<<9), + KEY_X = (1<<10), + KEY_Y = (1<<11) +}; + + + +void hidScanInput(void); +u32 hidKeysHeld(void); +u32 hidKeysDown(void); +u32 hidKeysUp(void); diff --git a/include/arm9/hardware/interrupt.h b/include/arm9/hardware/interrupt.h new file mode 100644 index 0000000..edfdd36 --- /dev/null +++ b/include/arm9/hardware/interrupt.h @@ -0,0 +1,104 @@ +#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 . + */ + +#include "types.h" + + +typedef enum +{ + IRQ_DMAC_1_0 = 0, // DMAC_1 = NDMA + IRQ_DMAC_1_1 = 1, + IRQ_DMAC_1_2 = 2, + IRQ_DMAC_1_3 = 3, + IRQ_DMAC_1_4 = 4, + IRQ_DMAC_1_5 = 5, + IRQ_DMAC_1_6 = 6, + IRQ_DMAC_1_7 = 7, + IRQ_TIMER_0 = 8, + IRQ_TIMER_1 = 9, + IRQ_TIMER_2 = 10, + IRQ_TIMER_3 = 11, + IRQ_PXI_SYNC = 12, + IRQ_PXI_NOT_FULL = 13, + IRQ_PXI_NOT_EMPTY = 14, + IRQ_AES = 15, + IRQ_SDIO_1 = 16, + IRQ_SDIO_1_ASYNC = 17, + IRQ_SDIO_3 = 18, + IRQ_SDIO_3_ASYNC = 19, + IRQ_DEBUG_RECV = 20, + IRQ_DEBUG_SEND = 21, + IRQ_RSA = 22, + IRQ_CTR_CARD_1 = 23, + IRQ_CTR_CARD_2 = 24, + IRQ_CGC = 25, + IRQ_CGC_DET = 26, + IRQ_DS_CARD = 27, + IRQ_DMAC_2 = 28, + IRQ_DMAC_2_ABORT = 29 +} Interrupt; + + +// IRQ handler type. +// id: contains the interrupt ID +typedef void (*IrqHandler)(u32 id); + + + +/** + * @brief Initializes interrupts. + */ +void IRQ_init(void); + +/** + * @brief Registers a interrupt handler and enables the specified interrupt. + * + * @param[in] id The interrupt ID. Must be <32. + * @param[in] handler The interrupt handler to call. + */ +void IRQ_registerHandler(Interrupt id, IrqHandler handler); + +/** + * @brief Unregisters the interrupt handler and disables the specified interrupt. + * + * @param[in] id The interrupt ID. Must be <32. + */ +void IRQ_unregisterHandler(Interrupt id); + + +static inline void waitForInterrupt(void) +{ + __asm__ __volatile__("mcr p15, 0, %0, c7, c0, 4" : : "r" (0)); +} + +inline u32 enterCriticalSection(void) +{ + u32 tmp; + __asm__ __volatile__("mrs %0, cpsr" : "=r" (tmp) : ); + __asm__ __volatile__("msr cpsr_c, %0" : : "r" (tmp | 0x80u)); + return tmp & 0x80u; +} + +inline void leaveCriticalSection(u32 oldState) +{ + u32 tmp; + __asm__ __volatile__("mrs %0, cpsr" : "=r" (tmp) : ); + __asm__ __volatile__("msr cpsr_c, %0" : : "r" ((tmp & ~(0x80u)) | oldState)); +} diff --git a/include/arm9/hardware/ndma.h b/include/arm9/hardware/ndma.h new file mode 100644 index 0000000..0cc769d --- /dev/null +++ b/include/arm9/hardware/ndma.h @@ -0,0 +1,188 @@ +#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 . + */ + +#include +#include "mem_map.h" +#include "types.h" + + +#define NDMA_REGS_BASE (IO_MEM_ARM9_ONLY + 0x2000) +#define REG_NDMA_GLOBAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x00)) + +#define REG_NDMA0_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x04)) +#define REG_NDMA0_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x08)) +#define REG_NDMA0_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x0C)) // Total repeat length in words +#define REG_NDMA0_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x10)) // Logical block size in words +#define REG_NDMA0_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x14)) // Timing/interval settings +#define REG_NDMA0_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x18)) +#define REG_NDMA0_CNT *((vu32*)(NDMA_REGS_BASE + 0x1C)) + +#define REG_NDMA1_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x20)) +#define REG_NDMA1_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x24)) +#define REG_NDMA1_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x28)) +#define REG_NDMA1_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x2C)) +#define REG_NDMA1_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x30)) +#define REG_NDMA1_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x34)) +#define REG_NDMA1_CNT *((vu32*)(NDMA_REGS_BASE + 0x38)) + +#define REG_NDMA2_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x3C)) +#define REG_NDMA2_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x40)) +#define REG_NDMA2_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x44)) +#define REG_NDMA2_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x48)) +#define REG_NDMA2_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x4C)) +#define REG_NDMA2_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x50)) +#define REG_NDMA2_CNT *((vu32*)(NDMA_REGS_BASE + 0x54)) + +#define REG_NDMA3_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x58)) +#define REG_NDMA3_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x5C)) +#define REG_NDMA3_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x60)) +#define REG_NDMA3_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x64)) +#define REG_NDMA3_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x68)) +#define REG_NDMA3_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x6C)) +#define REG_NDMA3_CNT *((vu32*)(NDMA_REGS_BASE + 0x70)) + +#define REG_NDMA4_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x74)) +#define REG_NDMA4_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x78)) +#define REG_NDMA4_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x7C)) +#define REG_NDMA4_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x80)) +#define REG_NDMA4_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x84)) +#define REG_NDMA4_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x88)) +#define REG_NDMA4_CNT *((vu32*)(NDMA_REGS_BASE + 0x8C)) + +#define REG_NDMA5_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x90)) +#define REG_NDMA5_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x94)) +#define REG_NDMA5_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x98)) +#define REG_NDMA5_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x9C)) +#define REG_NDMA5_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0xA0)) +#define REG_NDMA5_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0xA4)) +#define REG_NDMA5_CNT *((vu32*)(NDMA_REGS_BASE + 0xA8)) + +#define REG_NDMA6_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0xAC)) +#define REG_NDMA6_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0xB0)) +#define REG_NDMA6_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0xB4)) +#define REG_NDMA6_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0xB8)) +#define REG_NDMA6_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0xBC)) +#define REG_NDMA6_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0xC0)) +#define REG_NDMA6_CNT *((vu32*)(NDMA_REGS_BASE + 0xC4)) + +#define REG_NDMA7_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0xC8)) +#define REG_NDMA7_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0xCC)) +#define REG_NDMA7_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0xD0)) +#define REG_NDMA7_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0xD4)) +#define REG_NDMA7_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0xD8)) +#define REG_NDMA7_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0xDC)) +#define REG_NDMA7_CNT *((vu32*)(NDMA_REGS_BASE + 0xE0)) + +#define REG_NDMA_SRC_ADDR(n) *((vu32*)(NDMA_REGS_BASE + 0x04 + (n * 28))) +#define REG_NDMA_DST_ADDR(n) *((vu32*)(NDMA_REGS_BASE + 0x08 + (n * 28))) +#define REG_NDMA_TOTAL_CNT(n) *((vu32*)(NDMA_REGS_BASE + 0x0C + (n * 28))) +#define REG_NDMA_LOG_BLK_CNT(n) *((vu32*)(NDMA_REGS_BASE + 0x10 + (n * 28))) +#define REG_NDMA_INT_CNT(n) *((vu32*)(NDMA_REGS_BASE + 0x14 + (n * 28))) +#define REG_NDMA_FILL_DATA(n) *((vu32*)(NDMA_REGS_BASE + 0x18 + (n * 28))) +#define REG_NDMA_CNT(n) *((vu32*)(NDMA_REGS_BASE + 0x1C + (n * 28))) + + +// REG_NDMA_GLOBAL_CNT +#define NDMA_ROUND_ROBIN(n) ((u32)log2(n)<<16 | 1u<<31 | 1u) // n = number of CPU cycles +#define NDMA_HIGHEST_PRIO (1u) + +// REG_NDMA_INT_CNT +#define NDMA_INT_SYS_FREQ (0u) + +// REG_NDMA_CNT +#define NDMA_DST_UPDATE_INC (0u) +#define NDMA_DST_UPDATE_DEC (1u<<10) +#define NDMA_DST_UPDATE_FIXED (2u<<10) +#define NDMA_DST_ADDR_RELOAD (1u<<12) +#define NDMA_SRC_UPDATE_INC (0u) +#define NDMA_SRC_UPDATE_DEC (1u<<13) +#define NDMA_SRC_UPDATE_FIXED (2u<<13) +#define NDMA_SRC_UPDATE_FILL (3u<<13) +#define NDMA_SRC_ADDR_RELOAD (1u<<15) +// The block length is 2^n words (Example: 2^15 = 32768 words = 0x20000 bytes) +#define NDMA_BURST_SIZE(n) ((u32)log2(n)<<16) +#define NDMA_REPEATING_MODE (1u<<29) +#define NDMA_IRQ_ENABLE (1u<<30) +#define NDMA_ENABLE (1u<<31) + + + enum + { + NDMA_STARTUP_TIMER0 = (0<<24), // Unconfirmed + NDMA_STARTUP_TIMER1 = (1<<24), // Unconfirmed + NDMA_STARTUP_TIMER2 = (2<<24), // Unconfirmed + NDMA_STARTUP_TIMER3 = (3<<24), // Unconfirmed + NDMA_STARTUP_CTRCARD0 = (4<<24), + NDMA_STARTUP_CTRCARD1 = (5<<24), + NDMA_STARTUP_UNK_6 = (6<<24), + NDMA_STARTUP_EMMC = (7<<24), + NDMA_STARTUP_AES_IN = (8<<24), // AES write fifo + NDMA_STARTUP_AES_OUT = (9<<24), // AES read fifo + NDMA_STARTUP_SHA = (10<<24), + NDMA_STARTUP_UNK_11 = (11<<24), + NDMA_STARTUP_UNK_12 = (12<<24), + NDMA_STARTUP_UNK_13 = (13<<24), + NDMA_STARTUP_UNK_14 = (14<<24), + NDMA_STARTUP_AES_SHA = (15<<24), // Unconfirmed + NDMA_STARTUP_IMMEDIATE = (16<<24) + }; + + + +/** + * @brief Initializes all NDMA channels. + */ +void NDMA_init(void); + +/** + * @brief Asynchronous copying of data using the NDMA engine. + * + * @param dest Pointer to destination memory. Must be 4 bytes aligned. + * @param source Pointer to source data. Must be 4 bytes aligned. + * @param[in] size The size of the data. Must be multiple of 4. + */ +void NDMA_copyAsync(u32 *dest, const u32 *source, u32 num); + +/** + * @brief Copies data using the NDMA engine. + * + * @param dest Pointer to destination memory. Must be 4 bytes aligned. + * @param source Pointer to source data. Must be 4 bytes aligned. + * @param[in] size The size of the data. Must be multiple of 4. + */ +void NDMA_copy(u32 *dest, const u32 *source, u32 size); + +/** + * @brief Asynchronous memory fill with the given value using the NDMA engine. + * + * @param dest Pointer to destination memory. Must be 4 bytes aligned. + * @param[in] value The value each 32-bit word will be set to. + * @param[in] size The size of the memory to fill. Must be multiple of 4. + */ +void NDMA_fillAsync(u32 *dest, u32 value, u32 size); + +/** + * @brief Fills memory with the given value using the NDMA engine. + * + * @param dest Pointer to destination memory. Must be 4 bytes aligned. + * @param[in] value The value each 32-bit word will be set to. + * @param[in] size The size of the memory to fill. Must be multiple of 4. + */ +void NDMA_fill(u32 *dest, u32 value, u32 size); diff --git a/include/arm9/hardware/sdmmc.h b/include/arm9/hardware/sdmmc.h new file mode 100644 index 0000000..ac08efc --- /dev/null +++ b/include/arm9/hardware/sdmmc.h @@ -0,0 +1,185 @@ +#ifndef __SDMMC_H__ +#define __SDMMC_H__ + +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2014-2015, Normmatt + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2, as described below: + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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/. + */ + +#include +#include "types.h" + +#define SDMMC_BASE 0x10006000 + +#define REG_SDCMD 0x00 +#define REG_SDPORTSEL 0x02 +#define REG_SDCMDARG 0x04 +#define REG_SDCMDARG0 0x04 +#define REG_SDCMDARG1 0x06 +#define REG_SDSTOP 0x08 +#define REG_SDBLKCOUNT 0x0a + +#define REG_SDRESP0 0x0c +#define REG_SDRESP1 0x0e +#define REG_SDRESP2 0x10 +#define REG_SDRESP3 0x12 +#define REG_SDRESP4 0x14 +#define REG_SDRESP5 0x16 +#define REG_SDRESP6 0x18 +#define REG_SDRESP7 0x1a + +#define REG_SDSTATUS0 0x1c +#define REG_SDSTATUS1 0x1e + +#define REG_SDIRMASK0 0x20 +#define REG_SDIRMASK1 0x22 +#define REG_SDCLKCTL 0x24 + +#define REG_SDBLKLEN 0x26 +#define REG_SDOPT 0x28 +#define REG_SDFIFO 0x30 + +#define REG_DATACTL 0xd8 +#define REG_SDRESET 0xe0 +#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not? + +#define REG_DATACTL32 0x100 +#define REG_SDBLKLEN32 0x104 +#define REG_SDBLKCOUNT32 0x108 +#define REG_SDFIFO32 0x10C + +#define REG_CLK_AND_WAIT_CTL 0x138 +#define REG_RESET_SDIO 0x1e0 + +#define TMIO_STAT0_CMDRESPEND 0x0001 +#define TMIO_STAT0_DATAEND 0x0004 +#define TMIO_STAT0_CARD_REMOVE 0x0008 +#define TMIO_STAT0_CARD_INSERT 0x0010 +#define TMIO_STAT0_SIGSTATE 0x0020 +#define TMIO_STAT0_WRPROTECT 0x0080 +#define TMIO_STAT0_CARD_REMOVE_A 0x0100 +#define TMIO_STAT0_CARD_INSERT_A 0x0200 +#define TMIO_STAT0_SIGSTATE_A 0x0400 +#define TMIO_STAT1_CMD_IDX_ERR 0x0001 +#define TMIO_STAT1_CRCFAIL 0x0002 +#define TMIO_STAT1_STOPBIT_ERR 0x0004 +#define TMIO_STAT1_DATATIMEOUT 0x0008 +#define TMIO_STAT1_RXOVERFLOW 0x0010 +#define TMIO_STAT1_TXUNDERRUN 0x0020 +#define TMIO_STAT1_CMDTIMEOUT 0x0040 +#define TMIO_STAT1_RXRDY 0x0100 +#define TMIO_STAT1_TXRQ 0x0200 +#define TMIO_STAT1_ILL_FUNC 0x2000 +#define TMIO_STAT1_CMD_BUSY 0x4000 +#define TMIO_STAT1_ILL_ACCESS 0x8000 + +#define TMIO_MASK_ALL 0x837f031d + +#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \ + TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR) + +#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND) +#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND) + +#ifdef __cplusplus +extern "C" { +#endif + + typedef struct mmcdevice { + uint8_t* rData; + const uint8_t* tData; + uint32_t size; + uint32_t error; + uint16_t stat0; + uint16_t stat1; + uint32_t ret[4]; + uint32_t initarg; + uint32_t isSDHC; + uint32_t clk; + uint32_t SDOPT; + uint32_t devicenumber; + uint32_t total_size; //size in sectors of the device + uint32_t res; + } mmcdevice; + + void sdmmc_init(); + int sdmmc_sdcard_readsector(uint32_t sector_no, uint8_t *out); + int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out); + int sdmmc_sdcard_writesector(uint32_t sector_no, const uint8_t *in); + int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, const uint8_t *in); + + int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out); + int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, const uint8_t *in); + + int sdmmc_get_cid(bool isNand, uint32_t *info); + + mmcdevice *getMMCDevice(int drive); + + void InitSD(); + int Nand_Init(); + int SD_Init(); + +#ifdef __cplusplus +}; +#endif + +//--------------------------------------------------------------------------------- +static inline uint16_t sdmmc_read16(uint16_t reg) { +//--------------------------------------------------------------------------------- + return *(volatile uint16_t*)(SDMMC_BASE + reg); +} + +//--------------------------------------------------------------------------------- +static inline void sdmmc_write16(uint16_t reg, uint16_t val) { +//--------------------------------------------------------------------------------- + *(volatile uint16_t*)(SDMMC_BASE + reg) = val; +} + +//--------------------------------------------------------------------------------- +static inline uint32_t sdmmc_read32(uint16_t reg) { +//--------------------------------------------------------------------------------- + return *(volatile uint32_t*)(SDMMC_BASE + reg); +} + +//--------------------------------------------------------------------------------- +static inline void sdmmc_write32(uint16_t reg, uint32_t val) { +//--------------------------------------------------------------------------------- + *(volatile uint32_t*)(SDMMC_BASE + reg) = val; +} + +//--------------------------------------------------------------------------------- +static inline void sdmmc_mask16(uint16_t reg, const uint16_t clear, const uint16_t set) { +//--------------------------------------------------------------------------------- + uint16_t val = sdmmc_read16(reg); + val &= ~clear; + val |= set; + sdmmc_write16(reg, val); +} + +static inline void setckl(uint32_t data) +{ + sdmmc_mask16(REG_SDCLKCTL,0x100,0); + sdmmc_mask16(REG_SDCLKCTL,0x2FF,data&0x2FF); + sdmmc_mask16(REG_SDCLKCTL,0x0,0x100); +} + +#endif diff --git a/include/arm9/hardware/spiflash.h b/include/arm9/hardware/spiflash.h new file mode 100644 index 0000000..d935be1 --- /dev/null +++ b/include/arm9/hardware/spiflash.h @@ -0,0 +1,31 @@ +#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 . + */ + +#include "types.h" + + +#define SPIFLASH_CMD_RDSR (0x05) +#define SPIFLASH_CMD_READ (0x03) + + + +// true if spiflash is installed, false otherwise +bool spiflash_get_status(); +void spiflash_read(u32 offset, u32 size, u8 *buf); diff --git a/include/arm9/hardware/timer.h b/include/arm9/hardware/timer.h new file mode 100644 index 0000000..cd62d93 --- /dev/null +++ b/include/arm9/hardware/timer.h @@ -0,0 +1,83 @@ +#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 . + */ + +#include "types.h" + + +#define TIMER_BASE_FREQ (67027963.95) + +#define TIMER_COUNT_UP (1u<<2) // For cascading at least 2 timers +#define TIMER_IRQ_ENABLE (1u<<6) +#define TIMER_ENABLE (1u<<7) + +// Convenience macros for calculating the ticks. Based on libnds +#define TIMER_FREQ(n) (0x10000u - (u16)(TIMER_BASE_FREQ / n)) +#define TIMER_FREQ_64(n) (0x10000u - (u16)(TIMER_BASE_FREQ / 64.0 / n)) +#define TIMER_FREQ_256(n) (0x10000u - (u16)(TIMER_BASE_FREQ / 256.0 / n)) +#define TIMER_FREQ_1024(n) (0x10000u - (u16)(TIMER_BASE_FREQ / 1024.0 / n)) + + +typedef enum +{ + TIMER_0 = 0, + TIMER_1 = 1, + TIMER_2 = 2, + TIMER_3 = 3 +} Timer; + +typedef enum +{ + TIMER_PRESCALER_1 = 0, + TIMER_PRESCALER_64 = 1, + TIMER_PRESCALER_256 = 2, + TIMER_PRESCALER_1024 = 3 +} TimerPrescaler; + + + +/** + * @brief Resets/initializes the timer hardware. Should not be called manually. + */ +void TIMER_init(void); + +/** + * @brief Starts a timer. + * + * @param[in] timer The timer to start. + * @param[in] prescaler The prescaler to use. + * @param[in] ticks The initial number of ticks. This is also the reload + * value on overflow. + * @param[in] enableIrq Timer fires IRQs if true. + */ +void TIMER_start(Timer timer, TimerPrescaler prescaler, u16 ticks, bool enableIrq); + +/** + * @brief Stops a timer. + * + * @param[in] timer The timer to stop. + */ +void TIMER_stop(Timer timer); + +/** + * @brief Halts the CPU for the specified number of milliseconds. + * + * @param[in] ms The number of milliseconds to sleep. + */ +void TIMER_sleep(u32 ms); diff --git a/include/arm9/hid.h b/include/arm9/hid.h deleted file mode 100644 index e107224..0000000 --- a/include/arm9/hid.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -/* - * This code is part of ctrulib (https://github.com/smealum/ctrulib) - */ - -#include "types.h" - - -#define HID_KEY_MASK_ALL ((KEY_Y << 1) - 1) -#define HID_VERBOSE_MODE_BUTTONS (KEY_SELECT | KEY_START) - -enum -{ - KEY_A = (1), - KEY_B = (1<<1), - KEY_SELECT = (1<<2), - KEY_START = (1<<3), - KEY_DRIGHT = (1<<4), - KEY_DLEFT = (1<<5), - KEY_DUP = (1<<6), - KEY_DDOWN = (1<<7), - KEY_R = (1<<8), - KEY_L = (1<<9), - KEY_X = (1<<10), - KEY_Y = (1<<11) -}; - - - -void hidScanInput(void); -u32 hidKeysHeld(void); -u32 hidKeysDown(void); -u32 hidKeysUp(void); diff --git a/include/arm9/interrupt.h b/include/arm9/interrupt.h deleted file mode 100644 index edfdd36..0000000 --- a/include/arm9/interrupt.h +++ /dev/null @@ -1,104 +0,0 @@ -#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 . - */ - -#include "types.h" - - -typedef enum -{ - IRQ_DMAC_1_0 = 0, // DMAC_1 = NDMA - IRQ_DMAC_1_1 = 1, - IRQ_DMAC_1_2 = 2, - IRQ_DMAC_1_3 = 3, - IRQ_DMAC_1_4 = 4, - IRQ_DMAC_1_5 = 5, - IRQ_DMAC_1_6 = 6, - IRQ_DMAC_1_7 = 7, - IRQ_TIMER_0 = 8, - IRQ_TIMER_1 = 9, - IRQ_TIMER_2 = 10, - IRQ_TIMER_3 = 11, - IRQ_PXI_SYNC = 12, - IRQ_PXI_NOT_FULL = 13, - IRQ_PXI_NOT_EMPTY = 14, - IRQ_AES = 15, - IRQ_SDIO_1 = 16, - IRQ_SDIO_1_ASYNC = 17, - IRQ_SDIO_3 = 18, - IRQ_SDIO_3_ASYNC = 19, - IRQ_DEBUG_RECV = 20, - IRQ_DEBUG_SEND = 21, - IRQ_RSA = 22, - IRQ_CTR_CARD_1 = 23, - IRQ_CTR_CARD_2 = 24, - IRQ_CGC = 25, - IRQ_CGC_DET = 26, - IRQ_DS_CARD = 27, - IRQ_DMAC_2 = 28, - IRQ_DMAC_2_ABORT = 29 -} Interrupt; - - -// IRQ handler type. -// id: contains the interrupt ID -typedef void (*IrqHandler)(u32 id); - - - -/** - * @brief Initializes interrupts. - */ -void IRQ_init(void); - -/** - * @brief Registers a interrupt handler and enables the specified interrupt. - * - * @param[in] id The interrupt ID. Must be <32. - * @param[in] handler The interrupt handler to call. - */ -void IRQ_registerHandler(Interrupt id, IrqHandler handler); - -/** - * @brief Unregisters the interrupt handler and disables the specified interrupt. - * - * @param[in] id The interrupt ID. Must be <32. - */ -void IRQ_unregisterHandler(Interrupt id); - - -static inline void waitForInterrupt(void) -{ - __asm__ __volatile__("mcr p15, 0, %0, c7, c0, 4" : : "r" (0)); -} - -inline u32 enterCriticalSection(void) -{ - u32 tmp; - __asm__ __volatile__("mrs %0, cpsr" : "=r" (tmp) : ); - __asm__ __volatile__("msr cpsr_c, %0" : : "r" (tmp | 0x80u)); - return tmp & 0x80u; -} - -inline void leaveCriticalSection(u32 oldState) -{ - u32 tmp; - __asm__ __volatile__("mrs %0, cpsr" : "=r" (tmp) : ); - __asm__ __volatile__("msr cpsr_c, %0" : : "r" ((tmp & ~(0x80u)) | oldState)); -} diff --git a/include/arm9/ndma.h b/include/arm9/ndma.h deleted file mode 100644 index 0cc769d..0000000 --- a/include/arm9/ndma.h +++ /dev/null @@ -1,188 +0,0 @@ -#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 . - */ - -#include -#include "mem_map.h" -#include "types.h" - - -#define NDMA_REGS_BASE (IO_MEM_ARM9_ONLY + 0x2000) -#define REG_NDMA_GLOBAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x00)) - -#define REG_NDMA0_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x04)) -#define REG_NDMA0_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x08)) -#define REG_NDMA0_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x0C)) // Total repeat length in words -#define REG_NDMA0_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x10)) // Logical block size in words -#define REG_NDMA0_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x14)) // Timing/interval settings -#define REG_NDMA0_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x18)) -#define REG_NDMA0_CNT *((vu32*)(NDMA_REGS_BASE + 0x1C)) - -#define REG_NDMA1_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x20)) -#define REG_NDMA1_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x24)) -#define REG_NDMA1_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x28)) -#define REG_NDMA1_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x2C)) -#define REG_NDMA1_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x30)) -#define REG_NDMA1_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x34)) -#define REG_NDMA1_CNT *((vu32*)(NDMA_REGS_BASE + 0x38)) - -#define REG_NDMA2_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x3C)) -#define REG_NDMA2_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x40)) -#define REG_NDMA2_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x44)) -#define REG_NDMA2_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x48)) -#define REG_NDMA2_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x4C)) -#define REG_NDMA2_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x50)) -#define REG_NDMA2_CNT *((vu32*)(NDMA_REGS_BASE + 0x54)) - -#define REG_NDMA3_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x58)) -#define REG_NDMA3_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x5C)) -#define REG_NDMA3_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x60)) -#define REG_NDMA3_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x64)) -#define REG_NDMA3_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x68)) -#define REG_NDMA3_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x6C)) -#define REG_NDMA3_CNT *((vu32*)(NDMA_REGS_BASE + 0x70)) - -#define REG_NDMA4_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x74)) -#define REG_NDMA4_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x78)) -#define REG_NDMA4_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x7C)) -#define REG_NDMA4_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x80)) -#define REG_NDMA4_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0x84)) -#define REG_NDMA4_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0x88)) -#define REG_NDMA4_CNT *((vu32*)(NDMA_REGS_BASE + 0x8C)) - -#define REG_NDMA5_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0x90)) -#define REG_NDMA5_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0x94)) -#define REG_NDMA5_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0x98)) -#define REG_NDMA5_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0x9C)) -#define REG_NDMA5_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0xA0)) -#define REG_NDMA5_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0xA4)) -#define REG_NDMA5_CNT *((vu32*)(NDMA_REGS_BASE + 0xA8)) - -#define REG_NDMA6_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0xAC)) -#define REG_NDMA6_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0xB0)) -#define REG_NDMA6_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0xB4)) -#define REG_NDMA6_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0xB8)) -#define REG_NDMA6_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0xBC)) -#define REG_NDMA6_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0xC0)) -#define REG_NDMA6_CNT *((vu32*)(NDMA_REGS_BASE + 0xC4)) - -#define REG_NDMA7_SRC_ADDR *((vu32*)(NDMA_REGS_BASE + 0xC8)) -#define REG_NDMA7_DST_ADDR *((vu32*)(NDMA_REGS_BASE + 0xCC)) -#define REG_NDMA7_TOTAL_CNT *((vu32*)(NDMA_REGS_BASE + 0xD0)) -#define REG_NDMA7_LOG_BLK_CNT *((vu32*)(NDMA_REGS_BASE + 0xD4)) -#define REG_NDMA7_INT_CNT *((vu32*)(NDMA_REGS_BASE + 0xD8)) -#define REG_NDMA7_FILL_DATA *((vu32*)(NDMA_REGS_BASE + 0xDC)) -#define REG_NDMA7_CNT *((vu32*)(NDMA_REGS_BASE + 0xE0)) - -#define REG_NDMA_SRC_ADDR(n) *((vu32*)(NDMA_REGS_BASE + 0x04 + (n * 28))) -#define REG_NDMA_DST_ADDR(n) *((vu32*)(NDMA_REGS_BASE + 0x08 + (n * 28))) -#define REG_NDMA_TOTAL_CNT(n) *((vu32*)(NDMA_REGS_BASE + 0x0C + (n * 28))) -#define REG_NDMA_LOG_BLK_CNT(n) *((vu32*)(NDMA_REGS_BASE + 0x10 + (n * 28))) -#define REG_NDMA_INT_CNT(n) *((vu32*)(NDMA_REGS_BASE + 0x14 + (n * 28))) -#define REG_NDMA_FILL_DATA(n) *((vu32*)(NDMA_REGS_BASE + 0x18 + (n * 28))) -#define REG_NDMA_CNT(n) *((vu32*)(NDMA_REGS_BASE + 0x1C + (n * 28))) - - -// REG_NDMA_GLOBAL_CNT -#define NDMA_ROUND_ROBIN(n) ((u32)log2(n)<<16 | 1u<<31 | 1u) // n = number of CPU cycles -#define NDMA_HIGHEST_PRIO (1u) - -// REG_NDMA_INT_CNT -#define NDMA_INT_SYS_FREQ (0u) - -// REG_NDMA_CNT -#define NDMA_DST_UPDATE_INC (0u) -#define NDMA_DST_UPDATE_DEC (1u<<10) -#define NDMA_DST_UPDATE_FIXED (2u<<10) -#define NDMA_DST_ADDR_RELOAD (1u<<12) -#define NDMA_SRC_UPDATE_INC (0u) -#define NDMA_SRC_UPDATE_DEC (1u<<13) -#define NDMA_SRC_UPDATE_FIXED (2u<<13) -#define NDMA_SRC_UPDATE_FILL (3u<<13) -#define NDMA_SRC_ADDR_RELOAD (1u<<15) -// The block length is 2^n words (Example: 2^15 = 32768 words = 0x20000 bytes) -#define NDMA_BURST_SIZE(n) ((u32)log2(n)<<16) -#define NDMA_REPEATING_MODE (1u<<29) -#define NDMA_IRQ_ENABLE (1u<<30) -#define NDMA_ENABLE (1u<<31) - - - enum - { - NDMA_STARTUP_TIMER0 = (0<<24), // Unconfirmed - NDMA_STARTUP_TIMER1 = (1<<24), // Unconfirmed - NDMA_STARTUP_TIMER2 = (2<<24), // Unconfirmed - NDMA_STARTUP_TIMER3 = (3<<24), // Unconfirmed - NDMA_STARTUP_CTRCARD0 = (4<<24), - NDMA_STARTUP_CTRCARD1 = (5<<24), - NDMA_STARTUP_UNK_6 = (6<<24), - NDMA_STARTUP_EMMC = (7<<24), - NDMA_STARTUP_AES_IN = (8<<24), // AES write fifo - NDMA_STARTUP_AES_OUT = (9<<24), // AES read fifo - NDMA_STARTUP_SHA = (10<<24), - NDMA_STARTUP_UNK_11 = (11<<24), - NDMA_STARTUP_UNK_12 = (12<<24), - NDMA_STARTUP_UNK_13 = (13<<24), - NDMA_STARTUP_UNK_14 = (14<<24), - NDMA_STARTUP_AES_SHA = (15<<24), // Unconfirmed - NDMA_STARTUP_IMMEDIATE = (16<<24) - }; - - - -/** - * @brief Initializes all NDMA channels. - */ -void NDMA_init(void); - -/** - * @brief Asynchronous copying of data using the NDMA engine. - * - * @param dest Pointer to destination memory. Must be 4 bytes aligned. - * @param source Pointer to source data. Must be 4 bytes aligned. - * @param[in] size The size of the data. Must be multiple of 4. - */ -void NDMA_copyAsync(u32 *dest, const u32 *source, u32 num); - -/** - * @brief Copies data using the NDMA engine. - * - * @param dest Pointer to destination memory. Must be 4 bytes aligned. - * @param source Pointer to source data. Must be 4 bytes aligned. - * @param[in] size The size of the data. Must be multiple of 4. - */ -void NDMA_copy(u32 *dest, const u32 *source, u32 size); - -/** - * @brief Asynchronous memory fill with the given value using the NDMA engine. - * - * @param dest Pointer to destination memory. Must be 4 bytes aligned. - * @param[in] value The value each 32-bit word will be set to. - * @param[in] size The size of the memory to fill. Must be multiple of 4. - */ -void NDMA_fillAsync(u32 *dest, u32 value, u32 size); - -/** - * @brief Fills memory with the given value using the NDMA engine. - * - * @param dest Pointer to destination memory. Must be 4 bytes aligned. - * @param[in] value The value each 32-bit word will be set to. - * @param[in] size The size of the memory to fill. Must be multiple of 4. - */ -void NDMA_fill(u32 *dest, u32 value, u32 size); diff --git a/include/arm9/sdmmc.h b/include/arm9/sdmmc.h deleted file mode 100644 index ac08efc..0000000 --- a/include/arm9/sdmmc.h +++ /dev/null @@ -1,185 +0,0 @@ -#ifndef __SDMMC_H__ -#define __SDMMC_H__ - -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright (c) 2014-2015, Normmatt - * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License Version 2, as described below: - * - * This file is free software: you may copy, redistribute and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file 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/. - */ - -#include -#include "types.h" - -#define SDMMC_BASE 0x10006000 - -#define REG_SDCMD 0x00 -#define REG_SDPORTSEL 0x02 -#define REG_SDCMDARG 0x04 -#define REG_SDCMDARG0 0x04 -#define REG_SDCMDARG1 0x06 -#define REG_SDSTOP 0x08 -#define REG_SDBLKCOUNT 0x0a - -#define REG_SDRESP0 0x0c -#define REG_SDRESP1 0x0e -#define REG_SDRESP2 0x10 -#define REG_SDRESP3 0x12 -#define REG_SDRESP4 0x14 -#define REG_SDRESP5 0x16 -#define REG_SDRESP6 0x18 -#define REG_SDRESP7 0x1a - -#define REG_SDSTATUS0 0x1c -#define REG_SDSTATUS1 0x1e - -#define REG_SDIRMASK0 0x20 -#define REG_SDIRMASK1 0x22 -#define REG_SDCLKCTL 0x24 - -#define REG_SDBLKLEN 0x26 -#define REG_SDOPT 0x28 -#define REG_SDFIFO 0x30 - -#define REG_DATACTL 0xd8 -#define REG_SDRESET 0xe0 -#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not? - -#define REG_DATACTL32 0x100 -#define REG_SDBLKLEN32 0x104 -#define REG_SDBLKCOUNT32 0x108 -#define REG_SDFIFO32 0x10C - -#define REG_CLK_AND_WAIT_CTL 0x138 -#define REG_RESET_SDIO 0x1e0 - -#define TMIO_STAT0_CMDRESPEND 0x0001 -#define TMIO_STAT0_DATAEND 0x0004 -#define TMIO_STAT0_CARD_REMOVE 0x0008 -#define TMIO_STAT0_CARD_INSERT 0x0010 -#define TMIO_STAT0_SIGSTATE 0x0020 -#define TMIO_STAT0_WRPROTECT 0x0080 -#define TMIO_STAT0_CARD_REMOVE_A 0x0100 -#define TMIO_STAT0_CARD_INSERT_A 0x0200 -#define TMIO_STAT0_SIGSTATE_A 0x0400 -#define TMIO_STAT1_CMD_IDX_ERR 0x0001 -#define TMIO_STAT1_CRCFAIL 0x0002 -#define TMIO_STAT1_STOPBIT_ERR 0x0004 -#define TMIO_STAT1_DATATIMEOUT 0x0008 -#define TMIO_STAT1_RXOVERFLOW 0x0010 -#define TMIO_STAT1_TXUNDERRUN 0x0020 -#define TMIO_STAT1_CMDTIMEOUT 0x0040 -#define TMIO_STAT1_RXRDY 0x0100 -#define TMIO_STAT1_TXRQ 0x0200 -#define TMIO_STAT1_ILL_FUNC 0x2000 -#define TMIO_STAT1_CMD_BUSY 0x4000 -#define TMIO_STAT1_ILL_ACCESS 0x8000 - -#define TMIO_MASK_ALL 0x837f031d - -#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \ - TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR) - -#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND) -#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND) - -#ifdef __cplusplus -extern "C" { -#endif - - typedef struct mmcdevice { - uint8_t* rData; - const uint8_t* tData; - uint32_t size; - uint32_t error; - uint16_t stat0; - uint16_t stat1; - uint32_t ret[4]; - uint32_t initarg; - uint32_t isSDHC; - uint32_t clk; - uint32_t SDOPT; - uint32_t devicenumber; - uint32_t total_size; //size in sectors of the device - uint32_t res; - } mmcdevice; - - void sdmmc_init(); - int sdmmc_sdcard_readsector(uint32_t sector_no, uint8_t *out); - int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out); - int sdmmc_sdcard_writesector(uint32_t sector_no, const uint8_t *in); - int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, const uint8_t *in); - - int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out); - int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, const uint8_t *in); - - int sdmmc_get_cid(bool isNand, uint32_t *info); - - mmcdevice *getMMCDevice(int drive); - - void InitSD(); - int Nand_Init(); - int SD_Init(); - -#ifdef __cplusplus -}; -#endif - -//--------------------------------------------------------------------------------- -static inline uint16_t sdmmc_read16(uint16_t reg) { -//--------------------------------------------------------------------------------- - return *(volatile uint16_t*)(SDMMC_BASE + reg); -} - -//--------------------------------------------------------------------------------- -static inline void sdmmc_write16(uint16_t reg, uint16_t val) { -//--------------------------------------------------------------------------------- - *(volatile uint16_t*)(SDMMC_BASE + reg) = val; -} - -//--------------------------------------------------------------------------------- -static inline uint32_t sdmmc_read32(uint16_t reg) { -//--------------------------------------------------------------------------------- - return *(volatile uint32_t*)(SDMMC_BASE + reg); -} - -//--------------------------------------------------------------------------------- -static inline void sdmmc_write32(uint16_t reg, uint32_t val) { -//--------------------------------------------------------------------------------- - *(volatile uint32_t*)(SDMMC_BASE + reg) = val; -} - -//--------------------------------------------------------------------------------- -static inline void sdmmc_mask16(uint16_t reg, const uint16_t clear, const uint16_t set) { -//--------------------------------------------------------------------------------- - uint16_t val = sdmmc_read16(reg); - val &= ~clear; - val |= set; - sdmmc_write16(reg, val); -} - -static inline void setckl(uint32_t data) -{ - sdmmc_mask16(REG_SDCLKCTL,0x100,0); - sdmmc_mask16(REG_SDCLKCTL,0x2FF,data&0x2FF); - sdmmc_mask16(REG_SDCLKCTL,0x0,0x100); -} - -#endif diff --git a/include/arm9/spiflash.h b/include/arm9/spiflash.h deleted file mode 100644 index d935be1..0000000 --- a/include/arm9/spiflash.h +++ /dev/null @@ -1,31 +0,0 @@ -#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 . - */ - -#include "types.h" - - -#define SPIFLASH_CMD_RDSR (0x05) -#define SPIFLASH_CMD_READ (0x03) - - - -// true if spiflash is installed, false otherwise -bool spiflash_get_status(); -void spiflash_read(u32 offset, u32 size, u8 *buf); diff --git a/include/arm9/splash.h b/include/arm9/splash.h deleted file mode 100644 index 339d385..0000000 --- a/include/arm9/splash.h +++ /dev/null @@ -1,48 +0,0 @@ -#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 . - */ - -#include "types.h" - - -#define FLAG_ROTATED (1u<<3) -#define FLAG_COMPRESSED (1u<<4) -#define FLAG_SWAPPED (1u<<5) - - -enum -{ - FORMAT_RGB565 = 0, - FORMAT_RGB8 = 1, - FORMAT_RGBA8 = 2, - FORMAT_INVALID = 7 -}; - -typedef struct -{ - u32 magic; - u16 width; - u16 height; - u32 flags; -} SplashHeader; - - - -void getSplashDimensions(const void *const data, u32 *const width, u32 *const height); -bool drawSplashscreen(const void *const data, s32 startX, s32 startY); diff --git a/include/arm9/timer.h b/include/arm9/timer.h deleted file mode 100644 index cd62d93..0000000 --- a/include/arm9/timer.h +++ /dev/null @@ -1,83 +0,0 @@ -#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 . - */ - -#include "types.h" - - -#define TIMER_BASE_FREQ (67027963.95) - -#define TIMER_COUNT_UP (1u<<2) // For cascading at least 2 timers -#define TIMER_IRQ_ENABLE (1u<<6) -#define TIMER_ENABLE (1u<<7) - -// Convenience macros for calculating the ticks. Based on libnds -#define TIMER_FREQ(n) (0x10000u - (u16)(TIMER_BASE_FREQ / n)) -#define TIMER_FREQ_64(n) (0x10000u - (u16)(TIMER_BASE_FREQ / 64.0 / n)) -#define TIMER_FREQ_256(n) (0x10000u - (u16)(TIMER_BASE_FREQ / 256.0 / n)) -#define TIMER_FREQ_1024(n) (0x10000u - (u16)(TIMER_BASE_FREQ / 1024.0 / n)) - - -typedef enum -{ - TIMER_0 = 0, - TIMER_1 = 1, - TIMER_2 = 2, - TIMER_3 = 3 -} Timer; - -typedef enum -{ - TIMER_PRESCALER_1 = 0, - TIMER_PRESCALER_64 = 1, - TIMER_PRESCALER_256 = 2, - TIMER_PRESCALER_1024 = 3 -} TimerPrescaler; - - - -/** - * @brief Resets/initializes the timer hardware. Should not be called manually. - */ -void TIMER_init(void); - -/** - * @brief Starts a timer. - * - * @param[in] timer The timer to start. - * @param[in] prescaler The prescaler to use. - * @param[in] ticks The initial number of ticks. This is also the reload - * value on overflow. - * @param[in] enableIrq Timer fires IRQs if true. - */ -void TIMER_start(Timer timer, TimerPrescaler prescaler, u16 ticks, bool enableIrq); - -/** - * @brief Stops a timer. - * - * @param[in] timer The timer to stop. - */ -void TIMER_stop(Timer timer); - -/** - * @brief Halts the CPU for the specified number of milliseconds. - * - * @param[in] ms The number of milliseconds to sleep. - */ -void TIMER_sleep(u32 ms); diff --git a/include/cache.h b/include/cache.h deleted file mode 100644 index a2f511b..0000000 --- a/include/cache.h +++ /dev/null @@ -1,32 +0,0 @@ -#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 . - */ - -#include "types.h" - - - -void invalidateICache(void); -void invalidateICacheRange(const void *const base, u32 size); -void flushDCache(void); -void flushInvalidateDCache(void); -void flushDCacheRange(const void *const base, u32 size); -void flushInvalidateDCacheRange(const void *const base, u32 size); -void invalidateDCache(void); -void invalidateDCacheRange(const void *const base, u32 size); diff --git a/include/gfx.h b/include/gfx.h deleted file mode 100644 index 85e8b29..0000000 --- a/include/gfx.h +++ /dev/null @@ -1,49 +0,0 @@ -#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 . - */ - -#include "mem_map.h" -#include "types.h" - - -#define SCREEN_HEIGHT_TOP (240) -#define SCREEN_WIDTH_TOP (400) -#define SCREEN_SIZE_TOP (SCREEN_HEIGHT_TOP * SCREEN_WIDTH_TOP * 2) -#define SCREEN_HEIGHT_SUB (240) -#define SCREEN_WIDTH_SUB (320) -#define SCREEN_SIZE_SUB (SCREEN_HEIGHT_SUB * SCREEN_WIDTH_SUB * 2) - -#define FRAMEBUF_TOP_A_1 (VRAM_BASE) -#define FRAMEBUF_SUB_A_1 (FRAMEBUF_TOP_A_1 + (SCREEN_WIDTH_TOP * SCREEN_HEIGHT_TOP * 2)) -#define FRAMEBUF_TOP_A_2 (VRAM_BASE + 0x100000) -#define FRAMEBUF_SUB_A_2 (FRAMEBUF_TOP_A_2 + (SCREEN_WIDTH_TOP * SCREEN_HEIGHT_TOP * 2)) - -/// Converts packed RGB8 to packed RGB565. -#define RGB8_to_565(r,g,b) (((b)>>3)&0x1f)|((((g)>>2)&0x3f)<<5)|((((r)>>3)&0x1f)<<11) - - -#ifdef ARM11 -void GX_memoryFill(u64 *buf0a, u32 buf0v, u32 buf0Sz, u32 val0, u64 *buf1a, u32 buf1v, u32 buf1Sz, u32 val1); -void GX_displayTransfer(u64 *in, u32 indim, u64 *out, u32 outdim, u32 flags); -void GX_textureCopy(u64 *in, u32 indim, u64 *out, u32 outdim, u32 size); -void GFX_setBrightness(u32 brightness); -void GFX_swapFramebufs(void); -void GFX_init(void); -void GFX_deinit(void); -#endif diff --git a/include/hardware/cache.h b/include/hardware/cache.h new file mode 100644 index 0000000..a2f511b --- /dev/null +++ b/include/hardware/cache.h @@ -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 . + */ + +#include "types.h" + + + +void invalidateICache(void); +void invalidateICacheRange(const void *const base, u32 size); +void flushDCache(void); +void flushInvalidateDCache(void); +void flushDCacheRange(const void *const base, u32 size); +void flushInvalidateDCacheRange(const void *const base, u32 size); +void invalidateDCache(void); +void invalidateDCacheRange(const void *const base, u32 size); diff --git a/include/hardware/gfx.h b/include/hardware/gfx.h new file mode 100644 index 0000000..85e8b29 --- /dev/null +++ b/include/hardware/gfx.h @@ -0,0 +1,49 @@ +#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 . + */ + +#include "mem_map.h" +#include "types.h" + + +#define SCREEN_HEIGHT_TOP (240) +#define SCREEN_WIDTH_TOP (400) +#define SCREEN_SIZE_TOP (SCREEN_HEIGHT_TOP * SCREEN_WIDTH_TOP * 2) +#define SCREEN_HEIGHT_SUB (240) +#define SCREEN_WIDTH_SUB (320) +#define SCREEN_SIZE_SUB (SCREEN_HEIGHT_SUB * SCREEN_WIDTH_SUB * 2) + +#define FRAMEBUF_TOP_A_1 (VRAM_BASE) +#define FRAMEBUF_SUB_A_1 (FRAMEBUF_TOP_A_1 + (SCREEN_WIDTH_TOP * SCREEN_HEIGHT_TOP * 2)) +#define FRAMEBUF_TOP_A_2 (VRAM_BASE + 0x100000) +#define FRAMEBUF_SUB_A_2 (FRAMEBUF_TOP_A_2 + (SCREEN_WIDTH_TOP * SCREEN_HEIGHT_TOP * 2)) + +/// Converts packed RGB8 to packed RGB565. +#define RGB8_to_565(r,g,b) (((b)>>3)&0x1f)|((((g)>>2)&0x3f)<<5)|((((r)>>3)&0x1f)<<11) + + +#ifdef ARM11 +void GX_memoryFill(u64 *buf0a, u32 buf0v, u32 buf0Sz, u32 val0, u64 *buf1a, u32 buf1v, u32 buf1Sz, u32 val1); +void GX_displayTransfer(u64 *in, u32 indim, u64 *out, u32 outdim, u32 flags); +void GX_textureCopy(u64 *in, u32 indim, u64 *out, u32 outdim, u32 size); +void GFX_setBrightness(u32 brightness); +void GFX_swapFramebufs(void); +void GFX_init(void); +void GFX_deinit(void); +#endif diff --git a/include/hardware/pxi.h b/include/hardware/pxi.h new file mode 100644 index 0000000..08c48bb --- /dev/null +++ b/include/hardware/pxi.h @@ -0,0 +1,80 @@ +#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 . + */ + +#include "mem_map.h" +#include "types.h" + + +#ifdef ARM9 +#define PXI9_REGS_BASE (IO_MEM_ARM9_ONLY + 0x8000) +#define REG_PXI_SYNC9 *((vu32*)(PXI9_REGS_BASE + 0x00)) +#define REG_PXI_CNT9 *((vu32*)(PXI9_REGS_BASE + 0x04)) +#define REG_PXI_SEND9 *((vu32*)(PXI9_REGS_BASE + 0x08)) +#define REG_PXI_RECV9 *((vu32*)(PXI9_REGS_BASE + 0x0C)) +#endif + +#ifdef ARM11 +#define PXI11_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x63000) +#define REG_PXI_SYNC11 *((vu32*)(PXI11_REGS_BASE + 0x00)) +#define REG_PXI_CNT11 *((vu32*)(PXI11_REGS_BASE + 0x04)) +#define REG_PXI_SEND11 *((vu32*)(PXI11_REGS_BASE + 0x08)) +#define REG_PXI_RECV11 *((vu32*)(PXI11_REGS_BASE + 0x0C)) +#endif + + +// Defines for PX_SYNC regs +#define PXI_DATA_RECEIVED(reg) (reg & 0xFF) +#define PXI_DATA_SENT(reg) (reg>>8 & 0xFF) +#define PXI_NOTIFY_11 (1u<<29) +#define PXI_NOTIFY_9 (1u<<30) +#define PXI_IRQ_ENABLE (1u<<31) + +// Defines for PX_CNT regs +#define PXI_SEND_FIFO_EMPTY (1u<<0) +#define PXI_SEND_FIFO_FULL (1u<<1) +#define PXI_SEND_FIFO_EMPTY_IRQ (1u<<2) +#define PXI_FLUSH_SEND_FIFO (1u<<3) +#define PXI_RECV_FIFO_EMPTY (1u<<8) +#define PXI_RECV_FIFO_FULL (1u<<9) +#define PXI_RECV_FIFO_NOT_EMPTY_IRQ (1u<<10) +#define PXI_EMPTY_FULL_ERROR (1u<<14) +#define PXI_ENABLE_SEND_RECV_FIFO (1u<<15) + +// Custom PXI Command/Reply Definitions +#define PXI_CMD_ENABLE_LCDS (0x4C434453) +#define PXI_CMD_SET_BRIGHTNESS (0x78D28107) +#define PXI_CMD_POWER_OFF (0x504F4646) +#define PXI_CMD_REBOOT (0x48326482) +#define PXI_CMD_ALLOW_POWER_OFF (0x504F4F4B) +#define PXI_CMD_FORBID_POWER_OFF (0x504F4E4F) +#define PXI_CMD_FIRM_LAUNCH (0x544F4F42) +#define PXI_RPL_FIRM_LAUNCH_READY (0x4F4B6666) +#define PXI_RPL_OK (0x4F4B4F4B) +#define PXI_RPL_HOME_PRESSED (0x484F4D45) +#define PXI_RPL_HOME_HELD (0x484F4D22) +#define PXI_RPL_POWER_PRESSED (0x504F5752) + + +void PXI_init(void); +void PXI_sendWord(u32 val); +bool PXI_trySendWord(u32 val); +u32 PXI_recvWord(void); +u32 PXI_tryRecvWord(bool *success); +void PXI_sendBuf(const u32 *const buf, u32 size); diff --git a/include/pxi.h b/include/pxi.h deleted file mode 100644 index 08c48bb..0000000 --- a/include/pxi.h +++ /dev/null @@ -1,80 +0,0 @@ -#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 . - */ - -#include "mem_map.h" -#include "types.h" - - -#ifdef ARM9 -#define PXI9_REGS_BASE (IO_MEM_ARM9_ONLY + 0x8000) -#define REG_PXI_SYNC9 *((vu32*)(PXI9_REGS_BASE + 0x00)) -#define REG_PXI_CNT9 *((vu32*)(PXI9_REGS_BASE + 0x04)) -#define REG_PXI_SEND9 *((vu32*)(PXI9_REGS_BASE + 0x08)) -#define REG_PXI_RECV9 *((vu32*)(PXI9_REGS_BASE + 0x0C)) -#endif - -#ifdef ARM11 -#define PXI11_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x63000) -#define REG_PXI_SYNC11 *((vu32*)(PXI11_REGS_BASE + 0x00)) -#define REG_PXI_CNT11 *((vu32*)(PXI11_REGS_BASE + 0x04)) -#define REG_PXI_SEND11 *((vu32*)(PXI11_REGS_BASE + 0x08)) -#define REG_PXI_RECV11 *((vu32*)(PXI11_REGS_BASE + 0x0C)) -#endif - - -// Defines for PX_SYNC regs -#define PXI_DATA_RECEIVED(reg) (reg & 0xFF) -#define PXI_DATA_SENT(reg) (reg>>8 & 0xFF) -#define PXI_NOTIFY_11 (1u<<29) -#define PXI_NOTIFY_9 (1u<<30) -#define PXI_IRQ_ENABLE (1u<<31) - -// Defines for PX_CNT regs -#define PXI_SEND_FIFO_EMPTY (1u<<0) -#define PXI_SEND_FIFO_FULL (1u<<1) -#define PXI_SEND_FIFO_EMPTY_IRQ (1u<<2) -#define PXI_FLUSH_SEND_FIFO (1u<<3) -#define PXI_RECV_FIFO_EMPTY (1u<<8) -#define PXI_RECV_FIFO_FULL (1u<<9) -#define PXI_RECV_FIFO_NOT_EMPTY_IRQ (1u<<10) -#define PXI_EMPTY_FULL_ERROR (1u<<14) -#define PXI_ENABLE_SEND_RECV_FIFO (1u<<15) - -// Custom PXI Command/Reply Definitions -#define PXI_CMD_ENABLE_LCDS (0x4C434453) -#define PXI_CMD_SET_BRIGHTNESS (0x78D28107) -#define PXI_CMD_POWER_OFF (0x504F4646) -#define PXI_CMD_REBOOT (0x48326482) -#define PXI_CMD_ALLOW_POWER_OFF (0x504F4F4B) -#define PXI_CMD_FORBID_POWER_OFF (0x504F4E4F) -#define PXI_CMD_FIRM_LAUNCH (0x544F4F42) -#define PXI_RPL_FIRM_LAUNCH_READY (0x4F4B6666) -#define PXI_RPL_OK (0x4F4B4F4B) -#define PXI_RPL_HOME_PRESSED (0x484F4D45) -#define PXI_RPL_HOME_HELD (0x484F4D22) -#define PXI_RPL_POWER_PRESSED (0x504F5752) - - -void PXI_init(void); -void PXI_sendWord(u32 val); -bool PXI_trySendWord(u32 val); -u32 PXI_recvWord(void); -u32 PXI_tryRecvWord(bool *success); -void PXI_sendBuf(const u32 *const buf, u32 size); diff --git a/source/arm11/cache.s b/source/arm11/cache.s deleted file mode 100644 index 82dadf4..0000000 --- a/source/arm11/cache.s +++ /dev/null @@ -1,115 +0,0 @@ -/* - * 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 . - */ - -#include "asmfunc.h" - -.arm -.cpu mpcore -.fpu vfpv2 - - -#define CACHE_LINE_SIZE (32) - - - -ASM_FUNC invalidateICache - mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 @ Invalidate Entire Instruction Cache, also flushes the branch target cache - @mcr p15, 0, r0, c7, c5, 6 @ Flush Entire Branch Target Cache - mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier - mcr p15, 0, r0, c7, c5, 4 @ Flush Prefetch Buffer - bx lr - - -ASM_FUNC invalidateICacheRange - add r1, r1, r0 - bic r0, r0, #(CACHE_LINE_SIZE - 1) - mov r2, #0 - invalidateICacheRange_lp: - mcr p15, 0, r0, c7, c5, 1 @ Invalidate Instruction Cache Line (using MVA) - add r0, r0, #CACHE_LINE_SIZE - cmp r0, r1 - blt invalidateICacheRange_lp - mcr p15, 0, r2, c7, c5, 6 @ Flush Entire Branch Target Cache - mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier - mcr p15, 0, r2, c7, c5, 4 @ Flush Prefetch Buffer - bx lr - - -ASM_FUNC flushDCache - mov r0, #0 - mcr p15, 0, r0, c7, c10, 0 @ "Clean Entire Data Cache" - mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier - bx lr - - -ASM_FUNC flushInvalidateDCache - mov r0, #0 - mcr p15, 0, r0, c7, c14, 0 @ "Clean and Invalidate Entire Data Cache" - mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier - bx lr - - -ASM_FUNC flushDCacheRange - add r1, r1, r0 - bic r0, r0, #(CACHE_LINE_SIZE - 1) - mov r2, #0 - flushDCacheRange_lp: - mcr p15, 0, r0, c7, c10, 1 @ "Clean Data Cache Line (using MVA)" - add r0, r0, #CACHE_LINE_SIZE - cmp r0, r1 - blt flushDCacheRange_lp - mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier - bx lr - - -ASM_FUNC flushInvalidateDCacheRange - add r1, r1, r0 - bic r0, r0, #(CACHE_LINE_SIZE - 1) - mov r2, #0 - flushInvalidateDCacheRange_lp: - mcr p15, 0, r0, c7, c14, 1 @ "Clean and Invalidate Data Cache Line (using MVA)" - add r0, r0, #CACHE_LINE_SIZE - cmp r0, r1 - blt flushInvalidateDCacheRange_lp - mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier - bx lr - - -ASM_FUNC invalidateDCache - mov r0, #0 - mcr p15, 0, r0, c7, c6, 0 @ Invalidate Entire Data Cache - mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier - bx lr - - -ASM_FUNC invalidateDCacheRange - add r1, r1, r0 - tst r0, #(CACHE_LINE_SIZE - 1) - mcrne p15, 0, r0, c7, c10, 1 @ "Clean Data Cache Line (using MVA)" - tst r1, #(CACHE_LINE_SIZE - 1) - mcrne p15, 0, r1, c7, c10, 1 @ "Clean Data Cache Line (using MVA)" - bic r0, r0, #(CACHE_LINE_SIZE - 1) - mov r2, #0 - invalidateDCacheRange_lp: - mcr p15, 0, r0, c7, c6, 1 @ Invalidate Data Cache Line (using MVA) - add r0, r0, #CACHE_LINE_SIZE - cmp r0, r1 - blt invalidateDCacheRange_lp - mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier - bx lr diff --git a/source/arm11/exception.s b/source/arm11/exception.s deleted file mode 100644 index 730b3db..0000000 --- a/source/arm11/exception.s +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 . - */ - -#include "asmfunc.h" - -.arm -.cpu mpcore -.fpu vfpv2 - -.extern deinitCpu -.extern privIrqHandlerTable -.extern irqHandlerTable - - - -ASM_FUNC tmpExceptionHandler - bl deinitCpu - ldr r0, =0x10202A04 - mov r1, #0xFF - orr r1, #0x1000000 - str r1, [r0] -tmpExceptionHandler_lp: - wfi - b tmpExceptionHandler_lp -.pool - - -ASM_FUNC irqHandler - sub lr, lr, #4 - srsfd sp!, #31 @ Store lr and spsr on system mode stack - cps #31 @ Switch to system mode - stmfd sp!, {r0-r3, r12, lr} - mov r12, #0x17000000 - orr r12, r12, #0xE00000 - ldr r0, [r12, #0x10C] @ REG_CPU_II_AKN - and r1, r0, #0x7F - cmp r1, #32 - ldrlo r2, =privIrqHandlerTable - mrclo p15, 0, r3, c0, c0, 5 @ Get CPU ID - andlo r3, r3, #3 - addlo r2, r2, r3, lsl #7 - ldrhs r2, =irqHandlerTable - subhs r1, r1, #32 - ldr r3, [r2, r1, lsl #2] - cmp r3, #0 - beq irqHandler_skip_processing - stmfd sp!, {r0, r12} - cpsie i - blx r3 - cpsid i - ldmfd sp!, {r0, r12} -irqHandler_skip_processing: - str r0, [r12, #0x110] @ REG_CPU_II_EOI - ldmfd sp!, {r0-r3, r12, lr} - rfefd sp! @ Restore lr (pc) and spsr (cpsr) diff --git a/source/arm11/firm.c b/source/arm11/firm.c index 9bfb5e6..73f8d2f 100644 --- a/source/arm11/firm.c +++ b/source/arm11/firm.c @@ -20,7 +20,7 @@ #include "types.h" #include "mem_map.h" #include "arm11/start.h" -#include "pxi.h" +#include "hardware/pxi.h" diff --git a/source/arm11/gfx.c b/source/arm11/gfx.c deleted file mode 100644 index bb7687c..0000000 --- a/source/arm11/gfx.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * 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 . - */ - -/* - * Based on code from https://github.com/AuroraWright/Luma3DS - * for compatibility. - * - * Credits go to the Luma3DS devs and derrek for reverse engineering boot11. -*/ - -#include "types.h" -#include "mem_map.h" -#include "gfx.h" -#include "arm11/i2c.h" -#include "arm11/timer.h" -#include "arm11/interrupt.h" - - -#define PDN_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x40000) -#define REG_PDN_GPU_CNT *((vu32*)(PDN_REGS_BASE + 0x1200)) -#define REG_PDN_GPU_CNT2 *((vu32*)(PDN_REGS_BASE + 0x1204)) -#define REG_PDN_GPU_CNT2_8BIT *((vu8* )(PDN_REGS_BASE + 0x1204)) -#define REG_PDN_GPU_CNT4 *((vu8* )(PDN_REGS_BASE + 0x1208)) -#define REG_PDN_GPU_CNT3 *((vu16*)(PDN_REGS_BASE + 0x1210)) - -#define LCD_REGS_BASE (IO_MEM_ARM11_ONLY + 0x2000) -#define REG_LCD_COLORFILL_MAIN *((vu32*)(LCD_REGS_BASE + 0x204)) -#define REG_LCD_COLORFILL_SUB *((vu32*)(LCD_REGS_BASE + 0xA04)) -#define REG_LCD_BACKLIGHT_MAIN *((vu32*)(LCD_REGS_BASE + 0x240)) -#define REG_LCD_BACKLIGHT_SUB *((vu32*)(LCD_REGS_BASE + 0xA40)) - -#define GPU_EXT_REGS_BASE (IO_MEM_ARM11_ONLY + 0x200000) -#define REG_GPU_EXT_CNT *((vu32*)(GPU_EXT_REGS_BASE + 0x04)) - - - -static void gfxSetupLcdTop(void) -{ - *((vu32*)(0x10400400+0x00)) = 0x000001C2; - *((vu32*)(0x10400400+0x04)) = 0x000000D1; - *((vu32*)(0x10400400+0x08)) = 0x000001C1; - *((vu32*)(0x10400400+0x0C)) = 0x000001C1; - *((vu32*)(0x10400400+0x10)) = 0x00000000; - *((vu32*)(0x10400400+0x14)) = 0x000000CF; - *((vu32*)(0x10400400+0x18)) = 0x000000d1; - *((vu32*)(0x10400400+0x1C)) = 0x01C501C1; - *((vu32*)(0x10400400+0x20)) = 0x00010000; - *((vu32*)(0x10400400+0x24)) = 0x0000019D; - *((vu32*)(0x10400400+0x28)) = 0x00000002; - *((vu32*)(0x10400400+0x2C)) = 0x00000192; - *((vu32*)(0x10400400+0x30)) = 0x00000192; - *((vu32*)(0x10400400+0x34)) = 0x00000192; - *((vu32*)(0x10400400+0x38)) = 0x00000001; - *((vu32*)(0x10400400+0x3C)) = 0x00000002; - *((vu32*)(0x10400400+0x40)) = 0x01960192; - *((vu32*)(0x10400400+0x44)) = 0x00000000; - *((vu32*)(0x10400400+0x48)) = 0x00000000; - *((vu32*)(0x10400400+0x5C)) = (SCREEN_WIDTH_TOP << 16) | SCREEN_HEIGHT_TOP; // Width and height - *((vu32*)(0x10400400+0x60)) = 0x01C100D1; - *((vu32*)(0x10400400+0x64)) = 0x01920002; - *((vu32*)(0x10400400+0x68)) = FRAMEBUF_TOP_A_1; // Framebuffer A first address - *((vu32*)(0x10400400+0x6C)) = FRAMEBUF_TOP_A_2; // Framebuffer A second address - *((vu32*)(0x10400400+0x70)) = 0x00080042; // Format GL_RGB565_OES - *((vu32*)(0x10400400+0x74)) = 0x00010501; - *((vu32*)(0x10400400+0x78)) = 0x00000000; // Framebuffer select 0 - *((vu32*)(0x10400400+0x90)) = SCREEN_HEIGHT_TOP * 2; // Stride 0 - *((vu32*)(0x10400400+0x94)) = FRAMEBUF_TOP_A_1; // Framebuffer B first address - *((vu32*)(0x10400400+0x98)) = FRAMEBUF_TOP_A_2; // Framebuffer B second address - *((vu32*)(0x10400400+0x9C)) = 0x00000000; - - for(u32 i = 0; i < 0x100; i++) - { - u32 val = 0x10101; - val *= i; - *((vu32*)(0x10400400+0x84)) = val; - } -} - -static void gfxSetupLcdLow(void) -{ - *((vu32*)(0x10400500+0x00)) = 0x000001C2; - *((vu32*)(0x10400500+0x04)) = 0x000000D1; - *((vu32*)(0x10400500+0x08)) = 0x000001C1; - *((vu32*)(0x10400500+0x0C)) = 0x000001C1; - *((vu32*)(0x10400500+0x10)) = 0x000000CD; - *((vu32*)(0x10400500+0x14)) = 0x000000CF; - *((vu32*)(0x10400500+0x18)) = 0x000000D1; - *((vu32*)(0x10400500+0x1C)) = 0x01C501C1; - *((vu32*)(0x10400500+0x20)) = 0x00010000; - *((vu32*)(0x10400500+0x24)) = 0x0000019D; - *((vu32*)(0x10400500+0x28)) = 0x00000052; - *((vu32*)(0x10400500+0x2C)) = 0x00000192; - *((vu32*)(0x10400500+0x30)) = 0x00000192; - *((vu32*)(0x10400500+0x34)) = 0x0000004F; - *((vu32*)(0x10400500+0x38)) = 0x00000050; - *((vu32*)(0x10400500+0x3C)) = 0x00000052; - *((vu32*)(0x10400500+0x40)) = 0x01980194; - *((vu32*)(0x10400500+0x44)) = 0x00000000; - *((vu32*)(0x10400500+0x48)) = 0x00000011; - *((vu32*)(0x10400500+0x5C)) = (SCREEN_WIDTH_SUB << 16) | SCREEN_HEIGHT_SUB; // Width and height - *((vu32*)(0x10400500+0x60)) = 0x01C100D1; - *((vu32*)(0x10400500+0x64)) = 0x01920052; - *((vu32*)(0x10400500+0x68)) = FRAMEBUF_SUB_A_1; // Framebuffer first address - *((vu32*)(0x10400500+0x6C)) = FRAMEBUF_SUB_A_2; // Framebuffer second address - *((vu32*)(0x10400500+0x70)) = 0x00080002; // Format GL_RGB565_OES - *((vu32*)(0x10400500+0x74)) = 0x00010501; - *((vu32*)(0x10400500+0x78)) = 0x00000000; // Framebuffer select 0 - *((vu32*)(0x10400500+0x90)) = SCREEN_HEIGHT_SUB * 2; // Stride 0 - *((vu32*)(0x10400500+0x9C)) = 0x00000000; - - for(u32 i = 0; i < 0x100; i++) - { - u32 val = 0x10101; - val *= i; - *((vu32*)(0x10400500+0x84)) = val; - } -} - -static void gfxSetupFramebuffers(void) -{ - // Top screen - *((vu32*)(0x10400400+0x5C)) = (SCREEN_WIDTH_TOP << 16) | SCREEN_HEIGHT_TOP; // Width and height - *((vu32*)(0x10400400+0x68)) = FRAMEBUF_TOP_A_1; // Framebuffer A first address - *((vu32*)(0x10400400+0x6C)) = FRAMEBUF_TOP_A_2; // Framebuffer A second address - *((vu32*)(0x10400400+0x70)) = 0x00080042; // Format GL_RGB565_OES - *((vu32*)(0x10400400+0x78)) = 0x00000000; // Framebuffer select 0 - *((vu32*)(0x10400400+0x90)) = SCREEN_HEIGHT_TOP * 2; // Stride 0 - *((vu32*)(0x10400400+0x94)) = FRAMEBUF_TOP_A_1; // Framebuffer B first address - *((vu32*)(0x10400400+0x98)) = FRAMEBUF_TOP_A_2; // Framebuffer B second address - - // Bottom screen - *((vu32*)(0x10400500+0x5C)) = (SCREEN_WIDTH_SUB << 16) | SCREEN_HEIGHT_SUB; // Width and height - *((vu32*)(0x10400500+0x68)) = FRAMEBUF_SUB_A_1; // Framebuffer first address - *((vu32*)(0x10400500+0x6C)) = FRAMEBUF_SUB_A_2; // Framebuffer second address - *((vu32*)(0x10400500+0x70)) = 0x00080002; // Format GL_RGB565_OES - *((vu32*)(0x10400500+0x78)) = 0x00000000; // Framebuffer select 0 - *((vu32*)(0x10400500+0x90)) = SCREEN_HEIGHT_SUB * 2; // Stride 0 -} - -void GX_memoryFill(u64 *buf0a, u32 buf0v, u32 buf0Sz, u32 val0, u64 *buf1a, u32 buf1v, u32 buf1Sz, u32 val1) -{ - vu32 *REGs_PSC0 = (vu32*)0x10400010; - vu32 *REGs_PSC1 = (vu32*)0x10400020; - - REGs_PSC0[0] = (u32)buf0a>>3; // Start address - REGs_PSC0[1] = ((u32)buf0a + buf0Sz)>>3; // End address - REGs_PSC0[2] = val0; // Fill value - REGs_PSC0[3] = buf0v | 1u; // Pattern + start - - REGs_PSC1[0] = (u32)buf1a>>3; // Start address - REGs_PSC1[1] = ((u32)buf1a + buf1Sz)>>3; // End address - REGs_PSC1[2] = val1; // Fill value - REGs_PSC1[3] = buf1v | 1u; // Pattern + start -} - -void GX_displayTransfer(u64 *in, u32 indim, u64 *out, u32 outdim, u32 flags) -{ - vu32 *REGs_TE = (vu32*)0x10400C00; - - REGs_TE[0] = (u32)in>>3; - REGs_TE[1] = (u32)out>>3; - REGs_TE[2] = indim; - REGs_TE[3] = outdim; - REGs_TE[4] = flags; - REGs_TE[5] = 0; - REGs_TE[6] = 1; -} - -void GX_textureCopy(u64 *in, u32 indim, u64 *out, u32 outdim, u32 size) -{ - vu32 *REGs_TE = (vu32*)0x10400C00; - - REGs_TE[0] = (u32)in>>3; - REGs_TE[1] = (u32)out>>3; - REGs_TE[4] = 1u<<3; - REGs_TE[5] = 0; - REGs_TE[8] = size; - REGs_TE[9] = indim; - REGs_TE[10] = outdim; - REGs_TE[6] = 1; -} - -void GFX_setBrightness(u32 brightness) -{ - REG_LCD_BACKLIGHT_MAIN = brightness; - REG_LCD_BACKLIGHT_SUB = brightness; -} - -void GFX_swapFramebufs(void) -{ - static u32 activeFb = 0; - activeFb ^= 1; - - *((vu32*)(0x10400400+0x78)) = activeFb; - *((vu32*)(0x10400500+0x78)) = activeFb; -} - -static void vblankIrqHandler(UNUSED u32 intSource) -{ - GX_textureCopy((u64*)FRAMEBUF_TOP_A_1, 0, (u64*)FRAMEBUF_TOP_A_2, 0, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB); -} - -void GFX_init(void) -{ - if(REG_PDN_GPU_CNT != 0x1007F) // Check if screens are already initialized - { - REG_PDN_GPU_CNT = 0x1007F; - *((vu32*)0x10202014) = 0x00000001; - *((vu32*)0x1020200C) &= 0xFFFEFFFE; - REG_LCD_COLORFILL_MAIN = 1u<<24; - REG_LCD_COLORFILL_SUB = 1u<<24; - REG_LCD_BACKLIGHT_MAIN = 0x30; - REG_LCD_BACKLIGHT_SUB = 0x30; - *((vu32*)0x10202244) = 0x1023E; - *((vu32*)0x10202A44) = 0x1023E; - - gfxSetupLcdTop(); - gfxSetupLcdLow(); - - // The GPU mem fill races against the console. - //GX_memoryFill((u64*)FRAMEBUF_TOP_A_1, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB, 0, - // (u64*)FRAMEBUF_TOP_A_2, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB, 0); - I2C_writeReg(I2C_DEV_MCU, 0x22, 0x2A); - - // We must make sure the I2C bus is not used until this finishes - // otherwise the screens may not turn on on New 3DS. - TIMER_sleepMs(3); - } - else - { - REG_LCD_COLORFILL_MAIN = 1u<<24; - REG_LCD_COLORFILL_SUB = 1u<<24; - REG_LCD_BACKLIGHT_MAIN = 0x30; - REG_LCD_BACKLIGHT_SUB = 0x30; - gfxSetupFramebuffers(); - } - - IRQ_registerHandler(IRQ_PDC0, 14, 0, true, vblankIrqHandler); - GFX_swapFramebufs(); - - REG_LCD_COLORFILL_MAIN = 0; - REG_LCD_COLORFILL_SUB = 0; -} - -void GFX_deinit(void) -{ - IRQ_unregisterHandler(IRQ_PDC0); - - // Temporary Luma workaround - GX_memoryFill((u64*)FRAMEBUF_TOP_A_1, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB + 0x2A300, 0, - (u64*)FRAMEBUF_TOP_A_2, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB + 0x2A300, 0); - *((vu32*)(0x10400400+0x70)) = 0x00080341; // Format GL_RGB8_OES - *((vu32*)(0x10400400+0x90)) = SCREEN_HEIGHT_TOP * 3; // Stride 0 - *((vu32*)(0x10400500+0x70)) = 0x00080301; // Format GL_RGB8_OES - *((vu32*)(0x10400500+0x90)) = SCREEN_HEIGHT_SUB * 3; // Stride 0 -} diff --git a/source/arm11/gpio.c b/source/arm11/gpio.c deleted file mode 100644 index 4385ea1..0000000 --- a/source/arm11/gpio.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 . - */ - -#include "types.h" -#include "mem_map.h" - - -#define REGs_GPIO ((vu16*)(IO_MEM_ARM9_ARM11 + 0x47000)) - - - -void GPIO_setBit(u16 reg, u8 bitNum) -{ - REGs_GPIO[reg] |= 1u<. - */ - -#include "types.h" -#include "arm11/start.h" -#include "arm11/interrupt.h" -#include "arm11/timer.h" -#include "arm11/i2c.h" -#include "pxi.h" -#include "arm11/hid.h" - - - -void hardwareInit(void) -{ - IRQ_init(); - TIMER_init(); - - if(!getCpuId()) - { - I2C_init(); - PXI_init(); - hidInit(); - } - else - { - // We don't need core 1 yet so back it goes into boot11. - deinitCpu(); - ((void (*)(void))0x0001004C)(); - } -} - -/*void hardwareDeinit(void) -{ -}*/ diff --git a/source/arm11/hardware/cache.s b/source/arm11/hardware/cache.s new file mode 100644 index 0000000..82dadf4 --- /dev/null +++ b/source/arm11/hardware/cache.s @@ -0,0 +1,115 @@ +/* + * 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 . + */ + +#include "asmfunc.h" + +.arm +.cpu mpcore +.fpu vfpv2 + + +#define CACHE_LINE_SIZE (32) + + + +ASM_FUNC invalidateICache + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ Invalidate Entire Instruction Cache, also flushes the branch target cache + @mcr p15, 0, r0, c7, c5, 6 @ Flush Entire Branch Target Cache + mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier + mcr p15, 0, r0, c7, c5, 4 @ Flush Prefetch Buffer + bx lr + + +ASM_FUNC invalidateICacheRange + add r1, r1, r0 + bic r0, r0, #(CACHE_LINE_SIZE - 1) + mov r2, #0 + invalidateICacheRange_lp: + mcr p15, 0, r0, c7, c5, 1 @ Invalidate Instruction Cache Line (using MVA) + add r0, r0, #CACHE_LINE_SIZE + cmp r0, r1 + blt invalidateICacheRange_lp + mcr p15, 0, r2, c7, c5, 6 @ Flush Entire Branch Target Cache + mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier + mcr p15, 0, r2, c7, c5, 4 @ Flush Prefetch Buffer + bx lr + + +ASM_FUNC flushDCache + mov r0, #0 + mcr p15, 0, r0, c7, c10, 0 @ "Clean Entire Data Cache" + mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier + bx lr + + +ASM_FUNC flushInvalidateDCache + mov r0, #0 + mcr p15, 0, r0, c7, c14, 0 @ "Clean and Invalidate Entire Data Cache" + mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier + bx lr + + +ASM_FUNC flushDCacheRange + add r1, r1, r0 + bic r0, r0, #(CACHE_LINE_SIZE - 1) + mov r2, #0 + flushDCacheRange_lp: + mcr p15, 0, r0, c7, c10, 1 @ "Clean Data Cache Line (using MVA)" + add r0, r0, #CACHE_LINE_SIZE + cmp r0, r1 + blt flushDCacheRange_lp + mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier + bx lr + + +ASM_FUNC flushInvalidateDCacheRange + add r1, r1, r0 + bic r0, r0, #(CACHE_LINE_SIZE - 1) + mov r2, #0 + flushInvalidateDCacheRange_lp: + mcr p15, 0, r0, c7, c14, 1 @ "Clean and Invalidate Data Cache Line (using MVA)" + add r0, r0, #CACHE_LINE_SIZE + cmp r0, r1 + blt flushInvalidateDCacheRange_lp + mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier + bx lr + + +ASM_FUNC invalidateDCache + mov r0, #0 + mcr p15, 0, r0, c7, c6, 0 @ Invalidate Entire Data Cache + mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier + bx lr + + +ASM_FUNC invalidateDCacheRange + add r1, r1, r0 + tst r0, #(CACHE_LINE_SIZE - 1) + mcrne p15, 0, r0, c7, c10, 1 @ "Clean Data Cache Line (using MVA)" + tst r1, #(CACHE_LINE_SIZE - 1) + mcrne p15, 0, r1, c7, c10, 1 @ "Clean Data Cache Line (using MVA)" + bic r0, r0, #(CACHE_LINE_SIZE - 1) + mov r2, #0 + invalidateDCacheRange_lp: + mcr p15, 0, r0, c7, c6, 1 @ Invalidate Data Cache Line (using MVA) + add r0, r0, #CACHE_LINE_SIZE + cmp r0, r1 + blt invalidateDCacheRange_lp + mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier + bx lr diff --git a/source/arm11/hardware/exception.s b/source/arm11/hardware/exception.s new file mode 100644 index 0000000..730b3db --- /dev/null +++ b/source/arm11/hardware/exception.s @@ -0,0 +1,70 @@ +/* + * 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 . + */ + +#include "asmfunc.h" + +.arm +.cpu mpcore +.fpu vfpv2 + +.extern deinitCpu +.extern privIrqHandlerTable +.extern irqHandlerTable + + + +ASM_FUNC tmpExceptionHandler + bl deinitCpu + ldr r0, =0x10202A04 + mov r1, #0xFF + orr r1, #0x1000000 + str r1, [r0] +tmpExceptionHandler_lp: + wfi + b tmpExceptionHandler_lp +.pool + + +ASM_FUNC irqHandler + sub lr, lr, #4 + srsfd sp!, #31 @ Store lr and spsr on system mode stack + cps #31 @ Switch to system mode + stmfd sp!, {r0-r3, r12, lr} + mov r12, #0x17000000 + orr r12, r12, #0xE00000 + ldr r0, [r12, #0x10C] @ REG_CPU_II_AKN + and r1, r0, #0x7F + cmp r1, #32 + ldrlo r2, =privIrqHandlerTable + mrclo p15, 0, r3, c0, c0, 5 @ Get CPU ID + andlo r3, r3, #3 + addlo r2, r2, r3, lsl #7 + ldrhs r2, =irqHandlerTable + subhs r1, r1, #32 + ldr r3, [r2, r1, lsl #2] + cmp r3, #0 + beq irqHandler_skip_processing + stmfd sp!, {r0, r12} + cpsie i + blx r3 + cpsid i + ldmfd sp!, {r0, r12} +irqHandler_skip_processing: + str r0, [r12, #0x110] @ REG_CPU_II_EOI + ldmfd sp!, {r0-r3, r12, lr} + rfefd sp! @ Restore lr (pc) and spsr (cpsr) diff --git a/source/arm11/hardware/gfx.c b/source/arm11/hardware/gfx.c new file mode 100644 index 0000000..3e6ec8b --- /dev/null +++ b/source/arm11/hardware/gfx.c @@ -0,0 +1,271 @@ +/* + * 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 . + */ + +/* + * Based on code from https://github.com/AuroraWright/Luma3DS + * for compatibility. + * + * Credits go to the Luma3DS devs and derrek for reverse engineering boot11. +*/ + +#include "types.h" +#include "mem_map.h" +#include "hardware/gfx.h" +#include "arm11/hardware/i2c.h" +#include "arm11/hardware/timer.h" +#include "arm11/hardware/interrupt.h" + + +#define PDN_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x40000) +#define REG_PDN_GPU_CNT *((vu32*)(PDN_REGS_BASE + 0x1200)) +#define REG_PDN_GPU_CNT2 *((vu32*)(PDN_REGS_BASE + 0x1204)) +#define REG_PDN_GPU_CNT2_8BIT *((vu8* )(PDN_REGS_BASE + 0x1204)) +#define REG_PDN_GPU_CNT4 *((vu8* )(PDN_REGS_BASE + 0x1208)) +#define REG_PDN_GPU_CNT3 *((vu16*)(PDN_REGS_BASE + 0x1210)) + +#define LCD_REGS_BASE (IO_MEM_ARM11_ONLY + 0x2000) +#define REG_LCD_COLORFILL_MAIN *((vu32*)(LCD_REGS_BASE + 0x204)) +#define REG_LCD_COLORFILL_SUB *((vu32*)(LCD_REGS_BASE + 0xA04)) +#define REG_LCD_BACKLIGHT_MAIN *((vu32*)(LCD_REGS_BASE + 0x240)) +#define REG_LCD_BACKLIGHT_SUB *((vu32*)(LCD_REGS_BASE + 0xA40)) + +#define GPU_EXT_REGS_BASE (IO_MEM_ARM11_ONLY + 0x200000) +#define REG_GPU_EXT_CNT *((vu32*)(GPU_EXT_REGS_BASE + 0x04)) + + + +static void gfxSetupLcdTop(void) +{ + *((vu32*)(0x10400400+0x00)) = 0x000001C2; + *((vu32*)(0x10400400+0x04)) = 0x000000D1; + *((vu32*)(0x10400400+0x08)) = 0x000001C1; + *((vu32*)(0x10400400+0x0C)) = 0x000001C1; + *((vu32*)(0x10400400+0x10)) = 0x00000000; + *((vu32*)(0x10400400+0x14)) = 0x000000CF; + *((vu32*)(0x10400400+0x18)) = 0x000000d1; + *((vu32*)(0x10400400+0x1C)) = 0x01C501C1; + *((vu32*)(0x10400400+0x20)) = 0x00010000; + *((vu32*)(0x10400400+0x24)) = 0x0000019D; + *((vu32*)(0x10400400+0x28)) = 0x00000002; + *((vu32*)(0x10400400+0x2C)) = 0x00000192; + *((vu32*)(0x10400400+0x30)) = 0x00000192; + *((vu32*)(0x10400400+0x34)) = 0x00000192; + *((vu32*)(0x10400400+0x38)) = 0x00000001; + *((vu32*)(0x10400400+0x3C)) = 0x00000002; + *((vu32*)(0x10400400+0x40)) = 0x01960192; + *((vu32*)(0x10400400+0x44)) = 0x00000000; + *((vu32*)(0x10400400+0x48)) = 0x00000000; + *((vu32*)(0x10400400+0x5C)) = (SCREEN_WIDTH_TOP << 16) | SCREEN_HEIGHT_TOP; // Width and height + *((vu32*)(0x10400400+0x60)) = 0x01C100D1; + *((vu32*)(0x10400400+0x64)) = 0x01920002; + *((vu32*)(0x10400400+0x68)) = FRAMEBUF_TOP_A_1; // Framebuffer A first address + *((vu32*)(0x10400400+0x6C)) = FRAMEBUF_TOP_A_2; // Framebuffer A second address + *((vu32*)(0x10400400+0x70)) = 0x00080042; // Format GL_RGB565_OES + *((vu32*)(0x10400400+0x74)) = 0x00010501; + *((vu32*)(0x10400400+0x78)) = 0x00000000; // Framebuffer select 0 + *((vu32*)(0x10400400+0x90)) = SCREEN_HEIGHT_TOP * 2; // Stride 0 + *((vu32*)(0x10400400+0x94)) = FRAMEBUF_TOP_A_1; // Framebuffer B first address + *((vu32*)(0x10400400+0x98)) = FRAMEBUF_TOP_A_2; // Framebuffer B second address + *((vu32*)(0x10400400+0x9C)) = 0x00000000; + + for(u32 i = 0; i < 0x100; i++) + { + u32 val = 0x10101; + val *= i; + *((vu32*)(0x10400400+0x84)) = val; + } +} + +static void gfxSetupLcdLow(void) +{ + *((vu32*)(0x10400500+0x00)) = 0x000001C2; + *((vu32*)(0x10400500+0x04)) = 0x000000D1; + *((vu32*)(0x10400500+0x08)) = 0x000001C1; + *((vu32*)(0x10400500+0x0C)) = 0x000001C1; + *((vu32*)(0x10400500+0x10)) = 0x000000CD; + *((vu32*)(0x10400500+0x14)) = 0x000000CF; + *((vu32*)(0x10400500+0x18)) = 0x000000D1; + *((vu32*)(0x10400500+0x1C)) = 0x01C501C1; + *((vu32*)(0x10400500+0x20)) = 0x00010000; + *((vu32*)(0x10400500+0x24)) = 0x0000019D; + *((vu32*)(0x10400500+0x28)) = 0x00000052; + *((vu32*)(0x10400500+0x2C)) = 0x00000192; + *((vu32*)(0x10400500+0x30)) = 0x00000192; + *((vu32*)(0x10400500+0x34)) = 0x0000004F; + *((vu32*)(0x10400500+0x38)) = 0x00000050; + *((vu32*)(0x10400500+0x3C)) = 0x00000052; + *((vu32*)(0x10400500+0x40)) = 0x01980194; + *((vu32*)(0x10400500+0x44)) = 0x00000000; + *((vu32*)(0x10400500+0x48)) = 0x00000011; + *((vu32*)(0x10400500+0x5C)) = (SCREEN_WIDTH_SUB << 16) | SCREEN_HEIGHT_SUB; // Width and height + *((vu32*)(0x10400500+0x60)) = 0x01C100D1; + *((vu32*)(0x10400500+0x64)) = 0x01920052; + *((vu32*)(0x10400500+0x68)) = FRAMEBUF_SUB_A_1; // Framebuffer first address + *((vu32*)(0x10400500+0x6C)) = FRAMEBUF_SUB_A_2; // Framebuffer second address + *((vu32*)(0x10400500+0x70)) = 0x00080002; // Format GL_RGB565_OES + *((vu32*)(0x10400500+0x74)) = 0x00010501; + *((vu32*)(0x10400500+0x78)) = 0x00000000; // Framebuffer select 0 + *((vu32*)(0x10400500+0x90)) = SCREEN_HEIGHT_SUB * 2; // Stride 0 + *((vu32*)(0x10400500+0x9C)) = 0x00000000; + + for(u32 i = 0; i < 0x100; i++) + { + u32 val = 0x10101; + val *= i; + *((vu32*)(0x10400500+0x84)) = val; + } +} + +static void gfxSetupFramebuffers(void) +{ + // Top screen + *((vu32*)(0x10400400+0x5C)) = (SCREEN_WIDTH_TOP << 16) | SCREEN_HEIGHT_TOP; // Width and height + *((vu32*)(0x10400400+0x68)) = FRAMEBUF_TOP_A_1; // Framebuffer A first address + *((vu32*)(0x10400400+0x6C)) = FRAMEBUF_TOP_A_2; // Framebuffer A second address + *((vu32*)(0x10400400+0x70)) = 0x00080042; // Format GL_RGB565_OES + *((vu32*)(0x10400400+0x78)) = 0x00000000; // Framebuffer select 0 + *((vu32*)(0x10400400+0x90)) = SCREEN_HEIGHT_TOP * 2; // Stride 0 + *((vu32*)(0x10400400+0x94)) = FRAMEBUF_TOP_A_1; // Framebuffer B first address + *((vu32*)(0x10400400+0x98)) = FRAMEBUF_TOP_A_2; // Framebuffer B second address + + // Bottom screen + *((vu32*)(0x10400500+0x5C)) = (SCREEN_WIDTH_SUB << 16) | SCREEN_HEIGHT_SUB; // Width and height + *((vu32*)(0x10400500+0x68)) = FRAMEBUF_SUB_A_1; // Framebuffer first address + *((vu32*)(0x10400500+0x6C)) = FRAMEBUF_SUB_A_2; // Framebuffer second address + *((vu32*)(0x10400500+0x70)) = 0x00080002; // Format GL_RGB565_OES + *((vu32*)(0x10400500+0x78)) = 0x00000000; // Framebuffer select 0 + *((vu32*)(0x10400500+0x90)) = SCREEN_HEIGHT_SUB * 2; // Stride 0 +} + +void GX_memoryFill(u64 *buf0a, u32 buf0v, u32 buf0Sz, u32 val0, u64 *buf1a, u32 buf1v, u32 buf1Sz, u32 val1) +{ + vu32 *REGs_PSC0 = (vu32*)0x10400010; + vu32 *REGs_PSC1 = (vu32*)0x10400020; + + REGs_PSC0[0] = (u32)buf0a>>3; // Start address + REGs_PSC0[1] = ((u32)buf0a + buf0Sz)>>3; // End address + REGs_PSC0[2] = val0; // Fill value + REGs_PSC0[3] = buf0v | 1u; // Pattern + start + + REGs_PSC1[0] = (u32)buf1a>>3; // Start address + REGs_PSC1[1] = ((u32)buf1a + buf1Sz)>>3; // End address + REGs_PSC1[2] = val1; // Fill value + REGs_PSC1[3] = buf1v | 1u; // Pattern + start +} + +void GX_displayTransfer(u64 *in, u32 indim, u64 *out, u32 outdim, u32 flags) +{ + vu32 *REGs_TE = (vu32*)0x10400C00; + + REGs_TE[0] = (u32)in>>3; + REGs_TE[1] = (u32)out>>3; + REGs_TE[2] = indim; + REGs_TE[3] = outdim; + REGs_TE[4] = flags; + REGs_TE[5] = 0; + REGs_TE[6] = 1; +} + +void GX_textureCopy(u64 *in, u32 indim, u64 *out, u32 outdim, u32 size) +{ + vu32 *REGs_TE = (vu32*)0x10400C00; + + REGs_TE[0] = (u32)in>>3; + REGs_TE[1] = (u32)out>>3; + REGs_TE[4] = 1u<<3; + REGs_TE[5] = 0; + REGs_TE[8] = size; + REGs_TE[9] = indim; + REGs_TE[10] = outdim; + REGs_TE[6] = 1; +} + +void GFX_setBrightness(u32 brightness) +{ + REG_LCD_BACKLIGHT_MAIN = brightness; + REG_LCD_BACKLIGHT_SUB = brightness; +} + +void GFX_swapFramebufs(void) +{ + static u32 activeFb = 0; + activeFb ^= 1; + + *((vu32*)(0x10400400+0x78)) = activeFb; + *((vu32*)(0x10400500+0x78)) = activeFb; +} + +static void vblankIrqHandler(UNUSED u32 intSource) +{ + GX_textureCopy((u64*)FRAMEBUF_TOP_A_1, 0, (u64*)FRAMEBUF_TOP_A_2, 0, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB); +} + +void GFX_init(void) +{ + if(REG_PDN_GPU_CNT != 0x1007F) // Check if screens are already initialized + { + REG_PDN_GPU_CNT = 0x1007F; + *((vu32*)0x10202014) = 0x00000001; + *((vu32*)0x1020200C) &= 0xFFFEFFFE; + REG_LCD_COLORFILL_MAIN = 1u<<24; + REG_LCD_COLORFILL_SUB = 1u<<24; + REG_LCD_BACKLIGHT_MAIN = 0x30; + REG_LCD_BACKLIGHT_SUB = 0x30; + *((vu32*)0x10202244) = 0x1023E; + *((vu32*)0x10202A44) = 0x1023E; + + gfxSetupLcdTop(); + gfxSetupLcdLow(); + + // The GPU mem fill races against the console. + //GX_memoryFill((u64*)FRAMEBUF_TOP_A_1, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB, 0, + // (u64*)FRAMEBUF_TOP_A_2, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB, 0); + I2C_writeReg(I2C_DEV_MCU, 0x22, 0x2A); + + // We must make sure the I2C bus is not used until this finishes + // otherwise the screens may not turn on on New 3DS. + TIMER_sleepMs(3); + } + else + { + REG_LCD_COLORFILL_MAIN = 1u<<24; + REG_LCD_COLORFILL_SUB = 1u<<24; + REG_LCD_BACKLIGHT_MAIN = 0x30; + REG_LCD_BACKLIGHT_SUB = 0x30; + gfxSetupFramebuffers(); + } + + IRQ_registerHandler(IRQ_PDC0, 14, 0, true, vblankIrqHandler); + GFX_swapFramebufs(); + + REG_LCD_COLORFILL_MAIN = 0; + REG_LCD_COLORFILL_SUB = 0; +} + +void GFX_deinit(void) +{ + IRQ_unregisterHandler(IRQ_PDC0); + + // Temporary Luma workaround + GX_memoryFill((u64*)FRAMEBUF_TOP_A_1, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB + 0x2A300, 0, + (u64*)FRAMEBUF_TOP_A_2, 1u<<9, SCREEN_SIZE_TOP + SCREEN_SIZE_SUB + 0x2A300, 0); + *((vu32*)(0x10400400+0x70)) = 0x00080341; // Format GL_RGB8_OES + *((vu32*)(0x10400400+0x90)) = SCREEN_HEIGHT_TOP * 3; // Stride 0 + *((vu32*)(0x10400500+0x70)) = 0x00080301; // Format GL_RGB8_OES + *((vu32*)(0x10400500+0x90)) = SCREEN_HEIGHT_SUB * 3; // Stride 0 +} diff --git a/source/arm11/hardware/gpio.c b/source/arm11/hardware/gpio.c new file mode 100644 index 0000000..4385ea1 --- /dev/null +++ b/source/arm11/hardware/gpio.c @@ -0,0 +1,35 @@ +/* + * 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 . + */ + +#include "types.h" +#include "mem_map.h" + + +#define REGs_GPIO ((vu16*)(IO_MEM_ARM9_ARM11 + 0x47000)) + + + +void GPIO_setBit(u16 reg, u8 bitNum) +{ + REGs_GPIO[reg] |= 1u<. + */ + +#include "types.h" +#include "arm11/start.h" +#include "arm11/hardware/interrupt.h" +#include "arm11/hardware/timer.h" +#include "arm11/hardware/i2c.h" +#include "hardware/pxi.h" +#include "arm11/hardware/hid.h" + + + +void hardwareInit(void) +{ + IRQ_init(); + TIMER_init(); + + if(!getCpuId()) + { + I2C_init(); + PXI_init(); + hidInit(); + } + else + { + // We don't need core 1 yet so back it goes into boot11. + deinitCpu(); + ((void (*)(void))0x0001004C)(); + } +} + +/*void hardwareDeinit(void) +{ +}*/ diff --git a/source/arm11/hardware/hid.c b/source/arm11/hardware/hid.c new file mode 100644 index 0000000..7212e28 --- /dev/null +++ b/source/arm11/hardware/hid.c @@ -0,0 +1,95 @@ +/* + * 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 . + */ + +/* + * Based on code from https://github.com/smealum/ctrulib + */ + +#include "types.h" +#include "mem_map.h" +#include "arm11/hardware/hid.h" +#include "arm11/hardware/i2c.h" +#include "arm11/hardware/interrupt.h" +#include "arm11/hardware/gpio.h" + + +#define REG_HID_PAD (*((vu16*)(IO_MEM_ARM9_ARM11 + 0x46000)) ^ 0xFFFFu) + + +static u32 kHeld, kDown, kUp, homeShellState, powerWifiState; + + + +static void hidIrqHandler(UNUSED u32 intSource); + +void hidInit(void) +{ + IRQ_registerHandler(IRQ_MCU_HID, 14, 0, true, hidIrqHandler); + GPIO_setBit(19, 9); // This enables the MCU HID IRQ +} + +static void hidIrqHandler(UNUSED u32 intSource) +{ + const u32 state = (u32)i2cmcu_readreg_hid_irq(); + + powerWifiState |= state & 3; + powerWifiState |= state>>2 & 4; + + homeShellState |= (state & 4)<<19; + homeShellState |= (state & 0x20)<<17; + + if(homeShellState & KEY_HOME) homeShellState ^= (state & 8)<<18; + if(homeShellState & KEY_SHELL) homeShellState ^= (state & 0x40)<<16; +} + +u32 hidGetPowerButton(void) +{ + u32 tmp = powerWifiState; + powerWifiState &= ~3; + return tmp & 3; +} + +u32 hidGetWifiButton(void) +{ + u32 tmp = powerWifiState; + powerWifiState &= ~4; + return tmp>>2; +} + +void hidScanInput(void) +{ + u32 kOld = kHeld; + kHeld = homeShellState | REG_HID_PAD; + kDown = (~kOld) & kHeld; + kUp = kOld & (~kHeld); +} + +u32 hidKeysHeld(void) +{ + return kHeld; +} + +u32 hidKeysDown(void) +{ + return kDown; +} + +u32 hidKeysUp(void) +{ + return kUp; +} diff --git a/source/arm11/hardware/i2c.c b/source/arm11/hardware/i2c.c new file mode 100644 index 0000000..b746f7f --- /dev/null +++ b/source/arm11/hardware/i2c.c @@ -0,0 +1,265 @@ +/* + * 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 . + */ + +#include "types.h" +#include "mem_map.h" +#include "arm11/hardware/i2c.h" +#include "arm11/hardware/interrupt.h" + + +#define I2C1_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x61000) +#define REG_I2C1_DATA *((vu8* )(I2C1_REGS_BASE + 0x00)) +#define REG_I2C1_CNT *((vu8* )(I2C1_REGS_BASE + 0x01)) +#define REG_I2C1_CNTEX *((vu16*)(I2C1_REGS_BASE + 0x02)) +#define REG_I2C1_SCL *((vu16*)(I2C1_REGS_BASE + 0x04)) + +#define I2C2_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x44000) +#define REG_I2C2_DATA *((vu8* )(I2C2_REGS_BASE + 0x00)) +#define REG_I2C2_CNT *((vu8* )(I2C2_REGS_BASE + 0x01)) +#define REG_I2C2_CNTEX *((vu16*)(I2C2_REGS_BASE + 0x02)) +#define REG_I2C2_SCL *((vu16*)(I2C2_REGS_BASE + 0x04)) + +#define I2C3_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x48000) +#define REG_I2C3_DATA *((vu8* )(I2C3_REGS_BASE + 0x00)) +#define REG_I2C3_CNT *((vu8* )(I2C3_REGS_BASE + 0x01)) +#define REG_I2C3_CNTEX *((vu16*)(I2C3_REGS_BASE + 0x02)) +#define REG_I2C3_SCL *((vu16*)(I2C3_REGS_BASE + 0x04)) + + +static const struct +{ + u8 busId; + u8 devAddr; +} i2cDevTable[] = +{ + {0, 0x4A}, + {0, 0x7A}, + {0, 0x78}, + {1, 0x4A}, + {1, 0x78}, + {1, 0x2C}, + {1, 0x2E}, + {1, 0x40}, + {1, 0x44}, + {2, 0xA6}, // TODO: Find out if 0xA6 or 0xD6 is correct + {2, 0xD0}, + {2, 0xD2}, + {2, 0xA4}, + {2, 0x9A}, + {2, 0xA0}, + {1, 0xEE}, + {0, 0x40}, + {2, 0x54} +}; + + + +static void i2cWaitBusy(vu8 *cntReg) +{ + while(*cntReg & I2C_ENABLE); +} + +static vu8* i2cGetBusRegsBase(u8 busId) +{ + vu8 *base; + if(!busId) base = (vu8*)I2C1_REGS_BASE; + else if(busId == 1) base = (vu8*)I2C2_REGS_BASE; + else base = (vu8*)I2C3_REGS_BASE; + + return base; +} + +static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, vu8 *regsBase) +{ + const u8 devAddr = i2cDevTable[devId].devAddr; + vu8 *const i2cData = regsBase; + vu8 *const i2cCnt = regsBase + 1; + + + u32 i = 0; + for(; i < 8; i++) + { + i2cWaitBusy(i2cCnt); + + // Select device and start. + *i2cData = devAddr; + *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; + i2cWaitBusy(i2cCnt); + if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. + { + *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + continue; + } + + // Select register and change direction to write. + *i2cData = regAddr; + *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; + i2cWaitBusy(i2cCnt); + if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. + { + *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + continue; + } + + // Select device in read mode for read transfer. + if(read) + { + *i2cData = devAddr | 1u; // Set bit 0 for read. + *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; + i2cWaitBusy(i2cCnt); + if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. + { + *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + continue; + } + } + + break; + } + + if(i < 8) return true; + else return false; +} + +void I2C_init(void) +{ + i2cWaitBusy(i2cGetBusRegsBase(0)); + REG_I2C1_CNTEX = 2; // ? + REG_I2C1_SCL = 1280; // ? + + i2cWaitBusy(i2cGetBusRegsBase(1)); + REG_I2C2_CNTEX = 2; // ? + REG_I2C2_SCL = 1280; // ? + + i2cWaitBusy(i2cGetBusRegsBase(2)); + REG_I2C3_CNTEX = 2; // ? + REG_I2C3_SCL = 1280; // ? +} + +bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size) +{ + enterCriticalSection(); // TODO: Instead of blocking other interrupts we need locks. + const u8 busId = i2cDevTable[devId].busId; + vu8 *const i2cData = i2cGetBusRegsBase(busId); + vu8 *const i2cCnt = i2cData + 1; + + + if(!i2cStartTransfer(devId, regAddr, true, i2cData)) + { + leaveCriticalSection(); + return false; + } + + while(--size) + { + *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK; + i2cWaitBusy(i2cCnt); + *out++ = *i2cData; + } + + *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP; + i2cWaitBusy(i2cCnt); + *out = *i2cData; // Last byte + + leaveCriticalSection(); + return true; +} + +bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size) +{ + enterCriticalSection(); // TODO: Instead of blocking other interrupts we need locks. + const u8 busId = i2cDevTable[devId].busId; + vu8 *const i2cData = i2cGetBusRegsBase(busId); + vu8 *const i2cCnt = i2cData + 1; + + + if(!i2cStartTransfer(devId, regAddr, false, i2cData)) + { + leaveCriticalSection(); + return false; + } + + while(--size) + { + *i2cData = *in++; + *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; + i2cWaitBusy(i2cCnt); + if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. + { + *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + leaveCriticalSection(); + return false; + } + } + + *i2cData = *in; + *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_STOP; + i2cWaitBusy(i2cCnt); + if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. + { + *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; + leaveCriticalSection(); + return false; + } + + leaveCriticalSection(); + return true; +} + +u8 I2C_readReg(I2cDevice devId, u8 regAddr) +{ + u8 data; + if(!I2C_readRegBuf(devId, regAddr, &data, 1)) return 0xFF; + return data; +} + +bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data) +{ + return I2C_writeRegBuf(devId, regAddr, &data, 1); +} + +u8 i2cmcu_readreg_hid_irq(void) +{ + u8 data; + if(!I2C_readRegBuf(I2C_DEV_MCU, 0x10, &data, 1)) return 0; + return data; +} + +u8 i2cmcu_readreg_hid_held(void) +{ + u8 data[19]; + if(!I2C_readRegBuf(I2C_DEV_MCU, 0x7F, data, sizeof(data))) return 0; + return data[18]; +} + +// aka i2cmcu_write_reg0x20_0x22 +bool i2cmcu_lcd_poweron(void) +{ + return I2C_writeReg(I2C_DEV_MCU, 0x22, 2); // bit1 = lcd power enable for both screens +} + +// aka i2cmcu_write_reg0x20_0x22_2 +bool i2cmcu_lcd_backlight_poweron(void) +{ + return I2C_writeReg(I2C_DEV_MCU, 0x22, 0x28); // bit3 = lower screen, bit5 = upper +} + +bool i2cmcu_lcd_poweroff(void) +{ + return I2C_writeReg(I2C_DEV_MCU, 0x22, 1); // bit0 = lcd power disable for both screens (also disabled backlight) +} diff --git a/source/arm11/hardware/interrupt.c b/source/arm11/hardware/interrupt.c new file mode 100644 index 0000000..0c0b19e --- /dev/null +++ b/source/arm11/hardware/interrupt.c @@ -0,0 +1,186 @@ +/* + * 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 . + */ + +#include "types.h" +#include "mem_map.h" +#include "arm11/hardware/interrupt.h" +#include "arm11/start.h" + + +#define REG_CFG11_FIQ_CNT *((vu8* )(IO_MEM_ARM9_ARM11 + 0x40000 + 0x0104)) + +#define CPU_II_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x100) +#define REG_CPU_II_CNT *((vu32*)(CPU_II_REGS_BASE + 0x00)) +#define REG_CPU_II_MASK *((vu32*)(CPU_II_REGS_BASE + 0x04)) +#define REG_CPU_II_BIN_POI *((vu32*)(CPU_II_REGS_BASE + 0x08)) +#define REG_CPU_II_AKN *((vu32*)(CPU_II_REGS_BASE + 0x0C)) +#define REG_CPU_II_EOI *((vu32*)(CPU_II_REGS_BASE + 0x10)) +#define REG_CPU_II_RUN_PRIO *((vu32*)(CPU_II_REGS_BASE + 0x14)) +#define REG_CPU_II_HIGH_PEN *((vu32*)(CPU_II_REGS_BASE + 0x18)) + +#define GID_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x1000) +#define REG_GID_CNT *((vu32*)(GID_REGS_BASE + 0x000)) +#define REG_GID_CONTR_TYPE *((vu32*)(GID_REGS_BASE + 0x004)) +#define REGs_GID_ENA_SET ((vu32*)(GID_REGS_BASE + 0x100)) +#define REGs_GID_ENA_CLR ((vu32*)(GID_REGS_BASE + 0x180)) +#define REGs_GID_PEN_SET ((vu32*)(GID_REGS_BASE + 0x200)) +#define REGs_GID_PEN_CLR ((vu32*)(GID_REGS_BASE + 0x280)) +#define REGs_GID_ACTIVE_BIT ((vu32*)(GID_REGS_BASE + 0x300)) +#define REGs_GID_IPRIO ((vu32*)(GID_REGS_BASE + 0x400)) +#define REGs_GID_ITARG ((vu32*)(GID_REGS_BASE + 0x800)) +#define REGs_GID_ICONF ((vu32*)(GID_REGS_BASE + 0xC00)) +#define REGs_GID_LINE_LEV ((vu32*)(GID_REGS_BASE + 0xD00)) +#define REG_GID_SW_INT *((vu32*)(GID_REGS_BASE + 0xF00)) +#define REG_GID_PERI_INFO0 *((vu32*)(GID_REGS_BASE + 0xFE0)) +#define REG_GID_PERI_INFO1 *((vu32*)(GID_REGS_BASE + 0xFE4)) +#define REG_GID_PERI_INFO2 *((vu32*)(GID_REGS_BASE + 0xFE8)) +#define REG_GID_PERI_INFO3 *((vu32*)(GID_REGS_BASE + 0xFEC)) +#define REG_GID_PRIME_CELL0 *((vu32*)(GID_REGS_BASE + 0xFF0)) +#define REG_GID_PRIME_CELL1 *((vu32*)(GID_REGS_BASE + 0xFF4)) +#define REG_GID_PRIME_CELL2 *((vu32*)(GID_REGS_BASE + 0xFF8)) +#define REG_GID_PRIME_CELL3 *((vu32*)(GID_REGS_BASE + 0xFFC)) + + +IrqHandler privIrqHandlerTable[4][32] = {0}; // Table for private MPCore interrupts +IrqHandler irqHandlerTable[96] = {0}; // There are 96 external interrupts (total 128) + + + +void IRQ_init(void) +{ + // Disable the interrupt interface for this CPU + REG_CPU_II_CNT = 0; + + + if(!getCpuId()) + { + // Disable the global interrupt distributor + REG_GID_CNT = 0; + + // Disable all 128 interrupts + REGs_GID_ENA_CLR[0] = 0xFFFFFFFFu; // Interrupts 0-15 cant be disabled + REGs_GID_ENA_CLR[1] = 0xFFFFFFFFu; + REGs_GID_ENA_CLR[2] = 0xFFFFFFFFu; + REGs_GID_ENA_CLR[3] = 0xFFFFFFFFu; + + // Set all pending interrupts to inactive state + REGs_GID_PEN_CLR[0] = 0xFFFFFFFFu; // Interrupt 0-15 can't be set to inactive apparently + REGs_GID_PEN_CLR[1] = 0xFFFFFFFFu; + REGs_GID_PEN_CLR[2] = 0xFFFFFFFFu; + REGs_GID_PEN_CLR[3] = 0xFFFFFFFFu; + + // Set all 128 interrupts to lowest priority + for(u32 i = 0; i < 32; i++) REGs_GID_IPRIO[i] = 0xE0E0E0E0u; + + // Set all 128 interrupts to target no CPU. + // Interrupt 0-31 can't be changed + for(u32 i = 8; i < 32; i++) REGs_GID_ITARG[i] = 0; + + // Set all interrupts to rising edge sensitive and 1-N software model + for(u32 i = 0; i < 8; i++) REGs_GID_ICONF[i] = 0xFFFFFFFFu; + + // Enable the global interrupt distributor + REG_GID_CNT = 1; + } + else + { + REGs_GID_PEN_CLR[0] = 0xFFFFFFFFu; + + for(u32 i = 0; i < 8; i++) REGs_GID_IPRIO[i] = 0xE0E0E0E0u; + + REGs_GID_ICONF[0] = 0xFFFFFFFFu; + REGs_GID_ICONF[1] = 0xFFFFFFFFu; + } + + + // Mask no interrupt + REG_CPU_II_MASK = 0xF0; + // All priority bits are compared for pre-emption + REG_CPU_II_BIN_POI = 3; + // Enable the interrupt interface for this CPU + REG_CPU_II_CNT = 1; + + // Get rid of all interrupts stuck in pending/active state + u32 tmp; + do + { + tmp = REG_CPU_II_AKN; // Aknowledge + REG_CPU_II_EOI = tmp; // End of interrupt + } while(tmp != 1023); + + leaveCriticalSection(); // Enables interrupts +} + +void IRQ_registerHandler(Interrupt id, u8 prio, u8 cpuMask, bool edgeTriggered, IrqHandler handler) +{ + enterCriticalSection(); + + const u32 cpuId = getCpuId(); + + if(!cpuMask) cpuMask = 1u<>2] & ~(0xFu<>2] = tmp | (u32)prio<>2] & ~(0xFu<>2] = tmp | (u32)cpuMask<>4] & ~(1u<>4] = tmp | (u32)edgeTriggered<>5] = 1u<<(id % 32); + + leaveCriticalSection(); +} + +void IRQ_unregisterHandler(Interrupt id) +{ + enterCriticalSection(); + + REGs_GID_ENA_CLR[id>>5] = 1u<<(id % 32); + + if(id < 32) privIrqHandlerTable[getCpuId()][id] = (IrqHandler)NULL; + else irqHandlerTable[id - 32] = (IrqHandler)NULL; + + leaveCriticalSection(); +} + +void IRQ_setPriority(Interrupt id, u8 prio) +{ + enterCriticalSection(); + + u32 shift = (id % 4 * 8) + 4; + u32 tmp = REGs_GID_IPRIO[id>>2] & ~(0xFu<>2] = tmp | (u32)prio<. + */ + +#include "types.h" +#include "mem_map.h" +#include "arm11/start.h" +#include "arm11/hardware/interrupt.h" + + +#define SCU_REGS_BASE (MPCORE_PRIV_REG_BASE) +#define REG_SCU_CNT *((vu32*)(SCU_REGS_BASE + 0x00)) +#define REG_SCU_CONFIG *((vu32*)(SCU_REGS_BASE + 0x04)) +#define REG_SCU_CPU_STAT *((vu32*)(SCU_REGS_BASE + 0x08)) +#define REG_SCU_INVAL_TAG *((vu32*)(SCU_REGS_BASE + 0x0C)) + + + +// Mem permissions +#define PERM_NO_ACC (0b000000u) +#define PERM_PRIV_RW_USR_NO_ACC (0b000001u) +#define PERM_PRIV_RW_USR_RO (0b000010u) +#define PERM_PRIV_RW_USR_RW (0b000011u) +#define PERM_PRIV_RO_USR_NO_ACC (0b100001u) +#define PERM_PRIV_RO_USR_RO (0b100010u) + +// Predefined mem attributes. Only bits 0, 1 and 10-12 matter +#define ATTR_STRONGLY_ORDERED (0b0000000000000u) // Always shared +#define ATTR_SHARED_DEVICE (0b0000000000001u) // Always shared +#define ATTR_NORM_WRITE_TROUGH_NO_ALLOC (0b0000000000010u) +#define ATTR_NORM_WRITE_BACK_NO_ALLOC (0b0000000000011u) +#define ATTR_NORM_NONCACHABLE (0b0010000000000u) +#define ATTR_NORM_WRITE_BACK_ALLOC (0b0010000000011u) +#define ATTR_NONSHARED_DEVICE (0b0100000000000u) // Always non-shared + +// Policies for custom normal mem attributes +#define POLICY_NONCACHABLE_UNBUFFERED (0b00u) +#define POLICY_WRITE_BACK_ALLOC_BUFFERED (0b01u) +#define POLICY_WRITE_THROUGH_NO_ALLOC_BUFFERED (0b10u) // Behaves as noncacheable on ARM11 MPCore +#define POLICY_WRITE_BACK_NO_ALLOC_BUFFERED (0b11u) + +#define MAKE_CUSTOM_NORM_ATTR(outer, inner) ((1u<<12) | (outer<<10) | (inner)) + +// Converts the attribute bits from L1 format to L2 format +#define L1_TO_L2(attr) ((attr>>6 | attr) & 0x73) + + + +/** + * @brief Maps up to 4096 1 MB sections of memory. + * + * @param[in] va The virtual address base. Must be aligned to 1 MB. + * @param[in] pa The physical address base. Must be aligned to 1 MB. + * @param[in] num The number of sections to map. + * @param[in] shared If the sections are shared memory. + * @param[in] access The access permission bits. + * @param[in] domain One of the 16 possible domains. + * @param[in] xn If this memory should be marked as execute never. + * @param[in] attr Other attribute bits like caching. + */ +static void mmuMapSections(u32 va, u32 pa, u32 num, bool shared, u32 access, u8 domain, bool xn, u32 attr) +{ + for(u32 i = 0; i < 0x100000u * num; i += 0x100000u) + { + ((u32*)A11_MMU_TABLES_BASE)[(va + i)>>20] = (((pa + i) & 0xFFF00000u) | (u32)shared<<16 | access<<10 | + (u32)domain<<5 | (u32)xn<<4 | attr<<2 | 0b10u); + } +} + +/** + * @brief Maps up to 256 4 KB pages of memory. + * @brief The mapped range must not cross the next section. + * + * @param[in] va The virtual address base. Must be aligned to 4 KB. + * @param[in] pa The physical address base. Must be aligned to 4 KB. + * @param[in] num The number of pages to map. Must be <= 128. + * @param l2Table The L2 MMU table address base for this mapping. + * @param[in] shared If the pages are shared memory. + * @param[in] access The access permission bits. + * @param[in] domain One of the 16 possible domains. + * @param[in] xn If this memory should be marked as execute never. + * @param[in] attr Other attribute bits like caching. + */ +static void mmuMapPages(u32 va, u32 pa, u32 num, u32 *l2Table, bool shared, u32 access, u8 domain, bool xn, u32 attr) +{ + ((u32*)A11_MMU_TABLES_BASE)[va>>20] = (((u32)l2Table & 0xFFFFFC00u) | (u32)domain<<5 | 0b01u); + + for(u32 i = 0; i < 0x1000u * num; i += 0x1000u) + { + l2Table[(va + i)>>12 & 0xFFu] = (((pa + i) & 0xFFFFF000u) | (u32)shared<<10 | + access<<4 | attr<<2 | 0b10u | (u32)xn); + } +} + +void setupMmu(void) +{ + // TTBR0 address shared page table walk and outer cachable write-through, no allocate on write + __asm__ __volatile__("mcr p15, 0, %0, c2, c0, 0" : : "r" (A11_MMU_TABLES_BASE | 0x12u)); + // Use the 16 KB L1 table only + __asm__ __volatile__("mcr p15, 0, %0, c2, c0, 2" : : "r" (0u)); + // Domain 1 = client, remaining domains all = no access + __asm__ __volatile__("mcr p15, 0, %0, c3, c0, 0" : : "r" (4u)); + // Context ID Register (ASID = 0, PROCID = 0) + __asm__ __volatile__("mcr p15, 0, %0, c13, c0, 1" : : "r" (0u)); + + + static volatile bool syncFlag = false; + if(!getCpuId()) + { + // Clear L1 and L2 tables + clearMem((u32*)A11_MMU_TABLES_BASE, 0x4C00u); + + // IO mem mapping + mmuMapSections(IO_MEM_ARM9_ARM11, IO_MEM_ARM9_ARM11, 4, true, + PERM_PRIV_RW_USR_NO_ACC, 1, true, ATTR_SHARED_DEVICE); + + // MPCore private region mapping + mmuMapPages(MPCORE_PRIV_REG_BASE, MPCORE_PRIV_REG_BASE, 2, + (u32*)(A11_MMU_TABLES_BASE + 0x4000u), false, PERM_PRIV_RW_USR_NO_ACC, + 1, true, L1_TO_L2(ATTR_NONSHARED_DEVICE)); + + // VRAM mapping + mmuMapSections(VRAM_BASE, VRAM_BASE, 6, true, PERM_PRIV_RW_USR_NO_ACC, 1, true, ATTR_NORM_WRITE_TROUGH_NO_ALLOC); + + // DSP mem mapping to extend AXIWRAM + mmuMapPages(AXIWRAM_BASE + AXIWRAM_SIZE, DSP_MEM_BASE, 128, (u32*)(A11_MMU_TABLES_BASE + 0x4400u), true, + PERM_PRIV_RW_USR_NO_ACC, 1, true, + L1_TO_L2(MAKE_CUSTOM_NORM_ATTR(POLICY_WRITE_BACK_ALLOC_BUFFERED, POLICY_WRITE_BACK_ALLOC_BUFFERED))); + + // AXIWRAM MMU table mapping + mmuMapPages(A11_MMU_TABLES_BASE, A11_MMU_TABLES_BASE, 5, (u32*)(A11_MMU_TABLES_BASE + 0x4400u), true, + PERM_PRIV_RO_USR_NO_ACC, 1, true, L1_TO_L2(ATTR_NORM_NONCACHABLE)); + + // Remaining AXIWRAM pages + mmuMapPages(AXIWRAM_BASE + 0x5000u, AXIWRAM_BASE + 0x5000u, 123, + (u32*)(A11_MMU_TABLES_BASE + 0x4400u), true, PERM_PRIV_RW_USR_NO_ACC, 1, false, + L1_TO_L2(MAKE_CUSTOM_NORM_ATTR(POLICY_WRITE_BACK_ALLOC_BUFFERED, POLICY_WRITE_BACK_ALLOC_BUFFERED))); + + extern u32 __start__[]; + + // Map fastboot executable start to boot11 mirror (exception vectors) + mmuMapPages(BOOT11_MIRROR2, (u32)__start__, 1, (u32*)(A11_MMU_TABLES_BASE + 0x4800u), true, + PERM_PRIV_RO_USR_NO_ACC, 1, false, + L1_TO_L2(MAKE_CUSTOM_NORM_ATTR(POLICY_WRITE_BACK_ALLOC_BUFFERED, POLICY_WRITE_BACK_ALLOC_BUFFERED))); + + // Invalidate tag RAMs before enabling SMP as recommended by the MPCore doc. + REG_SCU_CNT = 0x1FFE; // Disable SCU and parity checking. Access to all CPUs interfaces. + REG_SCU_INVAL_TAG = 0xFFFF; // Invalidate SCU tag RAMs of all CPUs. + REG_SCU_CNT |= 0x2001u; // Enable SCU and parity checking. + + syncFlag = true; + signalEvent(); + } + else while(!syncFlag) waitForEvent(); + + + // Invalidate TLB (Unified TLB operation) + Data Synchronization Barrier + __asm__ __volatile__("mcr p15, 0, %0, c8, c7, 0\n\t" + "mcr p15, 0, %0, c7, c10, 4" : : "r" (0u)); + + + u32 tmp; + // Modify Auxiliary Control Register + __asm__ __volatile__("mrc p15, 0, %0, c1, c0, 1" : "=r" (tmp) : ); + tmp |= 0x6Fu; // Enable Return stack, Dynamic branch prediction, Static branch prediction, + // Instruction folding, SMP mode: the CPU is taking part in coherency + // and L1 parity checking + __asm__ __volatile__("mcr p15, 0, %0, c1, c0, 1" : : "r" (tmp)); + + // Modify Control Register + __asm__ __volatile__("mrc p15, 0, %0, c1, c0, 0" : "=r" (tmp) : ); + tmp |= 0xC03805u; // Enable MMU, D-Cache, Program flow prediction, + // I-Cache, high exception vectors, Unaligned data access, + // subpage AP bits disabled + __asm__ __volatile__("mcr p15, 0, %0, c1, c0, 0" : : "r" (tmp)); + + // Invalidate all caches + Data Synchronization Barrier + __asm__ __volatile__("mcr p15, 0, %0, c7, c7, 0\n\t" + "mcr p15, 0, %0, c7, c5, 4\n\t" + "mcr p15, 0, %0, c7, c10, 4" : : "r" (0u)); +} diff --git a/source/arm11/hardware/pxi.c b/source/arm11/hardware/pxi.c new file mode 100644 index 0000000..12e7d9e --- /dev/null +++ b/source/arm11/hardware/pxi.c @@ -0,0 +1,116 @@ +/* + * 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 . + */ + +#include "types.h" +#include "hardware/pxi.h" +#include "arm11/hardware/interrupt.h" +#include "hardware/gfx.h" +#include "arm11/main.h" +#include "arm11/power.h" + + + +static void pxiIrqHandler(UNUSED u32 intSource); + +void PXI_init(void) +{ + REG_PXI_SYNC11 = PXI_IRQ_ENABLE; + REG_PXI_CNT11 = PXI_FLUSH_SEND_FIFO | PXI_EMPTY_FULL_ERROR | PXI_ENABLE_SEND_RECV_FIFO; + + while((REG_PXI_SYNC11 & 0xFFu) != 9u); + REG_PXI_SYNC11 |= 11u<<8; + + IRQ_registerHandler(IRQ_PXI_SYNC, 13, 0, true, pxiIrqHandler); +} + +static void pxiIrqHandler(UNUSED u32 intSource) +{ + u32 cmdCode = PXI_recvWord(); + + switch(cmdCode) + { + case PXI_CMD_ENABLE_LCDS: + GFX_init(); + PXI_sendWord(PXI_RPL_OK); + break; + case PXI_CMD_SET_BRIGHTNESS: + cmdCode = PXI_recvWord(); + GFX_setBrightness(cmdCode); + break; + case PXI_CMD_ALLOW_POWER_OFF: + g_poweroffAllowed = true; + break; + case PXI_CMD_FORBID_POWER_OFF: + g_poweroffAllowed = false; + break; + case PXI_CMD_POWER_OFF: + power_off(); + break; + case PXI_CMD_REBOOT: + power_reboot(); + break; + case PXI_CMD_FIRM_LAUNCH: + g_startFirmLaunch = true; + break; + default: ; + } +} + +void PXI_sendWord(u32 val) +{ + while(REG_PXI_CNT11 & PXI_SEND_FIFO_FULL); + REG_PXI_SEND11 = val; + REG_PXI_SYNC11 |= PXI_NOTIFY_9; +} + +bool PXI_trySendWord(u32 val) +{ + if(REG_PXI_CNT11 & PXI_SEND_FIFO_FULL) + return false; + REG_PXI_SEND11 = val; + REG_PXI_SYNC11 |= PXI_NOTIFY_9; + return true; +} + +u32 PXI_recvWord(void) +{ + while(REG_PXI_CNT11 & PXI_RECV_FIFO_EMPTY); + return REG_PXI_RECV11; +} + +u32 PXI_tryRecvWord(bool *success) +{ + if(REG_PXI_CNT11 & PXI_RECV_FIFO_EMPTY) + { + *success = false; + return 0; + } + + *success = true; + return REG_PXI_RECV11; +} + +void PXI_sendBuf(const u32 *const buf, u32 size) +{ + while(REG_PXI_CNT11 & PXI_SEND_FIFO_FULL); + for(u32 i = 0; i < size / 4; i++) + { + REG_PXI_SEND11 = buf[i]; + } + REG_PXI_SYNC11 |= PXI_NOTIFY_9; +} diff --git a/source/arm11/hardware/timer.c b/source/arm11/hardware/timer.c new file mode 100644 index 0000000..9f330a9 --- /dev/null +++ b/source/arm11/hardware/timer.c @@ -0,0 +1,64 @@ +/* + * 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 . + */ + +#include "types.h" +#include "mem_map.h" +#include "arm11/hardware/timer.h" +#include "arm11/hardware/interrupt.h" + +#define TIMER_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x600) +#define REG_TIMER_LOAD *((vu32*)(TIMER_REGS_BASE + 0x00)) +#define REG_TIMER_COUNTER *((vu32*)(TIMER_REGS_BASE + 0x04)) +#define REG_TIMER_CNT *((vu32*)(TIMER_REGS_BASE + 0x08)) +#define REG_TIMER_INT_STAT *((vu32*)(TIMER_REGS_BASE + 0x0C)) + + + +void TIMER_init(void) +{ + REG_TIMER_CNT = 0; + REG_TIMER_INT_STAT = 1; + + IRQ_registerHandler(IRQ_TIMER, 12, 0, true, NULL); +} + +void TIMER_start(u8 prescaler, u32 ticks, bool autoReload, bool enableIrq) +{ + REG_TIMER_LOAD = ticks; + REG_TIMER_CNT = prescaler<<8 | (enableIrq ? TIMER_IRQ_ENABLE : 0) | + (autoReload ? TIMER_AUTO_RELOAD : TIMER_SINGLE_SHOT) | TIMER_ENABLE; +} + +void TIMER_stop(void) +{ + REG_TIMER_CNT = 0; + REG_TIMER_INT_STAT = 1; +} + +void TIMER_sleepTicks(u32 ticks) +{ + REG_TIMER_LOAD = ticks; + REG_TIMER_CNT = 0u<<8 | TIMER_IRQ_ENABLE | TIMER_SINGLE_SHOT | TIMER_ENABLE; + + while(REG_TIMER_COUNTER) + { + waitForEvent(); + } + + REG_TIMER_INT_STAT = 1; +} diff --git a/source/arm11/hid.c b/source/arm11/hid.c deleted file mode 100644 index a38fdbf..0000000 --- a/source/arm11/hid.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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 . - */ - -/* - * Based on code from https://github.com/smealum/ctrulib - */ - -#include "types.h" -#include "mem_map.h" -#include "arm11/hid.h" -#include "arm11/i2c.h" -#include "arm11/interrupt.h" -#include "arm11/gpio.h" - - -#define REG_HID_PAD (*((vu16*)(IO_MEM_ARM9_ARM11 + 0x46000)) ^ 0xFFFFu) - - -static u32 kHeld, kDown, kUp, homeShellState, powerWifiState; - - - -static void hidIrqHandler(UNUSED u32 intSource); - -void hidInit(void) -{ - IRQ_registerHandler(IRQ_MCU_HID, 14, 0, true, hidIrqHandler); - GPIO_setBit(19, 9); // This enables the MCU HID IRQ -} - -static void hidIrqHandler(UNUSED u32 intSource) -{ - const u32 state = (u32)i2cmcu_readreg_hid_irq(); - - powerWifiState |= state & 3; - powerWifiState |= state>>2 & 4; - - homeShellState |= (state & 4)<<19; - homeShellState |= (state & 0x20)<<17; - - if(homeShellState & KEY_HOME) homeShellState ^= (state & 8)<<18; - if(homeShellState & KEY_SHELL) homeShellState ^= (state & 0x40)<<16; -} - -u32 hidGetPowerButton(void) -{ - u32 tmp = powerWifiState; - powerWifiState &= ~3; - return tmp & 3; -} - -u32 hidGetWifiButton(void) -{ - u32 tmp = powerWifiState; - powerWifiState &= ~4; - return tmp>>2; -} - -void hidScanInput(void) -{ - u32 kOld = kHeld; - kHeld = homeShellState | REG_HID_PAD; - kDown = (~kOld) & kHeld; - kUp = kOld & (~kHeld); -} - -u32 hidKeysHeld(void) -{ - return kHeld; -} - -u32 hidKeysDown(void) -{ - return kDown; -} - -u32 hidKeysUp(void) -{ - return kUp; -} diff --git a/source/arm11/i2c.c b/source/arm11/i2c.c deleted file mode 100644 index d4a4741..0000000 --- a/source/arm11/i2c.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * 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 . - */ - -#include "types.h" -#include "mem_map.h" -#include "arm11/i2c.h" -#include "arm11/interrupt.h" - - -#define I2C1_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x61000) -#define REG_I2C1_DATA *((vu8* )(I2C1_REGS_BASE + 0x00)) -#define REG_I2C1_CNT *((vu8* )(I2C1_REGS_BASE + 0x01)) -#define REG_I2C1_CNTEX *((vu16*)(I2C1_REGS_BASE + 0x02)) -#define REG_I2C1_SCL *((vu16*)(I2C1_REGS_BASE + 0x04)) - -#define I2C2_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x44000) -#define REG_I2C2_DATA *((vu8* )(I2C2_REGS_BASE + 0x00)) -#define REG_I2C2_CNT *((vu8* )(I2C2_REGS_BASE + 0x01)) -#define REG_I2C2_CNTEX *((vu16*)(I2C2_REGS_BASE + 0x02)) -#define REG_I2C2_SCL *((vu16*)(I2C2_REGS_BASE + 0x04)) - -#define I2C3_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x48000) -#define REG_I2C3_DATA *((vu8* )(I2C3_REGS_BASE + 0x00)) -#define REG_I2C3_CNT *((vu8* )(I2C3_REGS_BASE + 0x01)) -#define REG_I2C3_CNTEX *((vu16*)(I2C3_REGS_BASE + 0x02)) -#define REG_I2C3_SCL *((vu16*)(I2C3_REGS_BASE + 0x04)) - - -static const struct -{ - u8 busId; - u8 devAddr; -} i2cDevTable[] = -{ - {0, 0x4A}, - {0, 0x7A}, - {0, 0x78}, - {1, 0x4A}, - {1, 0x78}, - {1, 0x2C}, - {1, 0x2E}, - {1, 0x40}, - {1, 0x44}, - {2, 0xA6}, // TODO: Find out if 0xA6 or 0xD6 is correct - {2, 0xD0}, - {2, 0xD2}, - {2, 0xA4}, - {2, 0x9A}, - {2, 0xA0}, - {1, 0xEE}, - {0, 0x40}, - {2, 0x54} -}; - - - -static void i2cWaitBusy(vu8 *cntReg) -{ - while(*cntReg & I2C_ENABLE); -} - -static vu8* i2cGetBusRegsBase(u8 busId) -{ - vu8 *base; - if(!busId) base = (vu8*)I2C1_REGS_BASE; - else if(busId == 1) base = (vu8*)I2C2_REGS_BASE; - else base = (vu8*)I2C3_REGS_BASE; - - return base; -} - -static bool i2cStartTransfer(I2cDevice devId, u8 regAddr, bool read, vu8 *regsBase) -{ - const u8 devAddr = i2cDevTable[devId].devAddr; - vu8 *const i2cData = regsBase; - vu8 *const i2cCnt = regsBase + 1; - - - u32 i = 0; - for(; i < 8; i++) - { - i2cWaitBusy(i2cCnt); - - // Select device and start. - *i2cData = devAddr; - *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; - i2cWaitBusy(i2cCnt); - if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. - { - *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; - continue; - } - - // Select register and change direction to write. - *i2cData = regAddr; - *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; - i2cWaitBusy(i2cCnt); - if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. - { - *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; - continue; - } - - // Select device in read mode for read transfer. - if(read) - { - *i2cData = devAddr | 1u; // Set bit 0 for read. - *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_START; - i2cWaitBusy(i2cCnt); - if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. - { - *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; - continue; - } - } - - break; - } - - if(i < 8) return true; - else return false; -} - -void I2C_init(void) -{ - i2cWaitBusy(i2cGetBusRegsBase(0)); - REG_I2C1_CNTEX = 2; // ? - REG_I2C1_SCL = 1280; // ? - - i2cWaitBusy(i2cGetBusRegsBase(1)); - REG_I2C2_CNTEX = 2; // ? - REG_I2C2_SCL = 1280; // ? - - i2cWaitBusy(i2cGetBusRegsBase(2)); - REG_I2C3_CNTEX = 2; // ? - REG_I2C3_SCL = 1280; // ? -} - -bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size) -{ - enterCriticalSection(); // TODO: Instead of blocking other interrupts we need locks. - const u8 busId = i2cDevTable[devId].busId; - vu8 *const i2cData = i2cGetBusRegsBase(busId); - vu8 *const i2cCnt = i2cData + 1; - - - if(!i2cStartTransfer(devId, regAddr, true, i2cData)) - { - leaveCriticalSection(); - return false; - } - - while(--size) - { - *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_ACK; - i2cWaitBusy(i2cCnt); - *out++ = *i2cData; - } - - *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_READ | I2C_STOP; - i2cWaitBusy(i2cCnt); - *out = *i2cData; // Last byte - - leaveCriticalSection(); - return true; -} - -bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size) -{ - enterCriticalSection(); // TODO: Instead of blocking other interrupts we need locks. - const u8 busId = i2cDevTable[devId].busId; - vu8 *const i2cData = i2cGetBusRegsBase(busId); - vu8 *const i2cCnt = i2cData + 1; - - - if(!i2cStartTransfer(devId, regAddr, false, i2cData)) - { - leaveCriticalSection(); - return false; - } - - while(--size) - { - *i2cData = *in++; - *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE; - i2cWaitBusy(i2cCnt); - if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. - { - *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; - leaveCriticalSection(); - return false; - } - } - - *i2cData = *in; - *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_DIRE_WRITE | I2C_STOP; - i2cWaitBusy(i2cCnt); - if(!I2C_GET_ACK(*i2cCnt)) // If ack flag is 0 it failed. - { - *i2cCnt = I2C_ENABLE | I2C_IRQ_ENABLE | I2C_ERROR | I2C_STOP; - leaveCriticalSection(); - return false; - } - - leaveCriticalSection(); - return true; -} - -u8 I2C_readReg(I2cDevice devId, u8 regAddr) -{ - u8 data; - if(!I2C_readRegBuf(devId, regAddr, &data, 1)) return 0xFF; - return data; -} - -bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data) -{ - return I2C_writeRegBuf(devId, regAddr, &data, 1); -} - -u8 i2cmcu_readreg_hid_irq(void) -{ - u8 data; - if(!I2C_readRegBuf(I2C_DEV_MCU, 0x10, &data, 1)) return 0; - return data; -} - -u8 i2cmcu_readreg_hid_held(void) -{ - u8 data[19]; - if(!I2C_readRegBuf(I2C_DEV_MCU, 0x7F, data, sizeof(data))) return 0; - return data[18]; -} - -// aka i2cmcu_write_reg0x20_0x22 -bool i2cmcu_lcd_poweron(void) -{ - return I2C_writeReg(I2C_DEV_MCU, 0x22, 2); // bit1 = lcd power enable for both screens -} - -// aka i2cmcu_write_reg0x20_0x22_2 -bool i2cmcu_lcd_backlight_poweron(void) -{ - return I2C_writeReg(I2C_DEV_MCU, 0x22, 0x28); // bit3 = lower screen, bit5 = upper -} - -bool i2cmcu_lcd_poweroff(void) -{ - return I2C_writeReg(I2C_DEV_MCU, 0x22, 1); // bit0 = lcd power disable for both screens (also disabled backlight) -} diff --git a/source/arm11/interrupt.c b/source/arm11/interrupt.c deleted file mode 100644 index 3201a42..0000000 --- a/source/arm11/interrupt.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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 . - */ - -#include "types.h" -#include "mem_map.h" -#include "arm11/interrupt.h" -#include "arm11/start.h" - - -#define REG_CFG11_FIQ_CNT *((vu8* )(IO_MEM_ARM9_ARM11 + 0x40000 + 0x0104)) - -#define CPU_II_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x100) -#define REG_CPU_II_CNT *((vu32*)(CPU_II_REGS_BASE + 0x00)) -#define REG_CPU_II_MASK *((vu32*)(CPU_II_REGS_BASE + 0x04)) -#define REG_CPU_II_BIN_POI *((vu32*)(CPU_II_REGS_BASE + 0x08)) -#define REG_CPU_II_AKN *((vu32*)(CPU_II_REGS_BASE + 0x0C)) -#define REG_CPU_II_EOI *((vu32*)(CPU_II_REGS_BASE + 0x10)) -#define REG_CPU_II_RUN_PRIO *((vu32*)(CPU_II_REGS_BASE + 0x14)) -#define REG_CPU_II_HIGH_PEN *((vu32*)(CPU_II_REGS_BASE + 0x18)) - -#define GID_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x1000) -#define REG_GID_CNT *((vu32*)(GID_REGS_BASE + 0x000)) -#define REG_GID_CONTR_TYPE *((vu32*)(GID_REGS_BASE + 0x004)) -#define REGs_GID_ENA_SET ((vu32*)(GID_REGS_BASE + 0x100)) -#define REGs_GID_ENA_CLR ((vu32*)(GID_REGS_BASE + 0x180)) -#define REGs_GID_PEN_SET ((vu32*)(GID_REGS_BASE + 0x200)) -#define REGs_GID_PEN_CLR ((vu32*)(GID_REGS_BASE + 0x280)) -#define REGs_GID_ACTIVE_BIT ((vu32*)(GID_REGS_BASE + 0x300)) -#define REGs_GID_IPRIO ((vu32*)(GID_REGS_BASE + 0x400)) -#define REGs_GID_ITARG ((vu32*)(GID_REGS_BASE + 0x800)) -#define REGs_GID_ICONF ((vu32*)(GID_REGS_BASE + 0xC00)) -#define REGs_GID_LINE_LEV ((vu32*)(GID_REGS_BASE + 0xD00)) -#define REG_GID_SW_INT *((vu32*)(GID_REGS_BASE + 0xF00)) -#define REG_GID_PERI_INFO0 *((vu32*)(GID_REGS_BASE + 0xFE0)) -#define REG_GID_PERI_INFO1 *((vu32*)(GID_REGS_BASE + 0xFE4)) -#define REG_GID_PERI_INFO2 *((vu32*)(GID_REGS_BASE + 0xFE8)) -#define REG_GID_PERI_INFO3 *((vu32*)(GID_REGS_BASE + 0xFEC)) -#define REG_GID_PRIME_CELL0 *((vu32*)(GID_REGS_BASE + 0xFF0)) -#define REG_GID_PRIME_CELL1 *((vu32*)(GID_REGS_BASE + 0xFF4)) -#define REG_GID_PRIME_CELL2 *((vu32*)(GID_REGS_BASE + 0xFF8)) -#define REG_GID_PRIME_CELL3 *((vu32*)(GID_REGS_BASE + 0xFFC)) - - -IrqHandler privIrqHandlerTable[4][32] = {0}; // Table for private MPCore interrupts -IrqHandler irqHandlerTable[96] = {0}; // There are 96 external interrupts (total 128) - - - -void IRQ_init(void) -{ - // Disable the interrupt interface for this CPU - REG_CPU_II_CNT = 0; - - - if(!getCpuId()) - { - // Disable the global interrupt distributor - REG_GID_CNT = 0; - - // Disable all 128 interrupts - REGs_GID_ENA_CLR[0] = 0xFFFFFFFFu; // Interrupts 0-15 cant be disabled - REGs_GID_ENA_CLR[1] = 0xFFFFFFFFu; - REGs_GID_ENA_CLR[2] = 0xFFFFFFFFu; - REGs_GID_ENA_CLR[3] = 0xFFFFFFFFu; - - // Set all pending interrupts to inactive state - REGs_GID_PEN_CLR[0] = 0xFFFFFFFFu; // Interrupt 0-15 can't be set to inactive apparently - REGs_GID_PEN_CLR[1] = 0xFFFFFFFFu; - REGs_GID_PEN_CLR[2] = 0xFFFFFFFFu; - REGs_GID_PEN_CLR[3] = 0xFFFFFFFFu; - - // Set all 128 interrupts to lowest priority - for(u32 i = 0; i < 32; i++) REGs_GID_IPRIO[i] = 0xE0E0E0E0u; - - // Set all 128 interrupts to target no CPU. - // Interrupt 0-31 can't be changed - for(u32 i = 8; i < 32; i++) REGs_GID_ITARG[i] = 0; - - // Set all interrupts to rising edge sensitive and 1-N software model - for(u32 i = 0; i < 8; i++) REGs_GID_ICONF[i] = 0xFFFFFFFFu; - - // Enable the global interrupt distributor - REG_GID_CNT = 1; - } - else - { - REGs_GID_PEN_CLR[0] = 0xFFFFFFFFu; - - for(u32 i = 0; i < 8; i++) REGs_GID_IPRIO[i] = 0xE0E0E0E0u; - - REGs_GID_ICONF[0] = 0xFFFFFFFFu; - REGs_GID_ICONF[1] = 0xFFFFFFFFu; - } - - - // Mask no interrupt - REG_CPU_II_MASK = 0xF0; - // All priority bits are compared for pre-emption - REG_CPU_II_BIN_POI = 3; - // Enable the interrupt interface for this CPU - REG_CPU_II_CNT = 1; - - // Get rid of all interrupts stuck in pending/active state - u32 tmp; - do - { - tmp = REG_CPU_II_AKN; // Aknowledge - REG_CPU_II_EOI = tmp; // End of interrupt - } while(tmp != 1023); - - leaveCriticalSection(); // Enables interrupts -} - -void IRQ_registerHandler(Interrupt id, u8 prio, u8 cpuMask, bool edgeTriggered, IrqHandler handler) -{ - enterCriticalSection(); - - const u32 cpuId = getCpuId(); - - if(!cpuMask) cpuMask = 1u<>2] & ~(0xFu<>2] = tmp | (u32)prio<>2] & ~(0xFu<>2] = tmp | (u32)cpuMask<>4] & ~(1u<>4] = tmp | (u32)edgeTriggered<>5] = 1u<<(id % 32); - - leaveCriticalSection(); -} - -void IRQ_unregisterHandler(Interrupt id) -{ - enterCriticalSection(); - - REGs_GID_ENA_CLR[id>>5] = 1u<<(id % 32); - - if(id < 32) privIrqHandlerTable[getCpuId()][id] = (IrqHandler)NULL; - else irqHandlerTable[id - 32] = (IrqHandler)NULL; - - leaveCriticalSection(); -} - -void IRQ_setPriority(Interrupt id, u8 prio) -{ - enterCriticalSection(); - - u32 shift = (id % 4 * 8) + 4; - u32 tmp = REGs_GID_IPRIO[id>>2] & ~(0xFu<>2] = tmp | (u32)prio<. - */ - -#include "types.h" -#include "mem_map.h" -#include "arm11/start.h" -#include "arm11/interrupt.h" - - -#define SCU_REGS_BASE (MPCORE_PRIV_REG_BASE) -#define REG_SCU_CNT *((vu32*)(SCU_REGS_BASE + 0x00)) -#define REG_SCU_CONFIG *((vu32*)(SCU_REGS_BASE + 0x04)) -#define REG_SCU_CPU_STAT *((vu32*)(SCU_REGS_BASE + 0x08)) -#define REG_SCU_INVAL_TAG *((vu32*)(SCU_REGS_BASE + 0x0C)) - - - -// Mem permissions -#define PERM_NO_ACC (0b000000u) -#define PERM_PRIV_RW_USR_NO_ACC (0b000001u) -#define PERM_PRIV_RW_USR_RO (0b000010u) -#define PERM_PRIV_RW_USR_RW (0b000011u) -#define PERM_PRIV_RO_USR_NO_ACC (0b100001u) -#define PERM_PRIV_RO_USR_RO (0b100010u) - -// Predefined mem attributes. Only bits 0, 1 and 10-12 matter -#define ATTR_STRONGLY_ORDERED (0b0000000000000u) // Always shared -#define ATTR_SHARED_DEVICE (0b0000000000001u) // Always shared -#define ATTR_NORM_WRITE_TROUGH_NO_ALLOC (0b0000000000010u) -#define ATTR_NORM_WRITE_BACK_NO_ALLOC (0b0000000000011u) -#define ATTR_NORM_NONCACHABLE (0b0010000000000u) -#define ATTR_NORM_WRITE_BACK_ALLOC (0b0010000000011u) -#define ATTR_NONSHARED_DEVICE (0b0100000000000u) // Always non-shared - -// Policies for custom normal mem attributes -#define POLICY_NONCACHABLE_UNBUFFERED (0b00u) -#define POLICY_WRITE_BACK_ALLOC_BUFFERED (0b01u) -#define POLICY_WRITE_THROUGH_NO_ALLOC_BUFFERED (0b10u) // Behaves as noncacheable on ARM11 MPCore -#define POLICY_WRITE_BACK_NO_ALLOC_BUFFERED (0b11u) - -#define MAKE_CUSTOM_NORM_ATTR(outer, inner) ((1u<<12) | (outer<<10) | (inner)) - -// Converts the attribute bits from L1 format to L2 format -#define L1_TO_L2(attr) ((attr>>6 | attr) & 0x73) - - - -/** - * @brief Maps up to 4096 1 MB sections of memory. - * - * @param[in] va The virtual address base. Must be aligned to 1 MB. - * @param[in] pa The physical address base. Must be aligned to 1 MB. - * @param[in] num The number of sections to map. - * @param[in] shared If the sections are shared memory. - * @param[in] access The access permission bits. - * @param[in] domain One of the 16 possible domains. - * @param[in] xn If this memory should be marked as execute never. - * @param[in] attr Other attribute bits like caching. - */ -static void mmuMapSections(u32 va, u32 pa, u32 num, bool shared, u32 access, u8 domain, bool xn, u32 attr) -{ - for(u32 i = 0; i < 0x100000u * num; i += 0x100000u) - { - ((u32*)A11_MMU_TABLES_BASE)[(va + i)>>20] = (((pa + i) & 0xFFF00000u) | (u32)shared<<16 | access<<10 | - (u32)domain<<5 | (u32)xn<<4 | attr<<2 | 0b10u); - } -} - -/** - * @brief Maps up to 256 4 KB pages of memory. - * @brief The mapped range must not cross the next section. - * - * @param[in] va The virtual address base. Must be aligned to 4 KB. - * @param[in] pa The physical address base. Must be aligned to 4 KB. - * @param[in] num The number of pages to map. Must be <= 128. - * @param l2Table The L2 MMU table address base for this mapping. - * @param[in] shared If the pages are shared memory. - * @param[in] access The access permission bits. - * @param[in] domain One of the 16 possible domains. - * @param[in] xn If this memory should be marked as execute never. - * @param[in] attr Other attribute bits like caching. - */ -static void mmuMapPages(u32 va, u32 pa, u32 num, u32 *l2Table, bool shared, u32 access, u8 domain, bool xn, u32 attr) -{ - ((u32*)A11_MMU_TABLES_BASE)[va>>20] = (((u32)l2Table & 0xFFFFFC00u) | (u32)domain<<5 | 0b01u); - - for(u32 i = 0; i < 0x1000u * num; i += 0x1000u) - { - l2Table[(va + i)>>12 & 0xFFu] = (((pa + i) & 0xFFFFF000u) | (u32)shared<<10 | - access<<4 | attr<<2 | 0b10u | (u32)xn); - } -} - -void setupMmu(void) -{ - // TTBR0 address shared page table walk and outer cachable write-through, no allocate on write - __asm__ __volatile__("mcr p15, 0, %0, c2, c0, 0" : : "r" (A11_MMU_TABLES_BASE | 0x12u)); - // Use the 16 KB L1 table only - __asm__ __volatile__("mcr p15, 0, %0, c2, c0, 2" : : "r" (0u)); - // Domain 1 = client, remaining domains all = no access - __asm__ __volatile__("mcr p15, 0, %0, c3, c0, 0" : : "r" (4u)); - // Context ID Register (ASID = 0, PROCID = 0) - __asm__ __volatile__("mcr p15, 0, %0, c13, c0, 1" : : "r" (0u)); - - - static volatile bool syncFlag = false; - if(!getCpuId()) - { - // Clear L1 and L2 tables - clearMem((u32*)A11_MMU_TABLES_BASE, 0x4C00u); - - // IO mem mapping - mmuMapSections(IO_MEM_ARM9_ARM11, IO_MEM_ARM9_ARM11, 4, true, - PERM_PRIV_RW_USR_NO_ACC, 1, true, ATTR_SHARED_DEVICE); - - // MPCore private region mapping - mmuMapPages(MPCORE_PRIV_REG_BASE, MPCORE_PRIV_REG_BASE, 2, - (u32*)(A11_MMU_TABLES_BASE + 0x4000u), false, PERM_PRIV_RW_USR_NO_ACC, - 1, true, L1_TO_L2(ATTR_NONSHARED_DEVICE)); - - // VRAM mapping - mmuMapSections(VRAM_BASE, VRAM_BASE, 6, true, PERM_PRIV_RW_USR_NO_ACC, 1, true, ATTR_NORM_WRITE_TROUGH_NO_ALLOC); - - // DSP mem mapping to extend AXIWRAM - mmuMapPages(AXIWRAM_BASE + AXIWRAM_SIZE, DSP_MEM_BASE, 128, (u32*)(A11_MMU_TABLES_BASE + 0x4400u), true, - PERM_PRIV_RW_USR_NO_ACC, 1, true, - L1_TO_L2(MAKE_CUSTOM_NORM_ATTR(POLICY_WRITE_BACK_ALLOC_BUFFERED, POLICY_WRITE_BACK_ALLOC_BUFFERED))); - - // AXIWRAM MMU table mapping - mmuMapPages(A11_MMU_TABLES_BASE, A11_MMU_TABLES_BASE, 5, (u32*)(A11_MMU_TABLES_BASE + 0x4400u), true, - PERM_PRIV_RO_USR_NO_ACC, 1, true, L1_TO_L2(ATTR_NORM_NONCACHABLE)); - - // Remaining AXIWRAM pages - mmuMapPages(AXIWRAM_BASE + 0x5000u, AXIWRAM_BASE + 0x5000u, 123, - (u32*)(A11_MMU_TABLES_BASE + 0x4400u), true, PERM_PRIV_RW_USR_NO_ACC, 1, false, - L1_TO_L2(MAKE_CUSTOM_NORM_ATTR(POLICY_WRITE_BACK_ALLOC_BUFFERED, POLICY_WRITE_BACK_ALLOC_BUFFERED))); - - extern u32 __start__[]; - - // Map fastboot executable start to boot11 mirror (exception vectors) - mmuMapPages(BOOT11_MIRROR2, (u32)__start__, 1, (u32*)(A11_MMU_TABLES_BASE + 0x4800u), true, - PERM_PRIV_RO_USR_NO_ACC, 1, false, - L1_TO_L2(MAKE_CUSTOM_NORM_ATTR(POLICY_WRITE_BACK_ALLOC_BUFFERED, POLICY_WRITE_BACK_ALLOC_BUFFERED))); - - // Invalidate tag RAMs before enabling SMP as recommended by the MPCore doc. - REG_SCU_CNT = 0x1FFE; // Disable SCU and parity checking. Access to all CPUs interfaces. - REG_SCU_INVAL_TAG = 0xFFFF; // Invalidate SCU tag RAMs of all CPUs. - REG_SCU_CNT |= 0x2001u; // Enable SCU and parity checking. - - syncFlag = true; - signalEvent(); - } - else while(!syncFlag) waitForEvent(); - - - // Invalidate TLB (Unified TLB operation) + Data Synchronization Barrier - __asm__ __volatile__("mcr p15, 0, %0, c8, c7, 0\n\t" - "mcr p15, 0, %0, c7, c10, 4" : : "r" (0u)); - - - u32 tmp; - // Modify Auxiliary Control Register - __asm__ __volatile__("mrc p15, 0, %0, c1, c0, 1" : "=r" (tmp) : ); - tmp |= 0x6Fu; // Enable Return stack, Dynamic branch prediction, Static branch prediction, - // Instruction folding, SMP mode: the CPU is taking part in coherency - // and L1 parity checking - __asm__ __volatile__("mcr p15, 0, %0, c1, c0, 1" : : "r" (tmp)); - - // Modify Control Register - __asm__ __volatile__("mrc p15, 0, %0, c1, c0, 0" : "=r" (tmp) : ); - tmp |= 0xC03805u; // Enable MMU, D-Cache, Program flow prediction, - // I-Cache, high exception vectors, Unaligned data access, - // subpage AP bits disabled - __asm__ __volatile__("mcr p15, 0, %0, c1, c0, 0" : : "r" (tmp)); - - // Invalidate all caches + Data Synchronization Barrier - __asm__ __volatile__("mcr p15, 0, %0, c7, c7, 0\n\t" - "mcr p15, 0, %0, c7, c5, 4\n\t" - "mcr p15, 0, %0, c7, c10, 4" : : "r" (0u)); -} diff --git a/source/arm11/power.c b/source/arm11/power.c index 899bdf4..a4f01a9 100644 --- a/source/arm11/power.c +++ b/source/arm11/power.c @@ -18,9 +18,9 @@ #include "types.h" #include "util.h" -#include "arm11/i2c.h" -#include "cache.h" -#include "arm11/interrupt.h" +#include "arm11/hardware/i2c.h" +#include "hardware/cache.h" +#include "arm11/hardware/interrupt.h" diff --git a/source/arm11/pxi.c b/source/arm11/pxi.c deleted file mode 100644 index f58d0cc..0000000 --- a/source/arm11/pxi.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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 . - */ - -#include "types.h" -#include "pxi.h" -#include "arm11/interrupt.h" -#include "gfx.h" -#include "arm11/main.h" -#include "arm11/power.h" - - - -static void pxiIrqHandler(UNUSED u32 intSource); - -void PXI_init(void) -{ - REG_PXI_SYNC11 = PXI_IRQ_ENABLE; - REG_PXI_CNT11 = PXI_FLUSH_SEND_FIFO | PXI_EMPTY_FULL_ERROR | PXI_ENABLE_SEND_RECV_FIFO; - - while((REG_PXI_SYNC11 & 0xFFu) != 9u); - REG_PXI_SYNC11 |= 11u<<8; - - IRQ_registerHandler(IRQ_PXI_SYNC, 13, 0, true, pxiIrqHandler); -} - -static void pxiIrqHandler(UNUSED u32 intSource) -{ - u32 cmdCode = PXI_recvWord(); - - switch(cmdCode) - { - case PXI_CMD_ENABLE_LCDS: - GFX_init(); - PXI_sendWord(PXI_RPL_OK); - break; - case PXI_CMD_SET_BRIGHTNESS: - cmdCode = PXI_recvWord(); - GFX_setBrightness(cmdCode); - break; - case PXI_CMD_ALLOW_POWER_OFF: - g_poweroffAllowed = true; - break; - case PXI_CMD_FORBID_POWER_OFF: - g_poweroffAllowed = false; - break; - case PXI_CMD_POWER_OFF: - power_off(); - break; - case PXI_CMD_REBOOT: - power_reboot(); - break; - case PXI_CMD_FIRM_LAUNCH: - g_startFirmLaunch = true; - break; - default: ; - } -} - -void PXI_sendWord(u32 val) -{ - while(REG_PXI_CNT11 & PXI_SEND_FIFO_FULL); - REG_PXI_SEND11 = val; - REG_PXI_SYNC11 |= PXI_NOTIFY_9; -} - -bool PXI_trySendWord(u32 val) -{ - if(REG_PXI_CNT11 & PXI_SEND_FIFO_FULL) - return false; - REG_PXI_SEND11 = val; - REG_PXI_SYNC11 |= PXI_NOTIFY_9; - return true; -} - -u32 PXI_recvWord(void) -{ - while(REG_PXI_CNT11 & PXI_RECV_FIFO_EMPTY); - return REG_PXI_RECV11; -} - -u32 PXI_tryRecvWord(bool *success) -{ - if(REG_PXI_CNT11 & PXI_RECV_FIFO_EMPTY) - { - *success = false; - return 0; - } - - *success = true; - return REG_PXI_RECV11; -} - -void PXI_sendBuf(const u32 *const buf, u32 size) -{ - while(REG_PXI_CNT11 & PXI_SEND_FIFO_FULL); - for(u32 i = 0; i < size / 4; i++) - { - REG_PXI_SEND11 = buf[i]; - } - REG_PXI_SYNC11 |= PXI_NOTIFY_9; -} diff --git a/source/arm11/timer.c b/source/arm11/timer.c deleted file mode 100644 index 3518d4a..0000000 --- a/source/arm11/timer.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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 . - */ - -#include "types.h" -#include "mem_map.h" -#include "arm11/timer.h" -#include "arm11/interrupt.h" - -#define TIMER_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x600) -#define REG_TIMER_LOAD *((vu32*)(TIMER_REGS_BASE + 0x00)) -#define REG_TIMER_COUNTER *((vu32*)(TIMER_REGS_BASE + 0x04)) -#define REG_TIMER_CNT *((vu32*)(TIMER_REGS_BASE + 0x08)) -#define REG_TIMER_INT_STAT *((vu32*)(TIMER_REGS_BASE + 0x0C)) - - - -void TIMER_init(void) -{ - REG_TIMER_CNT = 0; - REG_TIMER_INT_STAT = 1; - - IRQ_registerHandler(IRQ_TIMER, 12, 0, true, NULL); -} - -void TIMER_start(u8 prescaler, u32 ticks, bool autoReload, bool enableIrq) -{ - REG_TIMER_LOAD = ticks; - REG_TIMER_CNT = prescaler<<8 | (enableIrq ? TIMER_IRQ_ENABLE : 0) | - (autoReload ? TIMER_AUTO_RELOAD : TIMER_SINGLE_SHOT) | TIMER_ENABLE; -} - -void TIMER_stop(void) -{ - REG_TIMER_CNT = 0; - REG_TIMER_INT_STAT = 1; -} - -void TIMER_sleepTicks(u32 ticks) -{ - REG_TIMER_LOAD = ticks; - REG_TIMER_CNT = 0u<<8 | TIMER_IRQ_ENABLE | TIMER_SINGLE_SHOT | TIMER_ENABLE; - - while(REG_TIMER_COUNTER) - { - waitForEvent(); - } - - REG_TIMER_INT_STAT = 1; -} diff --git a/source/arm9/cache.s b/source/arm9/cache.s deleted file mode 100644 index 594cfdf..0000000 --- a/source/arm9/cache.s +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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 . - */ - -#include "asmfunc.h" - -.arm -.cpu arm946e-s -.fpu softvfp - - -#define ICACHE_SIZE (0x2000) -#define DCACHE_SIZE (0x1000) -#define CACHE_LINE_SIZE (32) - - - -ASM_FUNC invalidateICache - mov r0, #0 - mcr p15, 0, r0, c7, c5, 0 @ "Flush instruction cache" - bx lr - - -ASM_FUNC invalidateICacheRange - add r1, r1, r0 - bic r0, r0, #(CACHE_LINE_SIZE - 1) - invalidateICacheRange_lp: - mcr p15, 0, r0, c7, c5, 1 @ "Flush instruction cache single entry Address" - add r0, r0, #CACHE_LINE_SIZE - cmp r0, r1 - blt invalidateICacheRange_lp - bx lr - - -ASM_FUNC flushDCache - mov r1, #0 - flushDCache_outer_lp: - mov r0, #0 - flushDCache_inner_lp: - orr r2, r1, r0 @ Generate segment and line address - mcr p15, 0, r2, c7, c10, 2 @ "Clean data cache entry Index and segment" - add r0, r0, #CACHE_LINE_SIZE - cmp r0, #(DCACHE_SIZE / 4) - bne flushDCache_inner_lp - add r1, r1, #0x40000000 - cmp r1, #0 - bne flushDCache_outer_lp - b drainWriteBufferFlushInvalidate - - -ASM_FUNC flushInvalidateDCache - mov r1, #0 - flushInvalidateDCache_outer_lp: - mov r0, #0 - flushInvalidateDCache_inner_lp: - orr r2, r1, r0 @ Generate segment and line address - mcr p15, 0, r2, c7, c14, 2 @ "Clean and flush data cache entry Index and segment" - add r0, r0, #CACHE_LINE_SIZE - cmp r0, #(DCACHE_SIZE / 4) - bne flushInvalidateDCache_inner_lp - add r1, r1, #0x40000000 - cmp r1, #0 - bne flushInvalidateDCache_outer_lp -drainWriteBufferFlushInvalidate: - mcr p15, 0, r1, c7, c10, 4 @ Drain write buffer - bx lr - - -ASM_FUNC flushDCacheRange - add r1, r1, r0 - bic r0, r0, #(CACHE_LINE_SIZE - 1) - flushDCacheRange_lp: - mcr p15, 0, r0, c7, c10, 1 @ "Clean data cache entry Address" - add r0, r0, #CACHE_LINE_SIZE - cmp r0, r1 - blt flushDCacheRange_lp - b drainWriteBufferFlushInvalidateRange - - -ASM_FUNC flushInvalidateDCacheRange - add r1, r1, r0 - bic r0, r0, #(CACHE_LINE_SIZE - 1) - flushInvalidateDCacheRange_lp: - mcr p15, 0, r0, c7, c14, 1 @ "Clean and flush data cache entry Address" - add r0, r0, #CACHE_LINE_SIZE - cmp r0, r1 - blt flushInvalidateDCacheRange_lp -drainWriteBufferFlushInvalidateRange: - mov r0, #0 - mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer - bx lr - - -ASM_FUNC invalidateDCache - mov r0, #0 - mcr p15, 0, r0, c7, c6, 0 @ "Flush data cache" - bx lr - - -ASM_FUNC invalidateDCacheRange - add r1, r1, r0 - tst r0, #(CACHE_LINE_SIZE - 1) - mcrne p15, 0, r0, c7, c10, 1 @ "Clean data cache entry Address" - tst r1, #(CACHE_LINE_SIZE - 1) - mcrne p15, 0, r1, c7, c10, 1 @ "Clean data cache entry Address" - bic r0, r0, #(CACHE_LINE_SIZE - 1) - invalidateDCacheRange_lp: - mcr p15, 0, r0, c7, c6, 1 @ "Flush data cache single entry Address" - add r0, r0, #CACHE_LINE_SIZE - cmp r0, r1 - blt invalidateDCacheRange_lp - bx lr diff --git a/source/arm9/config.c b/source/arm9/config.c index 5bfb1ae..d530e21 100644 --- a/source/arm9/config.c +++ b/source/arm9/config.c @@ -29,9 +29,9 @@ #include "arm9/fsutils.h" #include "arm9/console.h" #include "arm9/main.h" -#include "arm9/interrupt.h" +#include "arm9/hardware/interrupt.h" #include "util.h" -#include "arm9/hid.h" +#include "arm9/hardware/hid.h" #include "arm9/debug.h" #include "arm9/gui/ui.h" #include "arm9/config.h" diff --git a/source/arm9/console.c b/source/arm9/console.c index 89a547e..1081328 100644 --- a/source/arm9/console.c +++ b/source/arm9/console.c @@ -6,7 +6,7 @@ #include #include "types.h" #include "arm9/fmt.h" -#include "gfx.h" +#include "hardware/gfx.h" #include "util.h" #include "arm9/console.h" diff --git a/source/arm9/crypto.c b/source/arm9/crypto.c deleted file mode 100644 index bfe8fa0..0000000 --- a/source/arm9/crypto.c +++ /dev/null @@ -1,654 +0,0 @@ -/* - * 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 . - */ - -#include -#include "arm9/fb_assert.h" -#include "mem_map.h" -#include "types.h" -#include "arm9/crypto.h" -#include "arm9/interrupt.h" -#include "arm9/ndma.h" - - - -////////////////////////////////// -// AES // -////////////////////////////////// - -#define AES_REGS_BASE (IO_MEM_ARM9_ONLY + 0x9000) -#define REG_AESCNT *((vu32*)(AES_REGS_BASE + 0x000)) - -#define REG_AESBLKCNT *((vu32*)(AES_REGS_BASE + 0x004)) -#define REG_AES_BLKCNT_LOW *((vu16*)(AES_REGS_BASE + 0x004)) -#define REG_AES_BLKCNT_HIGH *((vu16*)(AES_REGS_BASE + 0x006)) -#define REG_AESWRFIFO ( AES_REGS_BASE + 0x008) -#define REG_AESRDFIFO ( AES_REGS_BASE + 0x00C) -#define REG_AESKEYSEL *((vu8* )(AES_REGS_BASE + 0x010)) -#define REG_AESKEYCNT *((vu8* )(AES_REGS_BASE + 0x011)) -#define REG_AESCTR ((vu32*)(AES_REGS_BASE + 0x020)) -#define REG_AESMAC ((vu32*)(AES_REGS_BASE + 0x030)) - -#define REG_AESKEY0 ((vu32*)(AES_REGS_BASE + 0x040)) -#define REG_AESKEYX0 ((vu32*)(AES_REGS_BASE + 0x050)) -#define REG_AESKEYY0 ((vu32*)(AES_REGS_BASE + 0x060)) -#define REG_AESKEY1 ((vu32*)(AES_REGS_BASE + 0x070)) -#define REG_AESKEYX1 ((vu32*)(AES_REGS_BASE + 0x080)) -#define REG_AESKEYY1 ((vu32*)(AES_REGS_BASE + 0x090)) -#define REG_AESKEY2 ((vu32*)(AES_REGS_BASE + 0x0A0)) -#define REG_AESKEYX2 ((vu32*)(AES_REGS_BASE + 0x0B0)) -#define REG_AESKEYY2 ((vu32*)(AES_REGS_BASE + 0x0C0)) -#define REG_AESKEY3 ((vu32*)(AES_REGS_BASE + 0x0D0)) -#define REG_AESKEYX3 ((vu32*)(AES_REGS_BASE + 0x0E0)) -#define REG_AESKEYY3 ((vu32*)(AES_REGS_BASE + 0x0F0)) - -#define REG_AESKEYFIFO ((vu32*)(AES_REGS_BASE + 0x100)) -#define REG_AESKEYXFIFO ((vu32*)(AES_REGS_BASE + 0x104)) -#define REG_AESKEYYFIFO ((vu32*)(AES_REGS_BASE + 0x108)) - - -/*static void deriveKey(u32 pad[4], u32 boot9Off) -{ - const u32 *pad2 = (u32*)(BOOT9_BASE + boot9Off); - - pad[0] ^= pad2[0]; - pad[1] ^= pad2[1]; - pad[2] ^= pad2[2]; - pad[3] ^= pad2[3]; -}*/ - -static void setupKeys(void) -{ - // Setup TWL unit info and console ID - const bool isDevUnit = CFG_UNITINFO != 0; - const u64 twlConsoleId = (isDevUnit ? (*((vu64*)0x10012000)) : - ((*((vu64*)0x01FFB808) ^ 0x8C267B7B358A6AFULL) | 0x80000000ULL)); - *((vu8*)0x10010014) = CFG_UNITINFO; - *((vu64*)0x10012100) = twlConsoleId; - - - // TWL key init - REG_AESCNT = 0; - REG_AESKEYX1[2] = (u32)(twlConsoleId>>32); - REG_AESKEYX1[3] = (u32)twlConsoleId; - - AES_setKey(0x02, AES_KEY_X, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, (u32*)0x01FFD398); - - u32 key3X[4] = {(u32)twlConsoleId, 0, 0, (u32)(twlConsoleId>>32)}; - if(isDevUnit) - { - key3X[1] = 0xEE7A4B1E; - key3X[2] = 0xAF42C08B; - AES_setKey(0x03, AES_KEY_X, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, key3X); - - alignas(4) static const u8 key2YDev[16] = { - 0x3B, 0x06, 0x86, 0x57, 0x33, 0x04, 0x88, 0x11, 0x49, 0x04, 0x6B, 0x33, 0x12, 0x02, 0xAC, 0xF3}; - alignas(4) static const u8 key3YDev[16] = { - 0xAA, 0xBF, 0x76, 0xF1, 0x7A, 0xB8, 0xE8, 0x66, 0x97, 0x64, 0x6A, 0x26, 0x05, 0x00, 0xA0, 0xE1}; - AES_setKey(0x02, AES_KEY_Y, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, (const u32*)key2YDev); - AES_setKey(0x03, AES_KEY_Y, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, (const u32*)key3YDev); - } - else - { - key3X[1] = 0x544E494E; // "NINT" - key3X[2] = 0x4F444E45; // "ENDO" - AES_setKey(0x03, AES_KEY_X, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, key3X); - - AES_setKey(0x02, AES_KEY_Y, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, (u32*)0x01FFD220); - - u32 key3YRetail[4]; - key3YRetail[0] = ((u32*)0x01FFD3C8)[0]; - key3YRetail[1] = ((u32*)0x01FFD3C8)[1]; - key3YRetail[2] = ((u32*)0x01FFD3C8)[2]; - key3YRetail[3] = 0xE1A00005; - AES_setKey(0x03, AES_KEY_Y, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, key3YRetail); - } - - - // 3DS key init - if(REG_PDN_MPCORE_CFG & 2u) // New 3DS - { - alignas(4) static const u8 keyY0x05[16] = { - 0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE}; - AES_setKey(0x05, AES_KEY_Y, AES_INPUT_BIG | AES_INPUT_NORMAL, false, (const u32*)keyY0x05); - } - - alignas(4) static const u8 keyY0x24[16] = { - 0x74, 0xCA, 0x07, 0x48, 0x84, 0xF4, 0x22, 0x8D, 0xEB, 0x2A, 0x1C, 0xA7, 0x2D, 0x28, 0x77, 0x62}; - AES_setKey(0x24, AES_KEY_Y, AES_INPUT_BIG | AES_INPUT_NORMAL, false, (const u32*)keyY0x24); - - alignas(4) static const u8 keyX0x25s[2][16] = { - {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3}, - {0x81, 0x90, 0x7A, 0x4B, 0x6F, 0x1B, 0x47, 0x32, 0x3A, 0x67, 0x79, 0x74, 0xCE, 0x4A, 0xD7, 0x1B}}; - AES_setKey(0x25, AES_KEY_X, AES_INPUT_BIG | AES_INPUT_NORMAL, false, (const u32*)keyX0x25s[isDevUnit]); - - alignas(4) static const u8 keyY0x2Fs[2][16] = { - {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16}, - {0x73, 0x25, 0xC4, 0xEB, 0x14, 0x3A, 0x0D, 0x5F, 0x5D, 0xB6, 0xE5, 0xC5, 0x7A, 0x21, 0x95, 0xAC}}; - AES_setKey(0x2F, AES_KEY_Y, AES_INPUT_BIG | AES_INPUT_NORMAL, false, (const u32*)keyY0x2Fs[isDevUnit]); - - // Set 0x11 keyslot - alignas(4) static const u8 key1s[2][16] = { - {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8}, - {0xA2, 0xF4, 0x00, 0x3C, 0x7A, 0x95, 0x10, 0x25, 0xDF, 0x4E, 0x9E, 0x74, 0xE3, 0x0C, 0x92, 0x99}}; - alignas(4) static const u8 key2s[2][16] = { - {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0}, - {0xFF, 0x77, 0xA0, 0x9A, 0x99, 0x81, 0xE9, 0x48, 0xEC, 0x51, 0xC9, 0x32, 0x5D, 0x14, 0xEC, 0x25}}; - - - alignas(4) u8 keyBlocks[2][16] = { - {0xA4, 0x8D, 0xE4, 0xF1, 0x0B, 0x36, 0x44, 0xAA, 0x90, 0x31, 0x28, 0xFF, 0x4D, 0xCA, 0x76, 0xDF}, - {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98}}; - u32 decKey[4]; - - AES_ctx ctx; - AES_setCryptParams(&ctx, AES_INPUT_BIG | AES_INPUT_NORMAL, AES_OUTPUT_BIG | AES_OUTPUT_NORMAL); - - // key 0x18 - AES_setKey(0x11, AES_KEY_NORMAL, AES_INPUT_BIG | AES_INPUT_NORMAL, false, (const u32*)key1s[isDevUnit]); - AES_selectKeyslot(0x11); - AES_ecb(&ctx, (const u32*)keyBlocks[0], decKey, 1, false, false); - AES_setKey(0x18, AES_KEY_X, AES_INPUT_BIG | AES_INPUT_NORMAL, false, decKey); - - AES_setKey(0x11, AES_KEY_NORMAL, AES_INPUT_BIG | AES_INPUT_NORMAL, false, (const u32*)key2s[isDevUnit]); - AES_selectKeyslot(0x11); - for(u8 slot = 0x19; slot < 0x20; slot++, keyBlocks[1][0xF]++) - { - AES_ecb(&ctx, (const u32*)keyBlocks[1], decKey, 1, false, false); - AES_setKey(slot, AES_KEY_X, AES_INPUT_BIG | AES_INPUT_NORMAL, false, decKey); - } -} - -void AES_init(void) -{ - REG_AESCNT = AES_MAC_SIZE(4) | AES_FLUSH_WRITE_FIFO | AES_FLUSH_READ_FIFO; - *((vu8*)0x10000008) |= 0xCu; // ?? - - REG_NDMA0_DST_ADDR = REG_AESWRFIFO; - REG_NDMA0_INT_CNT = NDMA_INT_SYS_FREQ; - REG_NDMA0_CNT = NDMA_REPEATING_MODE | NDMA_STARTUP_AES_IN | - NDMA_SRC_UPDATE_INC | NDMA_DST_UPDATE_FIXED; - - REG_NDMA1_SRC_ADDR = REG_AESRDFIFO; - REG_NDMA1_INT_CNT = NDMA_INT_SYS_FREQ; - REG_NDMA1_CNT = NDMA_REPEATING_MODE | NDMA_STARTUP_AES_OUT | - NDMA_SRC_UPDATE_FIXED | NDMA_DST_UPDATE_INC; - - IRQ_registerHandler(IRQ_AES, NULL); - - setupKeys(); -} - -void AES_deinit(void) -{ - REG_AESCNT = AES_MAC_SIZE(4) | AES_FLUSH_WRITE_FIFO | AES_FLUSH_READ_FIFO; -} - -void AES_setKey(u8 keyslot, AesKeyType type, u8 orderEndianess, bool twlScrambler, const u32 key[4]) -{ - fb_assert(keyslot < 0x40); - fb_assert(key != NULL); - - - REG_AESCNT = (u32)orderEndianess<<23; - if(keyslot > 3) - { - REG_AESKEYCNT = 0x80u | (type > AES_KEY_NORMAL && twlScrambler ? 1u : 0u)<<6 | keyslot; - REG_AESKEYFIFO[type] = key[0]; - REG_AESKEYFIFO[type] = key[1]; - REG_AESKEYFIFO[type] = key[2]; - REG_AESKEYFIFO[type] = key[3]; - } - else - { - u32 lastu32; - vu32 *twlKeyNReg = ®_AESKEY0[12u * keyslot + type * 4u]; - if(orderEndianess & AES_INPUT_NORMAL) - { - twlKeyNReg[0] = key[3]; - twlKeyNReg[1] = key[2]; - twlKeyNReg[2] = key[1]; - lastu32 = key[0]; - } - else - { - twlKeyNReg[0] = key[0]; - twlKeyNReg[1] = key[1]; - twlKeyNReg[2] = key[2]; - lastu32 = key[3]; - } - twlKeyNReg[3] = lastu32; - } -} - -void AES_selectKeyslot(u8 keyslot) -{ - fb_assert(keyslot < 0x40); - - REG_AESKEYSEL = keyslot; - REG_AESCNT |= AES_UPDATE_KEYSLOT; -} - -void AES_setNonce(AES_ctx *const ctx, u8 orderEndianess, const u32 nonce[3]) -{ - fb_assert(ctx != NULL); - fb_assert(nonce != NULL); - - - ctx->ctrIvNonceParams = (u32)orderEndianess<<23; - u32 *const ctrIvNonce = ctx->ctrIvNonce; - u32 lastu32; - if(orderEndianess & AES_INPUT_NORMAL) - { - ctrIvNonce[0] = nonce[2]; - ctrIvNonce[1] = nonce[1]; - lastu32 = nonce[0]; - } - else - { - ctrIvNonce[0] = nonce[0]; - ctrIvNonce[1] = nonce[1]; - lastu32 = nonce[2]; - } - ctrIvNonce[2] = lastu32; -} - -void AES_setCtrIv(AES_ctx *const ctx, u8 orderEndianess, const u32 ctrIv[4]) -{ - fb_assert(ctx != NULL); - fb_assert(ctrIv != NULL); - - - ctx->ctrIvNonceParams = (u32)orderEndianess<<23; - u32 *const ctrIvNonce = ctx->ctrIvNonce; - u32 lastu32; - if(orderEndianess & AES_INPUT_NORMAL) - { - ctrIvNonce[0] = ctrIv[3]; - ctrIvNonce[1] = ctrIv[2]; - ctrIvNonce[2] = ctrIv[1]; - lastu32 = ctrIv[0]; - } - else - { - ctrIvNonce[0] = ctrIv[0]; - ctrIvNonce[1] = ctrIv[1]; - ctrIvNonce[2] = ctrIv[2]; - lastu32 = ctrIv[3]; - } - ctrIvNonce[3] = lastu32; -} - -// TODO: Handle endianess! -void AES_addCounter(u32 ctr[4], u32 val) -{ - fb_assert(ctr != NULL); - - u32 carry, i = 1; - u64 sum; - - sum = ctr[0]; - sum += (val >> 4); - carry = sum >> 32; - ctr[0] = sum & 0xFFFFFFFFu; - - while(carry) - { - sum = ctr[i]; - sum += carry; - carry = sum >> 32; - ctr[i] = sum & 0xFFFFFFFFu; - i++; - } -} - -void AES_subCounter(u32 ctr[4], u32 val) -{ - fb_assert(ctr != NULL); - - u32 carry, i = 1; - u32 sum; - - sum = ctr[0] - (val >> 4); - carry = (sum > ctr[0]); - ctr[0] = sum; - - while(carry && i < 4) - { - sum = ctr[i] - carry; - carry = (sum > ctr[i]); - ctr[i] = sum; - i++; - } -} - -void AES_setCryptParams(AES_ctx *const ctx, u8 inEndianessOrder, u8 outEndianessOrder) -{ - fb_assert(ctx != NULL); - - ctx->aesParams = (u32)inEndianessOrder<<23 | (u32)outEndianessOrder<<22; -} - -static void aesProcessBlocksCpu(const u32 *in, u32 *out, u32 blocks) -{ - REG_AES_BLKCNT_HIGH = blocks; - REG_AESCNT |= AES_ENABLE | 3<<12 | AES_FLUSH_READ_FIFO | AES_FLUSH_WRITE_FIFO; - - for(u32 i = 0; i < blocks * 4; i += 4) - { - *((vu32*)REG_AESWRFIFO) = in[0 + i]; - *((vu32*)REG_AESWRFIFO) = in[1 + i]; - *((vu32*)REG_AESWRFIFO) = in[2 + i]; - *((vu32*)REG_AESWRFIFO) = in[3 + i]; - - while(AES_READ_FIFO_COUNT == 0); - - out[0 + i] = *((vu32*)REG_AESRDFIFO); - out[1 + i] = *((vu32*)REG_AESRDFIFO); - out[2 + i] = *((vu32*)REG_AESRDFIFO); - out[3 + i] = *((vu32*)REG_AESRDFIFO); - } -} - -// AES_init() must be called before this works -static void aesProcessBlocksDma(const u32 *in, u32 *out, u32 blocks) -{ - // DMA can't reach TCMs - fb_assert(((u32)in >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)in < DTCM_BASE) || ((u32)in >= DTCM_BASE + DTCM_SIZE))); - fb_assert(((u32)out >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)out < DTCM_BASE) || ((u32)out >= DTCM_BASE + DTCM_SIZE))); - - - // Check block alignment - u32 aesFifoSize, dmaBurstSize; - if(!(blocks & 3) || blocks == AES_MAX_BLOCKS) - { - aesFifoSize = 3; - dmaBurstSize = NDMA_BURST_SIZE(16); - } - else if(!(blocks & 1)) - { - aesFifoSize = 1; - dmaBurstSize = NDMA_BURST_SIZE(8); - } - else - { - aesFifoSize = 0; - dmaBurstSize = NDMA_BURST_SIZE(4); - } - - REG_NDMA0_SRC_ADDR = (u32)in; - REG_NDMA0_LOG_BLK_CNT = aesFifoSize * 4 + 4; - REG_NDMA0_CNT = (REG_NDMA0_CNT & 0xFFF0FFFFu) | NDMA_ENABLE | dmaBurstSize; - - REG_NDMA1_DST_ADDR = (u32)out; - REG_NDMA1_LOG_BLK_CNT = aesFifoSize * 4 + 4; - REG_NDMA1_CNT = (REG_NDMA1_CNT & 0xFFF0FFFFu) | NDMA_ENABLE | dmaBurstSize; - - REG_AES_BLKCNT_HIGH = blocks; - REG_AESCNT |= AES_ENABLE | AES_IRQ_ENABLE | aesFifoSize<<14 | (3 - aesFifoSize)<<12 | - AES_FLUSH_READ_FIFO | AES_FLUSH_WRITE_FIFO; - while(REG_AESCNT & AES_ENABLE) - { - waitForInterrupt(); - } - - // Disable the NDMA channels - REG_NDMA0_CNT = (REG_NDMA0_CNT<<1)>>1; - REG_NDMA1_CNT = (REG_NDMA1_CNT<<1)>>1; -} - -void AES_ctr(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool dma) -{ - fb_assert(ctx != NULL); - fb_assert(in != NULL); - fb_assert(out != NULL); - - const u32 ctrParams = ctx->ctrIvNonceParams; - u32 *const ctr = ctx->ctrIvNonce; - const u32 aesParams = AES_MODE_CTR | ctx->aesParams; - - - while(blocks) - { - REG_AESCNT = ctrParams; - REG_AESCTR[0] = ctr[0]; - REG_AESCTR[1] = ctr[1]; - REG_AESCTR[2] = ctr[2]; - REG_AESCTR[3] = ctr[3]; - - REG_AESCNT = aesParams; - u32 blockNum = ((blocks > AES_MAX_BLOCKS) ? AES_MAX_BLOCKS : blocks); - if(dma) aesProcessBlocksDma(in, out, blockNum); - else aesProcessBlocksCpu(in, out, blockNum); - - // AES will process 64 bytes for the last block of the - // block transfer even if only 48 are setup (0xFFFF vs. 0x10000 blocks). - if(dma && blockNum == AES_MAX_BLOCKS) blockNum++; - - AES_addCounter(ctr, blockNum<<4); - in += blockNum<<2; - out += blockNum<<2; - blocks -= blockNum; - } -} - -/*void AES_cbc(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool enc, bool dma) -{ - fb_assert(ctx != NULL); - fb_assert(in != NULL); - fb_assert(out != NULL); - - const u32 ivParams = ctx->ctrIvNonceParams; - u32 *const iv = ctx->ctrIvNonce; - const u32 aesParams = (enc ? AES_MODE_CBC_ENCRYPT : AES_MODE_CBC_DECRYPT) | ctx->aesParams; - - - while(blocks) - { - REG_AESCNT = ivParams; - REG_AESCTR[0] = iv[0]; - REG_AESCTR[1] = iv[1]; - REG_AESCTR[2] = iv[2]; - REG_AESCTR[3] = iv[3]; - - u32 blockNum = ((blocks > AES_MAX_BLOCKS) ? AES_MAX_BLOCKS : blocks); - - if(!enc) - { - // Save last 16 bytes of the input blocks as next IV - const u32 *const nextIv = in + (blockNum<<2) - 4; - if(aesParams>>23 & AES_INPUT_NORMAL) - { - iv[0] = nextIv[3]; - iv[1] = nextIv[2]; - iv[2] = nextIv[1]; - iv[3] = nextIv[0]; - } - else - { - iv[0] = nextIv[0]; - iv[1] = nextIv[1]; - iv[2] = nextIv[2]; - iv[3] = nextIv[3]; - } - } - - REG_AESCNT = aesParams; - if(dma) aesProcessBlocksDma(in, out, blockNum); - else aesProcessBlocksCpu(in, out, blockNum); - - if(enc) - { - // Save last 16 bytes of the output blocks as next IV - const u32 *const nextIv = out + (blockNum<<2) - 4; - if(aesParams>>23 & AES_INPUT_NORMAL) - { - iv[0] = nextIv[3]; - iv[1] = nextIv[2]; - iv[2] = nextIv[1]; - iv[3] = nextIv[0]; - } - else - { - iv[0] = nextIv[0]; - iv[1] = nextIv[1]; - iv[2] = nextIv[2]; - iv[3] = nextIv[3]; - } - } - - in += blockNum<<2; - out += blockNum<<2; - blocks -= blockNum; - } -}*/ - -void AES_ecb(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool enc, bool dma) -{ - fb_assert(ctx != NULL); - fb_assert(in != NULL); - fb_assert(out != NULL); - - const u32 aesParams = (enc ? AES_MODE_ECB_ENCRYPT : AES_MODE_ECB_DECRYPT) | ctx->aesParams; - - - while(blocks) - { - REG_AESCNT = aesParams; - u32 blockNum = ((blocks > AES_MAX_BLOCKS) ? AES_MAX_BLOCKS : blocks); - if(dma) aesProcessBlocksDma(in, out, blockNum); - else aesProcessBlocksCpu(in, out, blockNum); - - // AES will process 64 bytes for the last block of the - // block transfer even if only 48 are setup (0xFFFF vs. 0x10000 blocks). - if(dma && blockNum == AES_MAX_BLOCKS) blockNum++; - - in += blockNum<<2; - out += blockNum<<2; - blocks -= blockNum; - } -} - -bool AES_ccm(const AES_ctx *const ctx, const u32 *const in, u32 *const out, u32 macSize, - u32 mac[4], u16 blocks, bool enc) -{ - fb_assert(ctx != NULL); - fb_assert(in != NULL); - fb_assert(out != NULL); - fb_assert(macSize != 0); - fb_assert(mac != NULL); - fb_assert(blocks != 0); - - - REG_AESCNT = ctx->ctrIvNonceParams; - REG_AESCTR[0] = ctx->ctrIvNonce[0]; - REG_AESCTR[1] = ctx->ctrIvNonce[1]; - REG_AESCTR[2] = ctx->ctrIvNonce[2]; - - REG_AES_BLKCNT_LOW = 0; - REG_AESCNT = (enc ? AES_MODE_CCM_ENCRYPT : AES_MODE_CCM_DECRYPT) | - AES_MAC_SIZE(macSize) | ctx->aesParams; - aesProcessBlocksCpu(in, out, blocks); - - // This is broken right now with DMA due to a (AES engine?) bug. - if(!enc) - { - *((vu32*)REG_AESWRFIFO) = mac[0]; - *((vu32*)REG_AESWRFIFO) = mac[1]; - *((vu32*)REG_AESWRFIFO) = mac[2]; - *((vu32*)REG_AESWRFIFO) = mac[3]; - while(REG_AESCNT & AES_ENABLE); - } - else - { - mac[0] = *((vu32*)REG_AESRDFIFO); - mac[1] = *((vu32*)REG_AESRDFIFO); - mac[2] = *((vu32*)REG_AESRDFIFO); - mac[3] = *((vu32*)REG_AESRDFIFO); - } - - if(enc) return true; - else return AES_IS_MAC_VALID; -} - - - -////////////////////////////////// -// SHA // -////////////////////////////////// - -#define SHA_REGS_BASE (IO_MEM_ARM9_ONLY + 0xA000) -#define REG_SHA_CNT *((vu32*)(SHA_REGS_BASE + 0x00)) -#define REG_SHA_BLKCNT *((vu32*)(SHA_REGS_BASE + 0x04)) -#define REG_SHA_HASH ((u32* )(SHA_REGS_BASE + 0x40)) -#define REG_SHA_INFIFO ( (SHA_REGS_BASE + 0x80)) - - -void SHA_start(u8 params) -{ - REG_SHA_CNT = (u32)params | SHA_ENABLE; -} - -void SHA_update(const u32 *data, u32 size) -{ - while(size >= 0x40) - { - for(u32 i = 0; i < 4; i++) - { - ((vu32*)REG_SHA_INFIFO)[0 + i] = *data++; - ((vu32*)REG_SHA_INFIFO)[1 + i] = *data++; - ((vu32*)REG_SHA_INFIFO)[2 + i] = *data++; - ((vu32*)REG_SHA_INFIFO)[3 + i] = *data++; - } - while(REG_SHA_CNT & SHA_ENABLE); - - size -= 0x40; - } - - if(size) memcpy((void*)REG_SHA_INFIFO, data, size); -} - -void SHA_finish(u32 *const hash, u8 endianess) -{ - REG_SHA_CNT = (REG_SHA_CNT & (SHA_MODE_1 | SHA_MODE_224 | SHA_MODE_256)) | (u32)endianess | SHA_PAD_INPUT; - while(REG_SHA_CNT & SHA_ENABLE); - - u32 hashSize; - switch(REG_SHA_CNT & (SHA_MODE_1 | SHA_MODE_224 | SHA_MODE_256)) - { - case SHA_MODE_256: - hashSize = 8; // 32; - break; - case SHA_MODE_224: - hashSize = 7; // 28; - break; - case SHA_MODE_1: - hashSize = 5; // 20; - break; - default: - return; - } - - for(u32 i = 0; i < hashSize; i++) hash[i] = REG_SHA_HASH[i]; -} - -void sha(const u32 *data, u32 size, u32 *const hash, u8 params, u8 hashEndianess) -{ - SHA_start(params); - SHA_update(data, size); - SHA_finish(hash, hashEndianess); -} diff --git a/source/arm9/debug.c b/source/arm9/debug.c index 70fa443..4138d4d 100644 --- a/source/arm9/debug.c +++ b/source/arm9/debug.c @@ -21,12 +21,12 @@ #include "types.h" #include "arm9/fmt.h" #include "mem_map.h" -#include "pxi.h" +#include "hardware/pxi.h" #include "arm9/console.h" #include "fatfs/ff.h" #include "arm9/fsutils.h" #include "arm9/main.h" -#include "arm9/interrupt.h" +#include "arm9/hardware/interrupt.h" static u32 debugHash = 0; diff --git a/source/arm9/dev.c b/source/arm9/dev.c index d05fe37..cf74d4f 100644 --- a/source/arm9/dev.c +++ b/source/arm9/dev.c @@ -24,11 +24,11 @@ #include "mem_map.h" #include "arm9/main.h" #include "arm9/ncsd.h" -#include "arm9/sdmmc.h" -#include "arm9/spiflash.h" -#include "arm9/crypto.h" -#include "cache.h" -#include "arm9/timer.h" +#include "arm9/hardware/sdmmc.h" +#include "arm9/hardware/spiflash.h" +#include "arm9/hardware/crypto.h" +#include "hardware/cache.h" +#include "arm9/hardware/timer.h" #include "util.h" #include "arm9/dev.h" #include "arm9/partitions.h" diff --git a/source/arm9/exception.s b/source/arm9/exception.s deleted file mode 100644 index 37215b7..0000000 --- a/source/arm9/exception.s +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 . - */ - -#include "asmfunc.h" -#include "mem_map.h" - -.arm -.cpu arm946e-s -.fpu softvfp - -.extern deinitCpu -.extern guruMeditation -.extern irqHandlerTable - - - -ASM_FUNC undefInstrHandler - msr cpsr_f, #(0<<29) @ Abuse conditional flags in cpsr for temporary exception type storage - b exceptionHandler -ASM_FUNC prefetchAbortHandler - msr cpsr_f, #(1<<29) - b exceptionHandler -ASM_FUNC dataAbortHandler - msr cpsr_f, #(2<<29) -ASM_FUNC exceptionHandler - sub sp, #68 - stmia sp, {r0-r14}^ @ Save all user/system mode regs except pc - mrs r2, spsr @ Get saved cpsr - mrs r3, cpsr - lsr r0, r3, #29 @ Get back the exception type from cpsr - and r1, r2, #0x1F - cmp r1, #0x10 @ User mode - beq exceptionHandler_skip_other_mode - add r4, sp, #32 - msr cpsr_c, r2 - stmia r4!, {r8-r14} @ Some regs are written twice but we don't care - msr cpsr_c, r3 -exceptionHandler_skip_other_mode: - str lr, [sp, #60] @ Save lr (pc) on exception stack - str r2, [sp, #64] @ Save spsr (cpsr) on exception stack - mov r4, r0 - mov r5, sp - bl deinitCpu - mov r0, r4 - mov sp, r5 - mov r1, r5 - b guruMeditation @ r0 = exception type, r1 = reg dump ptr {r0-r14, pc (unmodified), cpsr} - - -ASM_FUNC irqHandler - sub lr, lr, #4 - stmfd sp!, {r0-r3, r12, lr} - mov r12, #0x10000000 - orr r12, #0x1000 @ REG_IRQ_IE - ldm r12, {r1, r2} - and r1, r1, r2 - mov r3, #0x80000000 - irqHandler_find_first_lp: - clz r2, r1 - bics r1, r1, r3, lsr r2 - bne irqHandler_find_first_lp - mov r1, r3, lsr r2 - str r1, [r12, #4] @ REG_IRQ_IF - rsb r0, r2, #31 @ r0 = 31 - r2 - ldr r1, =irqHandlerTable - ldr r2, [r1, r0, lsl #2] - cmp r2, #0 - beq irqHandler_skip_processing - mrs r3, spsr - str r3, [sp, #-4]! - msr cpsr_c, #0x5F @ System mode, IRQ enabled - str lr, [sp, #-4]! - blx r2 - ldr lr, [sp], #4 - msr cpsr_c, #0xD2 @ IRQ mode, IRQ disabled - ldr r0, [sp], #4 - msr spsr_fsxc, r0 -irqHandler_skip_processing: - ldmfd sp!, {r0-r3, r12, pc}^ diff --git a/source/arm9/fb_assert.c b/source/arm9/fb_assert.c index 71bbde9..9f2b764 100644 --- a/source/arm9/fb_assert.c +++ b/source/arm9/fb_assert.c @@ -18,7 +18,7 @@ #include "types.h" #include "arm9/fmt.h" -#include "arm9/interrupt.h" +#include "arm9/hardware/interrupt.h" diff --git a/source/arm9/firm.c b/source/arm9/firm.c index dcbe146..b86fa34 100644 --- a/source/arm9/firm.c +++ b/source/arm9/firm.c @@ -26,12 +26,12 @@ #undef ARM11 #include "arm9/firm.h" #include "arm9/start.h" -#include "arm9/crypto.h" -#include "arm9/ndma.h" +#include "arm9/hardware/crypto.h" +#include "arm9/hardware/ndma.h" #include "arm9/gui/ui.h" -#include "cache.h" +#include "hardware/cache.h" #include "util.h" -#include "pxi.h" +#include "hardware/pxi.h" diff --git a/source/arm9/firmwriter.c b/source/arm9/firmwriter.c index d6d7b84..e087be2 100644 --- a/source/arm9/firmwriter.c +++ b/source/arm9/firmwriter.c @@ -23,12 +23,12 @@ #include "mem_map.h" #include "arm9/dev.h" #include "fatfs/ff.h" -#include "arm9/hid.h" +#include "arm9/hardware/hid.h" #include "util.h" #include "arm9/firmwriter.h" #include "arm9/main.h" #include "arm9/gui/menu.h" -#include "arm9/timer.h" +#include "arm9/hardware/timer.h" static size_t totalToWrite; diff --git a/source/arm9/gui/menu.c b/source/arm9/gui/menu.c index c9b8392..0012b70 100644 --- a/source/arm9/gui/menu.c +++ b/source/arm9/gui/menu.c @@ -22,18 +22,18 @@ #include "types.h" #include "mem_map.h" #include "util.h" -#include "pxi.h" +#include "hardware/pxi.h" #include "arm9/console.h" #include "arm9/dev.h" #include "fatfs/ff.h" #include "fatfs/diskio.h" #include "arm9/fsutils.h" -#include "arm9/hid.h" +#include "arm9/hardware/hid.h" #include "arm9/main.h" #include "arm9/gui/menu.h" #include "arm9/gui/menu_firmloader.h" -#include "arm9/timer.h" -#include "arm9/interrupt.h" +#include "arm9/hardware/timer.h" +#include "arm9/hardware/interrupt.h" #include "arm9/config.h" diff --git a/source/arm9/gui/menu_credits.c b/source/arm9/gui/menu_credits.c index ceb7518..ed5be7d 100644 --- a/source/arm9/gui/menu_credits.c +++ b/source/arm9/gui/menu_credits.c @@ -24,11 +24,11 @@ #include "arm9/console.h" #include "arm9/dev.h" #include "fatfs/ff.h" -#include "pxi.h" -#include "arm9/hid.h" +#include "hardware/pxi.h" +#include "arm9/hardware/hid.h" #include "util.h" #include "arm9/main.h" -#include "arm9/timer.h" +#include "arm9/hardware/timer.h" #include "arm9/gui/menu.h" #include "arm9/gui/ui.h" diff --git a/source/arm9/gui/menu_filebrowse.c b/source/arm9/gui/menu_filebrowse.c index 1142f2c..e394c84 100644 --- a/source/arm9/gui/menu_filebrowse.c +++ b/source/arm9/gui/menu_filebrowse.c @@ -26,10 +26,10 @@ #include "arm9/console.h" #include "arm9/main.h" #include "arm9/gui/menu.h" -#include "arm9/interrupt.h" +#include "arm9/hardware/interrupt.h" #include "arm9/dev.h" #include "util.h" -#include "arm9/hid.h" +#include "arm9/hardware/hid.h" #define MAX_CACHED_ENTRIES 0x400 diff --git a/source/arm9/gui/menu_firmloader.c b/source/arm9/gui/menu_firmloader.c index 2cd24e4..8dee59b 100644 --- a/source/arm9/gui/menu_firmloader.c +++ b/source/arm9/gui/menu_firmloader.c @@ -24,11 +24,11 @@ #include "arm9/console.h" #include "arm9/dev.h" #include "fatfs/ff.h" -#include "arm9/hid.h" +#include "arm9/hardware/hid.h" #include "util.h" -#include "pxi.h" +#include "hardware/pxi.h" #include "arm9/main.h" -#include "arm9/timer.h" +#include "arm9/hardware/timer.h" #include "arm9/gui/menu.h" #include "arm9/firm.h" #include "arm9/config.h" diff --git a/source/arm9/gui/menu_nand.c b/source/arm9/gui/menu_nand.c index 93b1604..e8bac07 100644 --- a/source/arm9/gui/menu_nand.c +++ b/source/arm9/gui/menu_nand.c @@ -23,11 +23,11 @@ #include "arm9/console.h" #include "arm9/dev.h" #include "fatfs/ff.h" -#include "arm9/hid.h" +#include "arm9/hardware/hid.h" #include "util.h" #include "arm9/main.h" #include "arm9/gui/menu.h" -#include "arm9/timer.h" +#include "arm9/hardware/timer.h" #include "arm9/partitions.h" #include "arm9/firmwriter.h" #include "arm9/nandimage.h" diff --git a/source/arm9/gui/menu_options.c b/source/arm9/gui/menu_options.c index 22535c2..b22e373 100644 --- a/source/arm9/gui/menu_options.c +++ b/source/arm9/gui/menu_options.c @@ -24,11 +24,11 @@ #include "arm9/console.h" #include "arm9/dev.h" #include "fatfs/ff.h" -#include "pxi.h" -#include "arm9/hid.h" +#include "hardware/pxi.h" +#include "arm9/hardware/hid.h" #include "util.h" #include "arm9/main.h" -#include "arm9/timer.h" +#include "arm9/hardware/timer.h" #include "arm9/gui/menu.h" #include "arm9/nandimage.h" #include "arm9/config.h" diff --git a/source/arm9/gui/menu_update.c b/source/arm9/gui/menu_update.c index bda1a34..405b3cc 100644 --- a/source/arm9/gui/menu_update.c +++ b/source/arm9/gui/menu_update.c @@ -25,12 +25,12 @@ #include "arm9/dev.h" #include "arm9/partitions.h" #include "fatfs/ff.h" -#include "arm9/hid.h" +#include "arm9/hardware/hid.h" #include "util.h" #include "arm9/firmwriter.h" #include "arm9/main.h" #include "arm9/gui/menu.h" -#include "arm9/timer.h" +#include "arm9/hardware/timer.h" #define MIN_UPDATE_SIZE 0x1000 diff --git a/source/arm9/gui/splash.c b/source/arm9/gui/splash.c new file mode 100644 index 0000000..72602d1 --- /dev/null +++ b/source/arm9/gui/splash.c @@ -0,0 +1,90 @@ +/* + * 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 . + */ + +#include +#include +#include +#include "types.h" +#include "arm9/gui/splash.h" +#include "arm9/fmt.h" +#include "hardware/gfx.h" + + + +void lz11Decompress(const void *in, void *out, u32 size); + +void getSplashDimensions(const void *const data, u32 *const width, u32 *const height) +{ + const SplashHeader *const header = (const SplashHeader *const)data; + + if(width) *width = header->width; + if(height) *height = header->height; +} + +static bool validateSplashHeader(const SplashHeader *const header) +{ + if(memcmp(&header->magic, "SPLA", 4)) return false; + + const u32 width = header->width, height = header->height; + if(width == 0 || width > SCREEN_WIDTH_TOP || height == 0 || height > SCREEN_HEIGHT_TOP) + return false; + + const u32 flags = header->flags; + if((flags & FORMAT_INVALID) != FORMAT_RGB565) return false; + if(!(flags & FLAG_ROTATED) || flags & FLAG_SWAPPED) return false; + + return true; +} + +bool drawSplashscreen(const void *const data, s32 startX, s32 startY) +{ + const SplashHeader *const header = (const SplashHeader *const)data; + if(!validateSplashHeader(header)) return false; + + const u32 width = header->width, height = header->height; + const u32 flags = header->flags; + const bool isCompressed = flags & FLAG_COMPRESSED; + + u16 *imgData; + if(isCompressed) + { + imgData = (u16*)malloc(width * height * 2); + if(!imgData) return false; + lz11Decompress(data + sizeof(SplashHeader), imgData, width * height * 2); + } + else imgData = (u16*)(data + sizeof(SplashHeader)); + + u32 xx, yy; + if(startX < 0 || (u32)startX > SCREEN_WIDTH_TOP - width) xx = (SCREEN_WIDTH_TOP - width) / 2; + else xx = (u32)startX; + if(startY < 0 || (u32)startY > SCREEN_HEIGHT_TOP - height) yy = (SCREEN_HEIGHT_TOP - height) / 2; + else yy = (u32)startY; + + u16 *fb = (u16*)FRAMEBUF_TOP_A_1; + for(u32 x = 0; x < width; x++) + { + for(u32 y = 0; y < height; y++) + { + fb[(x + xx) * SCREEN_HEIGHT_TOP + y + yy] = imgData[x * height + y]; + } + } + + if(isCompressed) free(imgData); + + return true; +} diff --git a/source/arm9/gui/ui.c b/source/arm9/gui/ui.c index 3acfa3e..b38006f 100644 --- a/source/arm9/gui/ui.c +++ b/source/arm9/gui/ui.c @@ -23,13 +23,13 @@ #include "types.h" #include "arm9/fmt.h" #include "util.h" -#include "arm9/hid.h" -#include "pxi.h" -#include "arm9/timer.h" +#include "arm9/hardware/hid.h" +#include "hardware/pxi.h" +#include "arm9/hardware/timer.h" #include "arm9/main.h" #include "arm9/gui/ui.h" #include "arm9/console.h" -#include "arm9/splash.h" +#include "arm9/gui/splash.h" #include "banner_spla.h" #include "bootwarning_spla.h" #include "bootfail_spla.h" diff --git a/source/arm9/hardware.c b/source/arm9/hardware.c deleted file mode 100644 index 38a9db0..0000000 --- a/source/arm9/hardware.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 . - */ - -#include "types.h" -#include "arm9/interrupt.h" -#include "arm9/ndma.h" -#include "arm9/timer.h" -#include "pxi.h" -#include "arm9/crypto.h" - - - -void hardwareInit(void) -{ - IRQ_init(); - NDMA_init(); - TIMER_init(); - PXI_init(); - AES_init(); -} - -void hardwareDeinit(void) -{ - // New 3DS K9L doesn't like FIFO counts >4 and hangs. - // Thx Nintendo - AES_deinit(); -} diff --git a/source/arm9/hardware/cache.s b/source/arm9/hardware/cache.s new file mode 100644 index 0000000..594cfdf --- /dev/null +++ b/source/arm9/hardware/cache.s @@ -0,0 +1,126 @@ +/* + * 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 . + */ + +#include "asmfunc.h" + +.arm +.cpu arm946e-s +.fpu softvfp + + +#define ICACHE_SIZE (0x2000) +#define DCACHE_SIZE (0x1000) +#define CACHE_LINE_SIZE (32) + + + +ASM_FUNC invalidateICache + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ "Flush instruction cache" + bx lr + + +ASM_FUNC invalidateICacheRange + add r1, r1, r0 + bic r0, r0, #(CACHE_LINE_SIZE - 1) + invalidateICacheRange_lp: + mcr p15, 0, r0, c7, c5, 1 @ "Flush instruction cache single entry Address" + add r0, r0, #CACHE_LINE_SIZE + cmp r0, r1 + blt invalidateICacheRange_lp + bx lr + + +ASM_FUNC flushDCache + mov r1, #0 + flushDCache_outer_lp: + mov r0, #0 + flushDCache_inner_lp: + orr r2, r1, r0 @ Generate segment and line address + mcr p15, 0, r2, c7, c10, 2 @ "Clean data cache entry Index and segment" + add r0, r0, #CACHE_LINE_SIZE + cmp r0, #(DCACHE_SIZE / 4) + bne flushDCache_inner_lp + add r1, r1, #0x40000000 + cmp r1, #0 + bne flushDCache_outer_lp + b drainWriteBufferFlushInvalidate + + +ASM_FUNC flushInvalidateDCache + mov r1, #0 + flushInvalidateDCache_outer_lp: + mov r0, #0 + flushInvalidateDCache_inner_lp: + orr r2, r1, r0 @ Generate segment and line address + mcr p15, 0, r2, c7, c14, 2 @ "Clean and flush data cache entry Index and segment" + add r0, r0, #CACHE_LINE_SIZE + cmp r0, #(DCACHE_SIZE / 4) + bne flushInvalidateDCache_inner_lp + add r1, r1, #0x40000000 + cmp r1, #0 + bne flushInvalidateDCache_outer_lp +drainWriteBufferFlushInvalidate: + mcr p15, 0, r1, c7, c10, 4 @ Drain write buffer + bx lr + + +ASM_FUNC flushDCacheRange + add r1, r1, r0 + bic r0, r0, #(CACHE_LINE_SIZE - 1) + flushDCacheRange_lp: + mcr p15, 0, r0, c7, c10, 1 @ "Clean data cache entry Address" + add r0, r0, #CACHE_LINE_SIZE + cmp r0, r1 + blt flushDCacheRange_lp + b drainWriteBufferFlushInvalidateRange + + +ASM_FUNC flushInvalidateDCacheRange + add r1, r1, r0 + bic r0, r0, #(CACHE_LINE_SIZE - 1) + flushInvalidateDCacheRange_lp: + mcr p15, 0, r0, c7, c14, 1 @ "Clean and flush data cache entry Address" + add r0, r0, #CACHE_LINE_SIZE + cmp r0, r1 + blt flushInvalidateDCacheRange_lp +drainWriteBufferFlushInvalidateRange: + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer + bx lr + + +ASM_FUNC invalidateDCache + mov r0, #0 + mcr p15, 0, r0, c7, c6, 0 @ "Flush data cache" + bx lr + + +ASM_FUNC invalidateDCacheRange + add r1, r1, r0 + tst r0, #(CACHE_LINE_SIZE - 1) + mcrne p15, 0, r0, c7, c10, 1 @ "Clean data cache entry Address" + tst r1, #(CACHE_LINE_SIZE - 1) + mcrne p15, 0, r1, c7, c10, 1 @ "Clean data cache entry Address" + bic r0, r0, #(CACHE_LINE_SIZE - 1) + invalidateDCacheRange_lp: + mcr p15, 0, r0, c7, c6, 1 @ "Flush data cache single entry Address" + add r0, r0, #CACHE_LINE_SIZE + cmp r0, r1 + blt invalidateDCacheRange_lp + bx lr diff --git a/source/arm9/hardware/crypto.c b/source/arm9/hardware/crypto.c new file mode 100644 index 0000000..ac4ade2 --- /dev/null +++ b/source/arm9/hardware/crypto.c @@ -0,0 +1,654 @@ +/* + * 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 . + */ + +#include +#include "arm9/fb_assert.h" +#include "mem_map.h" +#include "types.h" +#include "arm9/hardware/crypto.h" +#include "arm9/hardware/interrupt.h" +#include "arm9/hardware/ndma.h" + + + +////////////////////////////////// +// AES // +////////////////////////////////// + +#define AES_REGS_BASE (IO_MEM_ARM9_ONLY + 0x9000) +#define REG_AESCNT *((vu32*)(AES_REGS_BASE + 0x000)) + +#define REG_AESBLKCNT *((vu32*)(AES_REGS_BASE + 0x004)) +#define REG_AES_BLKCNT_LOW *((vu16*)(AES_REGS_BASE + 0x004)) +#define REG_AES_BLKCNT_HIGH *((vu16*)(AES_REGS_BASE + 0x006)) +#define REG_AESWRFIFO ( AES_REGS_BASE + 0x008) +#define REG_AESRDFIFO ( AES_REGS_BASE + 0x00C) +#define REG_AESKEYSEL *((vu8* )(AES_REGS_BASE + 0x010)) +#define REG_AESKEYCNT *((vu8* )(AES_REGS_BASE + 0x011)) +#define REG_AESCTR ((vu32*)(AES_REGS_BASE + 0x020)) +#define REG_AESMAC ((vu32*)(AES_REGS_BASE + 0x030)) + +#define REG_AESKEY0 ((vu32*)(AES_REGS_BASE + 0x040)) +#define REG_AESKEYX0 ((vu32*)(AES_REGS_BASE + 0x050)) +#define REG_AESKEYY0 ((vu32*)(AES_REGS_BASE + 0x060)) +#define REG_AESKEY1 ((vu32*)(AES_REGS_BASE + 0x070)) +#define REG_AESKEYX1 ((vu32*)(AES_REGS_BASE + 0x080)) +#define REG_AESKEYY1 ((vu32*)(AES_REGS_BASE + 0x090)) +#define REG_AESKEY2 ((vu32*)(AES_REGS_BASE + 0x0A0)) +#define REG_AESKEYX2 ((vu32*)(AES_REGS_BASE + 0x0B0)) +#define REG_AESKEYY2 ((vu32*)(AES_REGS_BASE + 0x0C0)) +#define REG_AESKEY3 ((vu32*)(AES_REGS_BASE + 0x0D0)) +#define REG_AESKEYX3 ((vu32*)(AES_REGS_BASE + 0x0E0)) +#define REG_AESKEYY3 ((vu32*)(AES_REGS_BASE + 0x0F0)) + +#define REG_AESKEYFIFO ((vu32*)(AES_REGS_BASE + 0x100)) +#define REG_AESKEYXFIFO ((vu32*)(AES_REGS_BASE + 0x104)) +#define REG_AESKEYYFIFO ((vu32*)(AES_REGS_BASE + 0x108)) + + +/*static void deriveKey(u32 pad[4], u32 boot9Off) +{ + const u32 *pad2 = (u32*)(BOOT9_BASE + boot9Off); + + pad[0] ^= pad2[0]; + pad[1] ^= pad2[1]; + pad[2] ^= pad2[2]; + pad[3] ^= pad2[3]; +}*/ + +static void setupKeys(void) +{ + // Setup TWL unit info and console ID + const bool isDevUnit = CFG_UNITINFO != 0; + const u64 twlConsoleId = (isDevUnit ? (*((vu64*)0x10012000)) : + ((*((vu64*)0x01FFB808) ^ 0x8C267B7B358A6AFULL) | 0x80000000ULL)); + *((vu8*)0x10010014) = CFG_UNITINFO; + *((vu64*)0x10012100) = twlConsoleId; + + + // TWL key init + REG_AESCNT = 0; + REG_AESKEYX1[2] = (u32)(twlConsoleId>>32); + REG_AESKEYX1[3] = (u32)twlConsoleId; + + AES_setKey(0x02, AES_KEY_X, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, (u32*)0x01FFD398); + + u32 key3X[4] = {(u32)twlConsoleId, 0, 0, (u32)(twlConsoleId>>32)}; + if(isDevUnit) + { + key3X[1] = 0xEE7A4B1E; + key3X[2] = 0xAF42C08B; + AES_setKey(0x03, AES_KEY_X, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, key3X); + + alignas(4) static const u8 key2YDev[16] = { + 0x3B, 0x06, 0x86, 0x57, 0x33, 0x04, 0x88, 0x11, 0x49, 0x04, 0x6B, 0x33, 0x12, 0x02, 0xAC, 0xF3}; + alignas(4) static const u8 key3YDev[16] = { + 0xAA, 0xBF, 0x76, 0xF1, 0x7A, 0xB8, 0xE8, 0x66, 0x97, 0x64, 0x6A, 0x26, 0x05, 0x00, 0xA0, 0xE1}; + AES_setKey(0x02, AES_KEY_Y, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, (const u32*)key2YDev); + AES_setKey(0x03, AES_KEY_Y, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, (const u32*)key3YDev); + } + else + { + key3X[1] = 0x544E494E; // "NINT" + key3X[2] = 0x4F444E45; // "ENDO" + AES_setKey(0x03, AES_KEY_X, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, key3X); + + AES_setKey(0x02, AES_KEY_Y, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, (u32*)0x01FFD220); + + u32 key3YRetail[4]; + key3YRetail[0] = ((u32*)0x01FFD3C8)[0]; + key3YRetail[1] = ((u32*)0x01FFD3C8)[1]; + key3YRetail[2] = ((u32*)0x01FFD3C8)[2]; + key3YRetail[3] = 0xE1A00005; + AES_setKey(0x03, AES_KEY_Y, AES_INPUT_LITTLE | AES_INPUT_REVERSED, false, key3YRetail); + } + + + // 3DS key init + if(REG_PDN_MPCORE_CFG & 2u) // New 3DS + { + alignas(4) static const u8 keyY0x05[16] = { + 0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE}; + AES_setKey(0x05, AES_KEY_Y, AES_INPUT_BIG | AES_INPUT_NORMAL, false, (const u32*)keyY0x05); + } + + alignas(4) static const u8 keyY0x24[16] = { + 0x74, 0xCA, 0x07, 0x48, 0x84, 0xF4, 0x22, 0x8D, 0xEB, 0x2A, 0x1C, 0xA7, 0x2D, 0x28, 0x77, 0x62}; + AES_setKey(0x24, AES_KEY_Y, AES_INPUT_BIG | AES_INPUT_NORMAL, false, (const u32*)keyY0x24); + + alignas(4) static const u8 keyX0x25s[2][16] = { + {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3}, + {0x81, 0x90, 0x7A, 0x4B, 0x6F, 0x1B, 0x47, 0x32, 0x3A, 0x67, 0x79, 0x74, 0xCE, 0x4A, 0xD7, 0x1B}}; + AES_setKey(0x25, AES_KEY_X, AES_INPUT_BIG | AES_INPUT_NORMAL, false, (const u32*)keyX0x25s[isDevUnit]); + + alignas(4) static const u8 keyY0x2Fs[2][16] = { + {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16}, + {0x73, 0x25, 0xC4, 0xEB, 0x14, 0x3A, 0x0D, 0x5F, 0x5D, 0xB6, 0xE5, 0xC5, 0x7A, 0x21, 0x95, 0xAC}}; + AES_setKey(0x2F, AES_KEY_Y, AES_INPUT_BIG | AES_INPUT_NORMAL, false, (const u32*)keyY0x2Fs[isDevUnit]); + + // Set 0x11 keyslot + alignas(4) static const u8 key1s[2][16] = { + {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8}, + {0xA2, 0xF4, 0x00, 0x3C, 0x7A, 0x95, 0x10, 0x25, 0xDF, 0x4E, 0x9E, 0x74, 0xE3, 0x0C, 0x92, 0x99}}; + alignas(4) static const u8 key2s[2][16] = { + {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0}, + {0xFF, 0x77, 0xA0, 0x9A, 0x99, 0x81, 0xE9, 0x48, 0xEC, 0x51, 0xC9, 0x32, 0x5D, 0x14, 0xEC, 0x25}}; + + + alignas(4) u8 keyBlocks[2][16] = { + {0xA4, 0x8D, 0xE4, 0xF1, 0x0B, 0x36, 0x44, 0xAA, 0x90, 0x31, 0x28, 0xFF, 0x4D, 0xCA, 0x76, 0xDF}, + {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98}}; + u32 decKey[4]; + + AES_ctx ctx; + AES_setCryptParams(&ctx, AES_INPUT_BIG | AES_INPUT_NORMAL, AES_OUTPUT_BIG | AES_OUTPUT_NORMAL); + + // key 0x18 + AES_setKey(0x11, AES_KEY_NORMAL, AES_INPUT_BIG | AES_INPUT_NORMAL, false, (const u32*)key1s[isDevUnit]); + AES_selectKeyslot(0x11); + AES_ecb(&ctx, (const u32*)keyBlocks[0], decKey, 1, false, false); + AES_setKey(0x18, AES_KEY_X, AES_INPUT_BIG | AES_INPUT_NORMAL, false, decKey); + + AES_setKey(0x11, AES_KEY_NORMAL, AES_INPUT_BIG | AES_INPUT_NORMAL, false, (const u32*)key2s[isDevUnit]); + AES_selectKeyslot(0x11); + for(u8 slot = 0x19; slot < 0x20; slot++, keyBlocks[1][0xF]++) + { + AES_ecb(&ctx, (const u32*)keyBlocks[1], decKey, 1, false, false); + AES_setKey(slot, AES_KEY_X, AES_INPUT_BIG | AES_INPUT_NORMAL, false, decKey); + } +} + +void AES_init(void) +{ + REG_AESCNT = AES_MAC_SIZE(4) | AES_FLUSH_WRITE_FIFO | AES_FLUSH_READ_FIFO; + *((vu8*)0x10000008) |= 0xCu; // ?? + + REG_NDMA0_DST_ADDR = REG_AESWRFIFO; + REG_NDMA0_INT_CNT = NDMA_INT_SYS_FREQ; + REG_NDMA0_CNT = NDMA_REPEATING_MODE | NDMA_STARTUP_AES_IN | + NDMA_SRC_UPDATE_INC | NDMA_DST_UPDATE_FIXED; + + REG_NDMA1_SRC_ADDR = REG_AESRDFIFO; + REG_NDMA1_INT_CNT = NDMA_INT_SYS_FREQ; + REG_NDMA1_CNT = NDMA_REPEATING_MODE | NDMA_STARTUP_AES_OUT | + NDMA_SRC_UPDATE_FIXED | NDMA_DST_UPDATE_INC; + + IRQ_registerHandler(IRQ_AES, NULL); + + setupKeys(); +} + +void AES_deinit(void) +{ + REG_AESCNT = AES_MAC_SIZE(4) | AES_FLUSH_WRITE_FIFO | AES_FLUSH_READ_FIFO; +} + +void AES_setKey(u8 keyslot, AesKeyType type, u8 orderEndianess, bool twlScrambler, const u32 key[4]) +{ + fb_assert(keyslot < 0x40); + fb_assert(key != NULL); + + + REG_AESCNT = (u32)orderEndianess<<23; + if(keyslot > 3) + { + REG_AESKEYCNT = 0x80u | (type > AES_KEY_NORMAL && twlScrambler ? 1u : 0u)<<6 | keyslot; + REG_AESKEYFIFO[type] = key[0]; + REG_AESKEYFIFO[type] = key[1]; + REG_AESKEYFIFO[type] = key[2]; + REG_AESKEYFIFO[type] = key[3]; + } + else + { + u32 lastu32; + vu32 *twlKeyNReg = ®_AESKEY0[12u * keyslot + type * 4u]; + if(orderEndianess & AES_INPUT_NORMAL) + { + twlKeyNReg[0] = key[3]; + twlKeyNReg[1] = key[2]; + twlKeyNReg[2] = key[1]; + lastu32 = key[0]; + } + else + { + twlKeyNReg[0] = key[0]; + twlKeyNReg[1] = key[1]; + twlKeyNReg[2] = key[2]; + lastu32 = key[3]; + } + twlKeyNReg[3] = lastu32; + } +} + +void AES_selectKeyslot(u8 keyslot) +{ + fb_assert(keyslot < 0x40); + + REG_AESKEYSEL = keyslot; + REG_AESCNT |= AES_UPDATE_KEYSLOT; +} + +void AES_setNonce(AES_ctx *const ctx, u8 orderEndianess, const u32 nonce[3]) +{ + fb_assert(ctx != NULL); + fb_assert(nonce != NULL); + + + ctx->ctrIvNonceParams = (u32)orderEndianess<<23; + u32 *const ctrIvNonce = ctx->ctrIvNonce; + u32 lastu32; + if(orderEndianess & AES_INPUT_NORMAL) + { + ctrIvNonce[0] = nonce[2]; + ctrIvNonce[1] = nonce[1]; + lastu32 = nonce[0]; + } + else + { + ctrIvNonce[0] = nonce[0]; + ctrIvNonce[1] = nonce[1]; + lastu32 = nonce[2]; + } + ctrIvNonce[2] = lastu32; +} + +void AES_setCtrIv(AES_ctx *const ctx, u8 orderEndianess, const u32 ctrIv[4]) +{ + fb_assert(ctx != NULL); + fb_assert(ctrIv != NULL); + + + ctx->ctrIvNonceParams = (u32)orderEndianess<<23; + u32 *const ctrIvNonce = ctx->ctrIvNonce; + u32 lastu32; + if(orderEndianess & AES_INPUT_NORMAL) + { + ctrIvNonce[0] = ctrIv[3]; + ctrIvNonce[1] = ctrIv[2]; + ctrIvNonce[2] = ctrIv[1]; + lastu32 = ctrIv[0]; + } + else + { + ctrIvNonce[0] = ctrIv[0]; + ctrIvNonce[1] = ctrIv[1]; + ctrIvNonce[2] = ctrIv[2]; + lastu32 = ctrIv[3]; + } + ctrIvNonce[3] = lastu32; +} + +// TODO: Handle endianess! +void AES_addCounter(u32 ctr[4], u32 val) +{ + fb_assert(ctr != NULL); + + u32 carry, i = 1; + u64 sum; + + sum = ctr[0]; + sum += (val >> 4); + carry = sum >> 32; + ctr[0] = sum & 0xFFFFFFFFu; + + while(carry) + { + sum = ctr[i]; + sum += carry; + carry = sum >> 32; + ctr[i] = sum & 0xFFFFFFFFu; + i++; + } +} + +void AES_subCounter(u32 ctr[4], u32 val) +{ + fb_assert(ctr != NULL); + + u32 carry, i = 1; + u32 sum; + + sum = ctr[0] - (val >> 4); + carry = (sum > ctr[0]); + ctr[0] = sum; + + while(carry && i < 4) + { + sum = ctr[i] - carry; + carry = (sum > ctr[i]); + ctr[i] = sum; + i++; + } +} + +void AES_setCryptParams(AES_ctx *const ctx, u8 inEndianessOrder, u8 outEndianessOrder) +{ + fb_assert(ctx != NULL); + + ctx->aesParams = (u32)inEndianessOrder<<23 | (u32)outEndianessOrder<<22; +} + +static void aesProcessBlocksCpu(const u32 *in, u32 *out, u32 blocks) +{ + REG_AES_BLKCNT_HIGH = blocks; + REG_AESCNT |= AES_ENABLE | 3<<12 | AES_FLUSH_READ_FIFO | AES_FLUSH_WRITE_FIFO; + + for(u32 i = 0; i < blocks * 4; i += 4) + { + *((vu32*)REG_AESWRFIFO) = in[0 + i]; + *((vu32*)REG_AESWRFIFO) = in[1 + i]; + *((vu32*)REG_AESWRFIFO) = in[2 + i]; + *((vu32*)REG_AESWRFIFO) = in[3 + i]; + + while(AES_READ_FIFO_COUNT == 0); + + out[0 + i] = *((vu32*)REG_AESRDFIFO); + out[1 + i] = *((vu32*)REG_AESRDFIFO); + out[2 + i] = *((vu32*)REG_AESRDFIFO); + out[3 + i] = *((vu32*)REG_AESRDFIFO); + } +} + +// AES_init() must be called before this works +static void aesProcessBlocksDma(const u32 *in, u32 *out, u32 blocks) +{ + // DMA can't reach TCMs + fb_assert(((u32)in >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)in < DTCM_BASE) || ((u32)in >= DTCM_BASE + DTCM_SIZE))); + fb_assert(((u32)out >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)out < DTCM_BASE) || ((u32)out >= DTCM_BASE + DTCM_SIZE))); + + + // Check block alignment + u32 aesFifoSize, dmaBurstSize; + if(!(blocks & 3) || blocks == AES_MAX_BLOCKS) + { + aesFifoSize = 3; + dmaBurstSize = NDMA_BURST_SIZE(16); + } + else if(!(blocks & 1)) + { + aesFifoSize = 1; + dmaBurstSize = NDMA_BURST_SIZE(8); + } + else + { + aesFifoSize = 0; + dmaBurstSize = NDMA_BURST_SIZE(4); + } + + REG_NDMA0_SRC_ADDR = (u32)in; + REG_NDMA0_LOG_BLK_CNT = aesFifoSize * 4 + 4; + REG_NDMA0_CNT = (REG_NDMA0_CNT & 0xFFF0FFFFu) | NDMA_ENABLE | dmaBurstSize; + + REG_NDMA1_DST_ADDR = (u32)out; + REG_NDMA1_LOG_BLK_CNT = aesFifoSize * 4 + 4; + REG_NDMA1_CNT = (REG_NDMA1_CNT & 0xFFF0FFFFu) | NDMA_ENABLE | dmaBurstSize; + + REG_AES_BLKCNT_HIGH = blocks; + REG_AESCNT |= AES_ENABLE | AES_IRQ_ENABLE | aesFifoSize<<14 | (3 - aesFifoSize)<<12 | + AES_FLUSH_READ_FIFO | AES_FLUSH_WRITE_FIFO; + while(REG_AESCNT & AES_ENABLE) + { + waitForInterrupt(); + } + + // Disable the NDMA channels + REG_NDMA0_CNT = (REG_NDMA0_CNT<<1)>>1; + REG_NDMA1_CNT = (REG_NDMA1_CNT<<1)>>1; +} + +void AES_ctr(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool dma) +{ + fb_assert(ctx != NULL); + fb_assert(in != NULL); + fb_assert(out != NULL); + + const u32 ctrParams = ctx->ctrIvNonceParams; + u32 *const ctr = ctx->ctrIvNonce; + const u32 aesParams = AES_MODE_CTR | ctx->aesParams; + + + while(blocks) + { + REG_AESCNT = ctrParams; + REG_AESCTR[0] = ctr[0]; + REG_AESCTR[1] = ctr[1]; + REG_AESCTR[2] = ctr[2]; + REG_AESCTR[3] = ctr[3]; + + REG_AESCNT = aesParams; + u32 blockNum = ((blocks > AES_MAX_BLOCKS) ? AES_MAX_BLOCKS : blocks); + if(dma) aesProcessBlocksDma(in, out, blockNum); + else aesProcessBlocksCpu(in, out, blockNum); + + // AES will process 64 bytes for the last block of the + // block transfer even if only 48 are setup (0xFFFF vs. 0x10000 blocks). + if(dma && blockNum == AES_MAX_BLOCKS) blockNum++; + + AES_addCounter(ctr, blockNum<<4); + in += blockNum<<2; + out += blockNum<<2; + blocks -= blockNum; + } +} + +/*void AES_cbc(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool enc, bool dma) +{ + fb_assert(ctx != NULL); + fb_assert(in != NULL); + fb_assert(out != NULL); + + const u32 ivParams = ctx->ctrIvNonceParams; + u32 *const iv = ctx->ctrIvNonce; + const u32 aesParams = (enc ? AES_MODE_CBC_ENCRYPT : AES_MODE_CBC_DECRYPT) | ctx->aesParams; + + + while(blocks) + { + REG_AESCNT = ivParams; + REG_AESCTR[0] = iv[0]; + REG_AESCTR[1] = iv[1]; + REG_AESCTR[2] = iv[2]; + REG_AESCTR[3] = iv[3]; + + u32 blockNum = ((blocks > AES_MAX_BLOCKS) ? AES_MAX_BLOCKS : blocks); + + if(!enc) + { + // Save last 16 bytes of the input blocks as next IV + const u32 *const nextIv = in + (blockNum<<2) - 4; + if(aesParams>>23 & AES_INPUT_NORMAL) + { + iv[0] = nextIv[3]; + iv[1] = nextIv[2]; + iv[2] = nextIv[1]; + iv[3] = nextIv[0]; + } + else + { + iv[0] = nextIv[0]; + iv[1] = nextIv[1]; + iv[2] = nextIv[2]; + iv[3] = nextIv[3]; + } + } + + REG_AESCNT = aesParams; + if(dma) aesProcessBlocksDma(in, out, blockNum); + else aesProcessBlocksCpu(in, out, blockNum); + + if(enc) + { + // Save last 16 bytes of the output blocks as next IV + const u32 *const nextIv = out + (blockNum<<2) - 4; + if(aesParams>>23 & AES_INPUT_NORMAL) + { + iv[0] = nextIv[3]; + iv[1] = nextIv[2]; + iv[2] = nextIv[1]; + iv[3] = nextIv[0]; + } + else + { + iv[0] = nextIv[0]; + iv[1] = nextIv[1]; + iv[2] = nextIv[2]; + iv[3] = nextIv[3]; + } + } + + in += blockNum<<2; + out += blockNum<<2; + blocks -= blockNum; + } +}*/ + +void AES_ecb(AES_ctx *const ctx, const u32 *in, u32 *out, u32 blocks, bool enc, bool dma) +{ + fb_assert(ctx != NULL); + fb_assert(in != NULL); + fb_assert(out != NULL); + + const u32 aesParams = (enc ? AES_MODE_ECB_ENCRYPT : AES_MODE_ECB_DECRYPT) | ctx->aesParams; + + + while(blocks) + { + REG_AESCNT = aesParams; + u32 blockNum = ((blocks > AES_MAX_BLOCKS) ? AES_MAX_BLOCKS : blocks); + if(dma) aesProcessBlocksDma(in, out, blockNum); + else aesProcessBlocksCpu(in, out, blockNum); + + // AES will process 64 bytes for the last block of the + // block transfer even if only 48 are setup (0xFFFF vs. 0x10000 blocks). + if(dma && blockNum == AES_MAX_BLOCKS) blockNum++; + + in += blockNum<<2; + out += blockNum<<2; + blocks -= blockNum; + } +} + +bool AES_ccm(const AES_ctx *const ctx, const u32 *const in, u32 *const out, u32 macSize, + u32 mac[4], u16 blocks, bool enc) +{ + fb_assert(ctx != NULL); + fb_assert(in != NULL); + fb_assert(out != NULL); + fb_assert(macSize != 0); + fb_assert(mac != NULL); + fb_assert(blocks != 0); + + + REG_AESCNT = ctx->ctrIvNonceParams; + REG_AESCTR[0] = ctx->ctrIvNonce[0]; + REG_AESCTR[1] = ctx->ctrIvNonce[1]; + REG_AESCTR[2] = ctx->ctrIvNonce[2]; + + REG_AES_BLKCNT_LOW = 0; + REG_AESCNT = (enc ? AES_MODE_CCM_ENCRYPT : AES_MODE_CCM_DECRYPT) | + AES_MAC_SIZE(macSize) | ctx->aesParams; + aesProcessBlocksCpu(in, out, blocks); + + // This is broken right now with DMA due to a (AES engine?) bug. + if(!enc) + { + *((vu32*)REG_AESWRFIFO) = mac[0]; + *((vu32*)REG_AESWRFIFO) = mac[1]; + *((vu32*)REG_AESWRFIFO) = mac[2]; + *((vu32*)REG_AESWRFIFO) = mac[3]; + while(REG_AESCNT & AES_ENABLE); + } + else + { + mac[0] = *((vu32*)REG_AESRDFIFO); + mac[1] = *((vu32*)REG_AESRDFIFO); + mac[2] = *((vu32*)REG_AESRDFIFO); + mac[3] = *((vu32*)REG_AESRDFIFO); + } + + if(enc) return true; + else return AES_IS_MAC_VALID; +} + + + +////////////////////////////////// +// SHA // +////////////////////////////////// + +#define SHA_REGS_BASE (IO_MEM_ARM9_ONLY + 0xA000) +#define REG_SHA_CNT *((vu32*)(SHA_REGS_BASE + 0x00)) +#define REG_SHA_BLKCNT *((vu32*)(SHA_REGS_BASE + 0x04)) +#define REG_SHA_HASH ((u32* )(SHA_REGS_BASE + 0x40)) +#define REG_SHA_INFIFO ( (SHA_REGS_BASE + 0x80)) + + +void SHA_start(u8 params) +{ + REG_SHA_CNT = (u32)params | SHA_ENABLE; +} + +void SHA_update(const u32 *data, u32 size) +{ + while(size >= 0x40) + { + for(u32 i = 0; i < 4; i++) + { + ((vu32*)REG_SHA_INFIFO)[0 + i] = *data++; + ((vu32*)REG_SHA_INFIFO)[1 + i] = *data++; + ((vu32*)REG_SHA_INFIFO)[2 + i] = *data++; + ((vu32*)REG_SHA_INFIFO)[3 + i] = *data++; + } + while(REG_SHA_CNT & SHA_ENABLE); + + size -= 0x40; + } + + if(size) memcpy((void*)REG_SHA_INFIFO, data, size); +} + +void SHA_finish(u32 *const hash, u8 endianess) +{ + REG_SHA_CNT = (REG_SHA_CNT & (SHA_MODE_1 | SHA_MODE_224 | SHA_MODE_256)) | (u32)endianess | SHA_PAD_INPUT; + while(REG_SHA_CNT & SHA_ENABLE); + + u32 hashSize; + switch(REG_SHA_CNT & (SHA_MODE_1 | SHA_MODE_224 | SHA_MODE_256)) + { + case SHA_MODE_256: + hashSize = 8; // 32; + break; + case SHA_MODE_224: + hashSize = 7; // 28; + break; + case SHA_MODE_1: + hashSize = 5; // 20; + break; + default: + return; + } + + for(u32 i = 0; i < hashSize; i++) hash[i] = REG_SHA_HASH[i]; +} + +void sha(const u32 *data, u32 size, u32 *const hash, u8 params, u8 hashEndianess) +{ + SHA_start(params); + SHA_update(data, size); + SHA_finish(hash, hashEndianess); +} diff --git a/source/arm9/hardware/exception.s b/source/arm9/hardware/exception.s new file mode 100644 index 0000000..37215b7 --- /dev/null +++ b/source/arm9/hardware/exception.s @@ -0,0 +1,94 @@ +/* + * 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 . + */ + +#include "asmfunc.h" +#include "mem_map.h" + +.arm +.cpu arm946e-s +.fpu softvfp + +.extern deinitCpu +.extern guruMeditation +.extern irqHandlerTable + + + +ASM_FUNC undefInstrHandler + msr cpsr_f, #(0<<29) @ Abuse conditional flags in cpsr for temporary exception type storage + b exceptionHandler +ASM_FUNC prefetchAbortHandler + msr cpsr_f, #(1<<29) + b exceptionHandler +ASM_FUNC dataAbortHandler + msr cpsr_f, #(2<<29) +ASM_FUNC exceptionHandler + sub sp, #68 + stmia sp, {r0-r14}^ @ Save all user/system mode regs except pc + mrs r2, spsr @ Get saved cpsr + mrs r3, cpsr + lsr r0, r3, #29 @ Get back the exception type from cpsr + and r1, r2, #0x1F + cmp r1, #0x10 @ User mode + beq exceptionHandler_skip_other_mode + add r4, sp, #32 + msr cpsr_c, r2 + stmia r4!, {r8-r14} @ Some regs are written twice but we don't care + msr cpsr_c, r3 +exceptionHandler_skip_other_mode: + str lr, [sp, #60] @ Save lr (pc) on exception stack + str r2, [sp, #64] @ Save spsr (cpsr) on exception stack + mov r4, r0 + mov r5, sp + bl deinitCpu + mov r0, r4 + mov sp, r5 + mov r1, r5 + b guruMeditation @ r0 = exception type, r1 = reg dump ptr {r0-r14, pc (unmodified), cpsr} + + +ASM_FUNC irqHandler + sub lr, lr, #4 + stmfd sp!, {r0-r3, r12, lr} + mov r12, #0x10000000 + orr r12, #0x1000 @ REG_IRQ_IE + ldm r12, {r1, r2} + and r1, r1, r2 + mov r3, #0x80000000 + irqHandler_find_first_lp: + clz r2, r1 + bics r1, r1, r3, lsr r2 + bne irqHandler_find_first_lp + mov r1, r3, lsr r2 + str r1, [r12, #4] @ REG_IRQ_IF + rsb r0, r2, #31 @ r0 = 31 - r2 + ldr r1, =irqHandlerTable + ldr r2, [r1, r0, lsl #2] + cmp r2, #0 + beq irqHandler_skip_processing + mrs r3, spsr + str r3, [sp, #-4]! + msr cpsr_c, #0x5F @ System mode, IRQ enabled + str lr, [sp, #-4]! + blx r2 + ldr lr, [sp], #4 + msr cpsr_c, #0xD2 @ IRQ mode, IRQ disabled + ldr r0, [sp], #4 + msr spsr_fsxc, r0 +irqHandler_skip_processing: + ldmfd sp!, {r0-r3, r12, pc}^ diff --git a/source/arm9/hardware/hardware.c b/source/arm9/hardware/hardware.c new file mode 100644 index 0000000..fc5e321 --- /dev/null +++ b/source/arm9/hardware/hardware.c @@ -0,0 +1,42 @@ +/* + * 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 . + */ + +#include "types.h" +#include "arm9/hardware/interrupt.h" +#include "arm9/hardware/ndma.h" +#include "arm9/hardware/timer.h" +#include "hardware/pxi.h" +#include "arm9/hardware/crypto.h" + + + +void hardwareInit(void) +{ + IRQ_init(); + NDMA_init(); + TIMER_init(); + PXI_init(); + AES_init(); +} + +void hardwareDeinit(void) +{ + // New 3DS K9L doesn't like FIFO counts >4 and hangs. + // Thx Nintendo + AES_deinit(); +} diff --git a/source/arm9/hardware/hid.c b/source/arm9/hardware/hid.c new file mode 100644 index 0000000..24484ad --- /dev/null +++ b/source/arm9/hardware/hid.c @@ -0,0 +1,37 @@ +/* + * This code is part of ctrulib (https://github.com/smealum/ctrulib) + */ + +#include "mem_map.h" +#include "types.h" + + +#define REG_HID_PAD (*((vu16*)(IO_MEM_ARM9_ARM11 + 0x46000)) ^ 0xFFFFu) + + +static u32 kHeld, kDown, kUp; + + + +void hidScanInput(void) +{ + u32 kOld = kHeld; + kHeld = REG_HID_PAD; + kDown = (~kOld) & kHeld; + kUp = kOld & (~kHeld); +} + +u32 hidKeysHeld(void) +{ + return kHeld; +} + +u32 hidKeysDown(void) +{ + return kDown; +} + +u32 hidKeysUp(void) +{ + return kUp; +} diff --git a/source/arm9/hardware/interrupt.c b/source/arm9/hardware/interrupt.c new file mode 100644 index 0000000..cf535df --- /dev/null +++ b/source/arm9/hardware/interrupt.c @@ -0,0 +1,59 @@ +/* + * 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 . + */ + +#include "types.h" +#include "mem_map.h" +#include "arm9/hardware/interrupt.h" + + +#define IRQ_REGS_BASE (IO_MEM_ARM9_ONLY + 0x1000) +#define REG_IRQ_IE *((vu32*)(IRQ_REGS_BASE + 0x00)) +#define REG_IRQ_IF *((vu32*)(IRQ_REGS_BASE + 0x04)) + + +IrqHandler irqHandlerTable[32] = {0}; + + + +void IRQ_init(void) +{ + REG_IRQ_IE = 0; + REG_IRQ_IF = 0xFFFFFFFFu; + + leaveCriticalSection(0u); // Abuse it to enable IRQ +} + +void IRQ_registerHandler(Interrupt id, IrqHandler handler) +{ + const u32 oldState = enterCriticalSection(); + + irqHandlerTable[id] = handler; + REG_IRQ_IE |= 1u<. + */ + +#include "types.h" +#include "arm9/fb_assert.h" +#include "arm9/hardware/ndma.h" +#include "arm9/hardware/interrupt.h" + + + +void NDMA_init(void) +{ + for(u32 i = 0; i < 8; i++) + { + REG_NDMA_CNT(i) = (REG_NDMA_CNT(i)<<1)>>1; + } + + REG_NDMA_GLOBAL_CNT = NDMA_ROUND_ROBIN(32); + + IRQ_registerHandler(IRQ_DMAC_1_7, NULL); +} + +void NDMA_copyAsync(u32 *dest, const u32 *source, u32 size) +{ + fb_assert(((u32)dest >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)dest < DTCM_BASE) || ((u32)dest >= DTCM_BASE + DTCM_SIZE))); + fb_assert(((u32)source >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)source < DTCM_BASE) || ((u32)source >= DTCM_BASE + DTCM_SIZE))); + + REG_NDMA7_SRC_ADDR = (u32)source; + REG_NDMA7_DST_ADDR = (u32)dest; + REG_NDMA7_LOG_BLK_CNT = size / 4; + REG_NDMA7_INT_CNT = NDMA_INT_SYS_FREQ; + REG_NDMA7_CNT = NDMA_ENABLE | NDMA_IRQ_ENABLE | NDMA_STARTUP_IMMEDIATE | NDMA_SRC_UPDATE_INC | NDMA_DST_UPDATE_INC; +} + +void NDMA_copy(u32 *dest, const u32 *source, u32 size) +{ + NDMA_copyAsync(dest, source, size); + + while(REG_NDMA7_CNT & NDMA_ENABLE) + { + waitForInterrupt(); + } +} + +void NDMA_fillAsync(u32 *dest, u32 value, u32 size) +{ + fb_assert(((u32)dest >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)dest < DTCM_BASE) || ((u32)dest >= DTCM_BASE + DTCM_SIZE))); + + REG_NDMA7_DST_ADDR = (u32)dest; + REG_NDMA7_LOG_BLK_CNT = size / 4; + REG_NDMA7_INT_CNT = NDMA_INT_SYS_FREQ; + REG_NDMA7_FILL_DATA = value; + REG_NDMA7_CNT = NDMA_ENABLE | NDMA_IRQ_ENABLE | NDMA_STARTUP_IMMEDIATE | NDMA_SRC_UPDATE_FILL | NDMA_DST_UPDATE_INC; +} + +void NDMA_fill(u32 *dest, u32 value, u32 size) +{ + NDMA_fillAsync(dest, value, size); + + while(REG_NDMA7_CNT & NDMA_ENABLE) + { + waitForInterrupt(); + } +} diff --git a/source/arm9/hardware/pxi.c b/source/arm9/hardware/pxi.c new file mode 100644 index 0000000..b20d501 --- /dev/null +++ b/source/arm9/hardware/pxi.c @@ -0,0 +1,78 @@ +/* + * 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 . + */ + +#include "types.h" +#include "hardware/pxi.h" +#include "arm9/hardware/interrupt.h" + + + +void PXI_init(void) +{ + REG_PXI_SYNC9 = PXI_IRQ_ENABLE; + REG_PXI_CNT9 = PXI_FLUSH_SEND_FIFO | PXI_EMPTY_FULL_ERROR | PXI_ENABLE_SEND_RECV_FIFO; + + REG_PXI_SYNC9 |= 9u<<8; + while((REG_PXI_SYNC9 & 0xFFu) != 11u); + + IRQ_registerHandler(IRQ_PXI_SYNC, NULL); +} + +void PXI_sendWord(u32 val) +{ + while(REG_PXI_CNT9 & PXI_SEND_FIFO_FULL); + REG_PXI_SEND9 = val; + REG_PXI_SYNC9 |= PXI_NOTIFY_11; +} + +bool PXI_trySendWord(u32 val) +{ + if(REG_PXI_CNT9 & PXI_SEND_FIFO_FULL) + return false; + REG_PXI_SEND9 = val; + REG_PXI_SYNC9 |= PXI_NOTIFY_11; + return true; +} + +u32 PXI_recvWord(void) +{ + while(REG_PXI_CNT9 & PXI_RECV_FIFO_EMPTY); + return REG_PXI_RECV9; +} + +u32 PXI_tryRecvWord(bool *success) +{ + if(REG_PXI_CNT9 & PXI_RECV_FIFO_EMPTY) + { + *success = false; + return 0; + } + + *success = true; + return REG_PXI_RECV9; +} + +void PXI_sendBuf(const u32 *const buf, u32 size) +{ + while(REG_PXI_CNT9 & PXI_SEND_FIFO_FULL); + for(u32 i = 0; i < size / 4; i++) + { + REG_PXI_SEND9 = buf[i]; + } + REG_PXI_SYNC9 |= PXI_NOTIFY_11; +} diff --git a/source/arm9/hardware/sdmmc.c b/source/arm9/hardware/sdmmc.c new file mode 100644 index 0000000..0310937 --- /dev/null +++ b/source/arm9/hardware/sdmmc.c @@ -0,0 +1,558 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Copyright (c) 2014-2015, Normmatt + * + * Alternatively, the contents of this file may be used under the terms + * of the GNU General Public License Version 2, as described below: + * + * This file is free software: you may copy, redistribute and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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/. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "types.h" +#include "util.h" +#include "arm9/dev.h" +#include "arm9/hardware/sdmmc.h" + +#define DATA32_SUPPORT + + +struct mmcdevice handleNAND; +struct mmcdevice handleSD; + +mmcdevice *getMMCDevice(int drive) +{ + if(drive==0) return &handleNAND; + return &handleSD; +} + +static int get_error(struct mmcdevice *ctx) +{ + return (int)((ctx->error << 29) >> 31); +} + + +static void set_target(struct mmcdevice *ctx) +{ + sdmmc_mask16(REG_SDPORTSEL,0x3,(uint16_t)ctx->devicenumber); + setckl(ctx->clk); + if(ctx->SDOPT == 0) + { + sdmmc_mask16(REG_SDOPT,0,0x8000); + } + else + { + sdmmc_mask16(REG_SDOPT,0x8000,0); + } +} + +static void sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args) +{ + const bool getSDRESP = (cmd << 15) >> 31; + uint16_t flags = (cmd << 15) >> 31; + const bool readdata = cmd & 0x20000; + const bool writedata = cmd & 0x40000; + + if(readdata || writedata) + { + flags |= TMIO_STAT0_DATAEND; + } + + ctx->error = 0; + while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working? + sdmmc_write16(REG_SDIRMASK0,0); + sdmmc_write16(REG_SDIRMASK1,0); + sdmmc_write16(REG_SDSTATUS0,0); + sdmmc_write16(REG_SDSTATUS1,0); + sdmmc_mask16(REG_DATACTL32,0x1800,0); + sdmmc_write16(REG_SDCMDARG0,args &0xFFFF); + sdmmc_write16(REG_SDCMDARG1,args >> 16); + sdmmc_write16(REG_SDCMD,cmd &0xFFFF); + + uint32_t size = ctx->size; + u32 *rDataPtr32 = (u32*)ctx->rData; + u8 *rDataPtr8 = ctx->rData; + const u32 *tDataPtr32 = (u32*)ctx->tData; + const u8 *tDataPtr8 = ctx->tData; + + bool rUseBuf = ( NULL != rDataPtr32 ); + bool tUseBuf = ( NULL != tDataPtr32 ); + + uint16_t status0 = 0; + while(1) + { + volatile uint16_t status1 = sdmmc_read16(REG_SDSTATUS1); +#ifdef DATA32_SUPPORT + volatile uint16_t ctl32 = sdmmc_read16(REG_DATACTL32); + if((ctl32 & 0x100)) +#else + if((status1 & TMIO_STAT1_RXRDY)) +#endif + { + if(readdata) + { + if(rUseBuf) + { + sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); + if(size > 0x1FF) + { + #ifdef DATA32_SUPPORT + if(!((u32)rDataPtr32 & 3)) + { + for(int i = 0; i<0x200; i+=4) + { + *rDataPtr32++ = sdmmc_read32(REG_SDFIFO32); + } + } + else + { + for(int i = 0; i<0x200; i+=4) + { + u32 data = sdmmc_read32(REG_SDFIFO32); + *rDataPtr8++ = data; + *rDataPtr8++ = data >> 8; + *rDataPtr8++ = data >> 16; + *rDataPtr8++ = data >> 24; + } + } + #else + if(!((u32)rDataPtr16 & 1)) + { + for(int i = 0; i<0x200; i+=4) + { + *rDataPtr16++ = sdmmc_read16(REG_SDFIFO); + } + } + else + { + for(int i = 0; i<0x200; i+=4) + { + u16 data = sdmmc_read16(REG_SDFIFO); + *rDataPtr8++ = data; + *rDataPtr8++ = data >> 8; + } + } + #endif + size -= 0x200; + } + } + + sdmmc_mask16(REG_DATACTL32, 0x800, 0); + } + } +#ifdef DATA32_SUPPORT + if(!(ctl32 & 0x200)) +#else + if((status1 & TMIO_STAT1_TXRQ)) +#endif + { + if(writedata) + { + if(tUseBuf) + { + sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0); + if(size > 0x1FF) + { + #ifdef DATA32_SUPPORT + if(!((u32)tDataPtr32 & 3)) + { + for(int i = 0; i<0x200; i+=4) + { + sdmmc_write32(REG_SDFIFO32, *tDataPtr32++); + } + } + else + { + for(int i = 0; i<0x200; i+=4) + { + uint32_t data = *tDataPtr8++; + data |= (uint32_t)*tDataPtr8++ << 8; + data |= (uint32_t)*tDataPtr8++ << 16; + data |= (uint32_t)*tDataPtr8++ << 24; + sdmmc_write32(REG_SDFIFO32, data); + } + } + #else + if(!((u32)tDataPtr16 & 1)) + { + for(int i = 0; i<0x200; i+=2) + { + sdmmc_write16(REG_SDFIFO, *tDataPtr16++); + } + } + else + { + for(int i = 0; i<0x200; i+=2) + { + uint16_t data = *tDataPtr8++; + data |= (uint16_t)(*tDataPtr8++ << 8); + sdmmc_write16(REG_SDFIFO, data); + } + } + #endif + size -= 0x200; + } + } + + sdmmc_mask16(REG_DATACTL32, 0x1000, 0); + } + } + if(status1 & TMIO_MASK_GW) + { + ctx->error |= 4; + break; + } + + if(!(status1 & TMIO_STAT1_CMD_BUSY)) + { + status0 = sdmmc_read16(REG_SDSTATUS0); + if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND) + { + ctx->error |= 0x1; + } + if(status0 & TMIO_STAT0_DATAEND) + { + ctx->error |= 0x2; + } + + if((status0 & flags) == flags) + break; + } + } + ctx->stat0 = sdmmc_read16(REG_SDSTATUS0); + ctx->stat1 = sdmmc_read16(REG_SDSTATUS1); + sdmmc_write16(REG_SDSTATUS0,0); + sdmmc_write16(REG_SDSTATUS1,0); + + if(getSDRESP != 0) + { + ctx->ret[0] = (uint32_t)(sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16)); + ctx->ret[1] = (uint32_t)(sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16)); + ctx->ret[2] = (uint32_t)(sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16)); + ctx->ret[3] = (uint32_t)(sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16)); + } +} + +int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, const uint8_t *in) +{ + if(handleSD.isSDHC == 0) sector_no <<= 9; + set_target(&handleSD); + sdmmc_write16(REG_SDSTOP,0x100); +#ifdef DATA32_SUPPORT + sdmmc_write16(REG_SDBLKCOUNT32,numsectors); + sdmmc_write16(REG_SDBLKLEN32,0x200); +#endif + sdmmc_write16(REG_SDBLKCOUNT,numsectors); + handleSD.tData = in; + handleSD.size = numsectors << 9; + sdmmc_send_command(&handleSD,0x52C19,sector_no); + return get_error(&handleSD); +} + +int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out) +{ + if(handleSD.isSDHC == 0) sector_no <<= 9; + set_target(&handleSD); + sdmmc_write16(REG_SDSTOP,0x100); +#ifdef DATA32_SUPPORT + sdmmc_write16(REG_SDBLKCOUNT32,numsectors); + sdmmc_write16(REG_SDBLKLEN32,0x200); +#endif + sdmmc_write16(REG_SDBLKCOUNT,numsectors); + handleSD.rData = out; + handleSD.size = numsectors << 9; + sdmmc_send_command(&handleSD,0x33C12,sector_no); + return get_error(&handleSD); +} + + + +int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out) +{ + if(handleNAND.isSDHC == 0) sector_no <<= 9; + set_target(&handleNAND); + sdmmc_write16(REG_SDSTOP,0x100); +#ifdef DATA32_SUPPORT + sdmmc_write16(REG_SDBLKCOUNT32,numsectors); + sdmmc_write16(REG_SDBLKLEN32,0x200); +#endif + sdmmc_write16(REG_SDBLKCOUNT,numsectors); + handleNAND.rData = out; + handleNAND.size = numsectors << 9; + sdmmc_send_command(&handleNAND,0x33C12,sector_no); + return get_error(&handleNAND); +} + +int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, const uint8_t *in) //experimental +{ + if(handleNAND.isSDHC == 0) sector_no <<= 9; + set_target(&handleNAND); + sdmmc_write16(REG_SDSTOP,0x100); +#ifdef DATA32_SUPPORT + sdmmc_write16(REG_SDBLKCOUNT32,numsectors); + sdmmc_write16(REG_SDBLKLEN32,0x200); +#endif + sdmmc_write16(REG_SDBLKCOUNT,numsectors); + handleNAND.tData = in; + handleNAND.size = numsectors << 9; + sdmmc_send_command(&handleNAND,0x52C19,sector_no); + return get_error(&handleNAND); +} + +static uint32_t sdmmc_calc_size(uint8_t* csd, int type) +{ + uint32_t result = 0; + if(type == -1) type = csd[14] >> 6; + switch(type) + { + case 0: + { + uint32_t block_len=csd[9]&0xf; + block_len=1u<>7)|((csd[5]&3)<<1)); + mult=1u<<(mult+2); + result=csd[8]&3; + result=(result<<8)|csd[7]; + result=(result<<2)|(csd[6]>>6); + result=(result+1)*mult*block_len/512; + } + break; + case 1: + result=csd[7]&0x3f; + result=(result<<8)|csd[6]; + result=(result<<8)|csd[5]; + result=(result+1)*1024; + break; + default: + break; //Do nothing otherwise FIXME perhaps return some error? + } + return result; +} + +void sdmmc_init() +{ + //NAND + handleNAND.isSDHC = 0; + handleNAND.SDOPT = 0; + handleNAND.res = 0; + handleNAND.initarg = 1; + handleNAND.clk = 0x80; + handleNAND.devicenumber = 1; + + //SD + handleSD.isSDHC = 0; + handleSD.SDOPT = 0; + handleSD.res = 0; + handleSD.initarg = 0; + handleSD.clk = 0x80; + handleSD.devicenumber = 0; + + *(volatile uint16_t*)0x10006100 &= 0xF7FFu; //SDDATACTL32 + *(volatile uint16_t*)0x10006100 &= 0xEFFFu; //SDDATACTL32 +#ifdef DATA32_SUPPORT + *(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32 +#else + *(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32 +#endif + *(volatile uint16_t*)0x100060D8 = (*(volatile uint16_t*)0x100060D8 & 0xFFDD) | 2; +#ifdef DATA32_SUPPORT + *(volatile uint16_t*)0x10006100 &= 0xFFFFu; //SDDATACTL32 + *(volatile uint16_t*)0x100060D8 &= 0xFFDFu; //SDDATACTL + *(volatile uint16_t*)0x10006104 = 512; //SDBLKLEN32 +#else + *(volatile uint16_t*)0x10006100 &= 0xFFFDu; //SDDATACTL32 + *(volatile uint16_t*)0x100060D8 &= 0xFFDDu; //SDDATACTL + *(volatile uint16_t*)0x10006104 = 0; //SDBLKLEN32 +#endif + *(volatile uint16_t*)0x10006108 = 1; //SDBLKCOUNT32 + *(volatile uint16_t*)0x100060E0 &= 0xFFFEu; //SDRESET + *(volatile uint16_t*)0x100060E0 |= 1u; //SDRESET + *(volatile uint16_t*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0 + *(volatile uint16_t*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1 + *(volatile uint16_t*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7 + *(volatile uint16_t*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8 + *(volatile uint16_t*)0x10006002 &= 0xFFFCu; //SDPORTSEL +#ifdef DATA32_SUPPORT + *(volatile uint16_t*)0x10006024 = 0x20; + *(volatile uint16_t*)0x10006028 = 0x40EE; +#else + *(volatile uint16_t*)0x10006024 = 0x40; //Nintendo sets this to 0x20 + *(volatile uint16_t*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE +#endif + *(volatile uint16_t*)0x10006002 &= 0xFFFCu; ////SDPORTSEL + *(volatile uint16_t*)0x10006026 = 512; //SDBLKLEN + *(volatile uint16_t*)0x10006008 = 0; //SDSTOP +} + +int Nand_Init() +{ + set_target(&handleNAND); + wait(0xF000); + + sdmmc_send_command(&handleNAND,0,0); + + do + { + do + { + sdmmc_send_command(&handleNAND,0x10701,0x100000); + } while ( !(handleNAND.error & 1) ); + } + while((handleNAND.ret[0] & 0x80000000) == 0); + + sdmmc_send_command(&handleNAND,0x10602,0x0); + if((handleNAND.error & 0x4))return -1; + + sdmmc_send_command(&handleNAND,0x10403,handleNAND.initarg << 0x10); + if((handleNAND.error & 0x4))return -1; + + sdmmc_send_command(&handleNAND,0x10609,handleNAND.initarg << 0x10); + if((handleNAND.error & 0x4))return -1; + + handleNAND.total_size = sdmmc_calc_size((uint8_t*)&handleNAND.ret[0],0); + handleNAND.clk = 1; + setckl(1); + + sdmmc_send_command(&handleNAND,0x10407,handleNAND.initarg << 0x10); + if((handleNAND.error & 0x4))return -1; + + handleNAND.SDOPT = 1; + + sdmmc_send_command(&handleNAND,0x10506,0x3B70100); + if((handleNAND.error & 0x4))return -1; + + sdmmc_send_command(&handleNAND,0x10506,0x3B90100); + if((handleNAND.error & 0x4))return -1; + + sdmmc_send_command(&handleNAND,0x1040D,handleNAND.initarg << 0x10); + if((handleNAND.error & 0x4))return -1; + + sdmmc_send_command(&handleNAND,0x10410,0x200); + if((handleNAND.error & 0x4))return -1; + + handleNAND.clk |= 0x200; + + return 0; +} + +int SD_Init() +{ + set_target(&handleSD); + + wait(0xF000); + + sdmmc_send_command(&handleSD,0,0); + sdmmc_send_command(&handleSD,0x10408,0x1AA); + uint32_t temp = (handleSD.error & 0x1) << 0x1E; + + uint32_t temp2 = 0; + + do + { + do + { + sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10); + sdmmc_send_command(&handleSD,0x10769,0x00FF8000 | temp); + temp2 = 1; + } while ( !(handleSD.error & 1) ); + } + while((handleSD.ret[0] & 0x80000000) == 0); + + if(!((handleSD.ret[0] >> 30) & 1) || !temp) + temp2 = 0; + + handleSD.isSDHC = temp2; + + sdmmc_send_command(&handleSD,0x10602,0); + if((handleSD.error & 0x4)) return -1; + + sdmmc_send_command(&handleSD,0x10403,0); + if((handleSD.error & 0x4)) return -2; + handleSD.initarg = handleSD.ret[0] >> 0x10; + + sdmmc_send_command(&handleSD,0x10609,handleSD.initarg << 0x10); + if((handleSD.error & 0x4)) return -3; + + handleSD.total_size = sdmmc_calc_size((uint8_t*)&handleSD.ret[0],-1); + handleSD.clk = 1; + setckl(1); + + sdmmc_send_command(&handleSD,0x10507,handleSD.initarg << 0x10); + if((handleSD.error & 0x4)) return -4; + + sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10); + if((handleSD.error & 0x4)) return -5; + + handleSD.SDOPT = 1; + sdmmc_send_command(&handleSD,0x10446,0x2); + if((handleSD.error & 0x4)) return -6; + + sdmmc_send_command(&handleSD,0x1040D,handleSD.initarg << 0x10); + if((handleSD.error & 0x4)) return -7; + + sdmmc_send_command(&handleSD,0x10410,0x200); + if((handleSD.error & 0x4)) return -8; + handleSD.clk |= 0x200; + + return 0; +} + +int sdmmc_get_cid(bool isNand, uint32_t *info) +{ + struct mmcdevice *device; + if(isNand) + device = &handleNAND; + else + device = &handleSD; + + set_target(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; + } + + return 0; +} diff --git a/source/arm9/hardware/spiflash.c b/source/arm9/hardware/spiflash.c new file mode 100644 index 0000000..2312a33 --- /dev/null +++ b/source/arm9/hardware/spiflash.c @@ -0,0 +1,90 @@ +/* + * 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 . + */ + +#include "mem_map.h" +#include "types.h" +#include "arm9/hardware/spiflash.h" + + +#define SPI_REGS_BUS2_BASE (IO_MEM_ARM9_ARM11 + 0x60000) +#define REG_SPI_BUS2_CNT *((vu16*)(SPI_REGS_BUS2_BASE + 0x00)) +#define REG_SPI_BUS2_DATA *((vu8* )(SPI_REGS_BUS2_BASE + 0x02)) + + + +static void spi_busy_wait() +{ + while(REG_SPI_BUS2_CNT & 0x80); +} + +static void spi_put_byte(u8 data) +{ + REG_SPI_BUS2_DATA = data; + spi_busy_wait(); +} + +static u8 spi_receive_byte() +{ + // clock out a dummy byte + REG_SPI_BUS2_DATA = 0x00; + spi_busy_wait(); + return REG_SPI_BUS2_DATA; +} + +// select spiflash if select=true, deselect otherwise +static void spiflash_select(bool select) +{ + // select device 1, enable SPI bus + REG_SPI_BUS2_CNT = 0x8100 | (select << 11); +} + +bool spiflash_get_status() +{ + u8 resp; + + spi_busy_wait(); + spiflash_select(1); + spi_put_byte(SPIFLASH_CMD_RDSR); + spiflash_select(0); + resp = spi_receive_byte(); + + if(resp & 1) return false; + return true; +} + +void spiflash_read(u32 offset, u32 size, u8 *buf) +{ + spi_busy_wait(); + spiflash_select(1); + spi_put_byte(SPIFLASH_CMD_READ); + + // write addr (24-bit, msb first) + for(int i=0; i<3; i++) + { + offset <<= 8; + spi_put_byte((offset >> 24) & 0xFF); + } + + // read bytes + for(u32 i=0; i. + */ + +#include "mem_map.h" +#include "types.h" +#include "arm9/hardware/timer.h" +#include "arm9/hardware/interrupt.h" + + +#define TIMER_REGS_BASE (IO_MEM_ARM9_ONLY + 0x3000) +#define REG_TIMER0_VAL *((vu16*)(TIMER_REGS_BASE + 0x00)) +#define REG_TIMER0_CNT *((vu16*)(TIMER_REGS_BASE + 0x02)) + +#define REG_TIMER1_VAL *((vu16*)(TIMER_REGS_BASE + 0x04)) +#define REG_TIMER1_CNT *((vu16*)(TIMER_REGS_BASE + 0x06)) + +#define REG_TIMER2_VAL *((vu16*)(TIMER_REGS_BASE + 0x08)) +#define REG_TIMER2_CNT *((vu16*)(TIMER_REGS_BASE + 0x0A)) + +#define REG_TIMER3_VAL *((vu16*)(TIMER_REGS_BASE + 0x0C)) +#define REG_TIMER3_CNT *((vu16*)(TIMER_REGS_BASE + 0x0E)) + +#define REG_TIMER_VAL(n) *((vu16*)(TIMER_REGS_BASE + 0x00 + (n * 4))) +#define REG_TIMER_CNT(n) *((vu16*)(TIMER_REGS_BASE + 0x02 + (n * 4))) + + +// For TIMER_sleep() +static u32 overflows; + + + +static void timerSleepHandler(UNUSED u32 id); + +void TIMER_init(void) +{ + for(u32 i = 0; i < 4; i++) + { + REG_TIMER_CNT(i) = 0; + } + + IRQ_registerHandler(IRQ_TIMER_3, timerSleepHandler); +} + +void TIMER_start(Timer timer, TimerPrescaler prescaler, u16 ticks, bool enableIrq) +{ + REG_TIMER_VAL(timer) = ticks; + REG_TIMER_CNT(timer) = TIMER_ENABLE | (enableIrq ? TIMER_IRQ_ENABLE : 0) | prescaler; +} + +void TIMER_stop(Timer timer) +{ + REG_TIMER_CNT(timer) = 0; +} + +void TIMER_sleep(u32 ms) +{ + REG_TIMER3_VAL = TIMER_FREQ_1024(1000.0); + overflows = ms; + + REG_TIMER3_CNT = TIMER_ENABLE | TIMER_IRQ_ENABLE | TIMER_PRESCALER_1024; + + while(REG_TIMER3_CNT & TIMER_ENABLE) + { + waitForInterrupt(); + } +} + +static void timerSleepHandler(UNUSED u32 id) +{ + overflows--; + if(!overflows) REG_TIMER3_CNT = 0; +} diff --git a/source/arm9/hid.c b/source/arm9/hid.c deleted file mode 100644 index 24484ad..0000000 --- a/source/arm9/hid.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This code is part of ctrulib (https://github.com/smealum/ctrulib) - */ - -#include "mem_map.h" -#include "types.h" - - -#define REG_HID_PAD (*((vu16*)(IO_MEM_ARM9_ARM11 + 0x46000)) ^ 0xFFFFu) - - -static u32 kHeld, kDown, kUp; - - - -void hidScanInput(void) -{ - u32 kOld = kHeld; - kHeld = REG_HID_PAD; - kDown = (~kOld) & kHeld; - kUp = kOld & (~kHeld); -} - -u32 hidKeysHeld(void) -{ - return kHeld; -} - -u32 hidKeysDown(void) -{ - return kDown; -} - -u32 hidKeysUp(void) -{ - return kUp; -} diff --git a/source/arm9/interrupt.c b/source/arm9/interrupt.c deleted file mode 100644 index 2abd146..0000000 --- a/source/arm9/interrupt.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 . - */ - -#include "types.h" -#include "mem_map.h" -#include "arm9/interrupt.h" - - -#define IRQ_REGS_BASE (IO_MEM_ARM9_ONLY + 0x1000) -#define REG_IRQ_IE *((vu32*)(IRQ_REGS_BASE + 0x00)) -#define REG_IRQ_IF *((vu32*)(IRQ_REGS_BASE + 0x04)) - - -IrqHandler irqHandlerTable[32] = {0}; - - - -void IRQ_init(void) -{ - REG_IRQ_IE = 0; - REG_IRQ_IF = 0xFFFFFFFFu; - - leaveCriticalSection(0u); // Abuse it to enable IRQ -} - -void IRQ_registerHandler(Interrupt id, IrqHandler handler) -{ - const u32 oldState = enterCriticalSection(); - - irqHandlerTable[id] = handler; - REG_IRQ_IE |= 1u<. - */ - -#include "types.h" -#include "arm9/fb_assert.h" -#include "arm9/ndma.h" -#include "arm9/interrupt.h" - - - -void NDMA_init(void) -{ - for(u32 i = 0; i < 8; i++) - { - REG_NDMA_CNT(i) = (REG_NDMA_CNT(i)<<1)>>1; - } - - REG_NDMA_GLOBAL_CNT = NDMA_ROUND_ROBIN(32); - - IRQ_registerHandler(IRQ_DMAC_1_7, NULL); -} - -void NDMA_copyAsync(u32 *dest, const u32 *source, u32 size) -{ - fb_assert(((u32)dest >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)dest < DTCM_BASE) || ((u32)dest >= DTCM_BASE + DTCM_SIZE))); - fb_assert(((u32)source >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)source < DTCM_BASE) || ((u32)source >= DTCM_BASE + DTCM_SIZE))); - - REG_NDMA7_SRC_ADDR = (u32)source; - REG_NDMA7_DST_ADDR = (u32)dest; - REG_NDMA7_LOG_BLK_CNT = size / 4; - REG_NDMA7_INT_CNT = NDMA_INT_SYS_FREQ; - REG_NDMA7_CNT = NDMA_ENABLE | NDMA_IRQ_ENABLE | NDMA_STARTUP_IMMEDIATE | NDMA_SRC_UPDATE_INC | NDMA_DST_UPDATE_INC; -} - -void NDMA_copy(u32 *dest, const u32 *source, u32 size) -{ - NDMA_copyAsync(dest, source, size); - - while(REG_NDMA7_CNT & NDMA_ENABLE) - { - waitForInterrupt(); - } -} - -void NDMA_fillAsync(u32 *dest, u32 value, u32 size) -{ - fb_assert(((u32)dest >= ITCM_BOOT9_MIRROR + ITCM_SIZE) && (((u32)dest < DTCM_BASE) || ((u32)dest >= DTCM_BASE + DTCM_SIZE))); - - REG_NDMA7_DST_ADDR = (u32)dest; - REG_NDMA7_LOG_BLK_CNT = size / 4; - REG_NDMA7_INT_CNT = NDMA_INT_SYS_FREQ; - REG_NDMA7_FILL_DATA = value; - REG_NDMA7_CNT = NDMA_ENABLE | NDMA_IRQ_ENABLE | NDMA_STARTUP_IMMEDIATE | NDMA_SRC_UPDATE_FILL | NDMA_DST_UPDATE_INC; -} - -void NDMA_fill(u32 *dest, u32 value, u32 size) -{ - NDMA_fillAsync(dest, value, size); - - while(REG_NDMA7_CNT & NDMA_ENABLE) - { - waitForInterrupt(); - } -} diff --git a/source/arm9/pxi.c b/source/arm9/pxi.c deleted file mode 100644 index 0e4fc48..0000000 --- a/source/arm9/pxi.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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 . - */ - -#include "types.h" -#include "pxi.h" -#include "arm9/interrupt.h" - - - -void PXI_init(void) -{ - REG_PXI_SYNC9 = PXI_IRQ_ENABLE; - REG_PXI_CNT9 = PXI_FLUSH_SEND_FIFO | PXI_EMPTY_FULL_ERROR | PXI_ENABLE_SEND_RECV_FIFO; - - REG_PXI_SYNC9 |= 9u<<8; - while((REG_PXI_SYNC9 & 0xFFu) != 11u); - - IRQ_registerHandler(IRQ_PXI_SYNC, NULL); -} - -void PXI_sendWord(u32 val) -{ - while(REG_PXI_CNT9 & PXI_SEND_FIFO_FULL); - REG_PXI_SEND9 = val; - REG_PXI_SYNC9 |= PXI_NOTIFY_11; -} - -bool PXI_trySendWord(u32 val) -{ - if(REG_PXI_CNT9 & PXI_SEND_FIFO_FULL) - return false; - REG_PXI_SEND9 = val; - REG_PXI_SYNC9 |= PXI_NOTIFY_11; - return true; -} - -u32 PXI_recvWord(void) -{ - while(REG_PXI_CNT9 & PXI_RECV_FIFO_EMPTY); - return REG_PXI_RECV9; -} - -u32 PXI_tryRecvWord(bool *success) -{ - if(REG_PXI_CNT9 & PXI_RECV_FIFO_EMPTY) - { - *success = false; - return 0; - } - - *success = true; - return REG_PXI_RECV9; -} - -void PXI_sendBuf(const u32 *const buf, u32 size) -{ - while(REG_PXI_CNT9 & PXI_SEND_FIFO_FULL); - for(u32 i = 0; i < size / 4; i++) - { - REG_PXI_SEND9 = buf[i]; - } - REG_PXI_SYNC9 |= PXI_NOTIFY_11; -} diff --git a/source/arm9/sdmmc.c b/source/arm9/sdmmc.c deleted file mode 100644 index d5f98b8..0000000 --- a/source/arm9/sdmmc.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - * - * Copyright (c) 2014-2015, Normmatt - * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License Version 2, as described below: - * - * This file is free software: you may copy, redistribute and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 2 of the License, or (at your - * option) any later version. - * - * This file 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/. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "types.h" -#include "util.h" -#include "arm9/dev.h" -#include "arm9/sdmmc.h" - -#define DATA32_SUPPORT - - -struct mmcdevice handleNAND; -struct mmcdevice handleSD; - -mmcdevice *getMMCDevice(int drive) -{ - if(drive==0) return &handleNAND; - return &handleSD; -} - -static int get_error(struct mmcdevice *ctx) -{ - return (int)((ctx->error << 29) >> 31); -} - - -static void set_target(struct mmcdevice *ctx) -{ - sdmmc_mask16(REG_SDPORTSEL,0x3,(uint16_t)ctx->devicenumber); - setckl(ctx->clk); - if(ctx->SDOPT == 0) - { - sdmmc_mask16(REG_SDOPT,0,0x8000); - } - else - { - sdmmc_mask16(REG_SDOPT,0x8000,0); - } -} - -static void sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args) -{ - const bool getSDRESP = (cmd << 15) >> 31; - uint16_t flags = (cmd << 15) >> 31; - const bool readdata = cmd & 0x20000; - const bool writedata = cmd & 0x40000; - - if(readdata || writedata) - { - flags |= TMIO_STAT0_DATAEND; - } - - ctx->error = 0; - while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working? - sdmmc_write16(REG_SDIRMASK0,0); - sdmmc_write16(REG_SDIRMASK1,0); - sdmmc_write16(REG_SDSTATUS0,0); - sdmmc_write16(REG_SDSTATUS1,0); - sdmmc_mask16(REG_DATACTL32,0x1800,0); - sdmmc_write16(REG_SDCMDARG0,args &0xFFFF); - sdmmc_write16(REG_SDCMDARG1,args >> 16); - sdmmc_write16(REG_SDCMD,cmd &0xFFFF); - - uint32_t size = ctx->size; - u32 *rDataPtr32 = (u32*)ctx->rData; - u8 *rDataPtr8 = ctx->rData; - const u32 *tDataPtr32 = (u32*)ctx->tData; - const u8 *tDataPtr8 = ctx->tData; - - bool rUseBuf = ( NULL != rDataPtr32 ); - bool tUseBuf = ( NULL != tDataPtr32 ); - - uint16_t status0 = 0; - while(1) - { - volatile uint16_t status1 = sdmmc_read16(REG_SDSTATUS1); -#ifdef DATA32_SUPPORT - volatile uint16_t ctl32 = sdmmc_read16(REG_DATACTL32); - if((ctl32 & 0x100)) -#else - if((status1 & TMIO_STAT1_RXRDY)) -#endif - { - if(readdata) - { - if(rUseBuf) - { - sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0); - if(size > 0x1FF) - { - #ifdef DATA32_SUPPORT - if(!((u32)rDataPtr32 & 3)) - { - for(int i = 0; i<0x200; i+=4) - { - *rDataPtr32++ = sdmmc_read32(REG_SDFIFO32); - } - } - else - { - for(int i = 0; i<0x200; i+=4) - { - u32 data = sdmmc_read32(REG_SDFIFO32); - *rDataPtr8++ = data; - *rDataPtr8++ = data >> 8; - *rDataPtr8++ = data >> 16; - *rDataPtr8++ = data >> 24; - } - } - #else - if(!((u32)rDataPtr16 & 1)) - { - for(int i = 0; i<0x200; i+=4) - { - *rDataPtr16++ = sdmmc_read16(REG_SDFIFO); - } - } - else - { - for(int i = 0; i<0x200; i+=4) - { - u16 data = sdmmc_read16(REG_SDFIFO); - *rDataPtr8++ = data; - *rDataPtr8++ = data >> 8; - } - } - #endif - size -= 0x200; - } - } - - sdmmc_mask16(REG_DATACTL32, 0x800, 0); - } - } -#ifdef DATA32_SUPPORT - if(!(ctl32 & 0x200)) -#else - if((status1 & TMIO_STAT1_TXRQ)) -#endif - { - if(writedata) - { - if(tUseBuf) - { - sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0); - if(size > 0x1FF) - { - #ifdef DATA32_SUPPORT - if(!((u32)tDataPtr32 & 3)) - { - for(int i = 0; i<0x200; i+=4) - { - sdmmc_write32(REG_SDFIFO32, *tDataPtr32++); - } - } - else - { - for(int i = 0; i<0x200; i+=4) - { - uint32_t data = *tDataPtr8++; - data |= (uint32_t)*tDataPtr8++ << 8; - data |= (uint32_t)*tDataPtr8++ << 16; - data |= (uint32_t)*tDataPtr8++ << 24; - sdmmc_write32(REG_SDFIFO32, data); - } - } - #else - if(!((u32)tDataPtr16 & 1)) - { - for(int i = 0; i<0x200; i+=2) - { - sdmmc_write16(REG_SDFIFO, *tDataPtr16++); - } - } - else - { - for(int i = 0; i<0x200; i+=2) - { - uint16_t data = *tDataPtr8++; - data |= (uint16_t)(*tDataPtr8++ << 8); - sdmmc_write16(REG_SDFIFO, data); - } - } - #endif - size -= 0x200; - } - } - - sdmmc_mask16(REG_DATACTL32, 0x1000, 0); - } - } - if(status1 & TMIO_MASK_GW) - { - ctx->error |= 4; - break; - } - - if(!(status1 & TMIO_STAT1_CMD_BUSY)) - { - status0 = sdmmc_read16(REG_SDSTATUS0); - if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND) - { - ctx->error |= 0x1; - } - if(status0 & TMIO_STAT0_DATAEND) - { - ctx->error |= 0x2; - } - - if((status0 & flags) == flags) - break; - } - } - ctx->stat0 = sdmmc_read16(REG_SDSTATUS0); - ctx->stat1 = sdmmc_read16(REG_SDSTATUS1); - sdmmc_write16(REG_SDSTATUS0,0); - sdmmc_write16(REG_SDSTATUS1,0); - - if(getSDRESP != 0) - { - ctx->ret[0] = (uint32_t)(sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16)); - ctx->ret[1] = (uint32_t)(sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16)); - ctx->ret[2] = (uint32_t)(sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16)); - ctx->ret[3] = (uint32_t)(sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16)); - } -} - -int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, const uint8_t *in) -{ - if(handleSD.isSDHC == 0) sector_no <<= 9; - set_target(&handleSD); - sdmmc_write16(REG_SDSTOP,0x100); -#ifdef DATA32_SUPPORT - sdmmc_write16(REG_SDBLKCOUNT32,numsectors); - sdmmc_write16(REG_SDBLKLEN32,0x200); -#endif - sdmmc_write16(REG_SDBLKCOUNT,numsectors); - handleSD.tData = in; - handleSD.size = numsectors << 9; - sdmmc_send_command(&handleSD,0x52C19,sector_no); - return get_error(&handleSD); -} - -int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out) -{ - if(handleSD.isSDHC == 0) sector_no <<= 9; - set_target(&handleSD); - sdmmc_write16(REG_SDSTOP,0x100); -#ifdef DATA32_SUPPORT - sdmmc_write16(REG_SDBLKCOUNT32,numsectors); - sdmmc_write16(REG_SDBLKLEN32,0x200); -#endif - sdmmc_write16(REG_SDBLKCOUNT,numsectors); - handleSD.rData = out; - handleSD.size = numsectors << 9; - sdmmc_send_command(&handleSD,0x33C12,sector_no); - return get_error(&handleSD); -} - - - -int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out) -{ - if(handleNAND.isSDHC == 0) sector_no <<= 9; - set_target(&handleNAND); - sdmmc_write16(REG_SDSTOP,0x100); -#ifdef DATA32_SUPPORT - sdmmc_write16(REG_SDBLKCOUNT32,numsectors); - sdmmc_write16(REG_SDBLKLEN32,0x200); -#endif - sdmmc_write16(REG_SDBLKCOUNT,numsectors); - handleNAND.rData = out; - handleNAND.size = numsectors << 9; - sdmmc_send_command(&handleNAND,0x33C12,sector_no); - return get_error(&handleNAND); -} - -int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, const uint8_t *in) //experimental -{ - if(handleNAND.isSDHC == 0) sector_no <<= 9; - set_target(&handleNAND); - sdmmc_write16(REG_SDSTOP,0x100); -#ifdef DATA32_SUPPORT - sdmmc_write16(REG_SDBLKCOUNT32,numsectors); - sdmmc_write16(REG_SDBLKLEN32,0x200); -#endif - sdmmc_write16(REG_SDBLKCOUNT,numsectors); - handleNAND.tData = in; - handleNAND.size = numsectors << 9; - sdmmc_send_command(&handleNAND,0x52C19,sector_no); - return get_error(&handleNAND); -} - -static uint32_t sdmmc_calc_size(uint8_t* csd, int type) -{ - uint32_t result = 0; - if(type == -1) type = csd[14] >> 6; - switch(type) - { - case 0: - { - uint32_t block_len=csd[9]&0xf; - block_len=1u<>7)|((csd[5]&3)<<1)); - mult=1u<<(mult+2); - result=csd[8]&3; - result=(result<<8)|csd[7]; - result=(result<<2)|(csd[6]>>6); - result=(result+1)*mult*block_len/512; - } - break; - case 1: - result=csd[7]&0x3f; - result=(result<<8)|csd[6]; - result=(result<<8)|csd[5]; - result=(result+1)*1024; - break; - default: - break; //Do nothing otherwise FIXME perhaps return some error? - } - return result; -} - -void sdmmc_init() -{ - //NAND - handleNAND.isSDHC = 0; - handleNAND.SDOPT = 0; - handleNAND.res = 0; - handleNAND.initarg = 1; - handleNAND.clk = 0x80; - handleNAND.devicenumber = 1; - - //SD - handleSD.isSDHC = 0; - handleSD.SDOPT = 0; - handleSD.res = 0; - handleSD.initarg = 0; - handleSD.clk = 0x80; - handleSD.devicenumber = 0; - - *(volatile uint16_t*)0x10006100 &= 0xF7FFu; //SDDATACTL32 - *(volatile uint16_t*)0x10006100 &= 0xEFFFu; //SDDATACTL32 -#ifdef DATA32_SUPPORT - *(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32 -#else - *(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32 -#endif - *(volatile uint16_t*)0x100060D8 = (*(volatile uint16_t*)0x100060D8 & 0xFFDD) | 2; -#ifdef DATA32_SUPPORT - *(volatile uint16_t*)0x10006100 &= 0xFFFFu; //SDDATACTL32 - *(volatile uint16_t*)0x100060D8 &= 0xFFDFu; //SDDATACTL - *(volatile uint16_t*)0x10006104 = 512; //SDBLKLEN32 -#else - *(volatile uint16_t*)0x10006100 &= 0xFFFDu; //SDDATACTL32 - *(volatile uint16_t*)0x100060D8 &= 0xFFDDu; //SDDATACTL - *(volatile uint16_t*)0x10006104 = 0; //SDBLKLEN32 -#endif - *(volatile uint16_t*)0x10006108 = 1; //SDBLKCOUNT32 - *(volatile uint16_t*)0x100060E0 &= 0xFFFEu; //SDRESET - *(volatile uint16_t*)0x100060E0 |= 1u; //SDRESET - *(volatile uint16_t*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0 - *(volatile uint16_t*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1 - *(volatile uint16_t*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7 - *(volatile uint16_t*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8 - *(volatile uint16_t*)0x10006002 &= 0xFFFCu; //SDPORTSEL -#ifdef DATA32_SUPPORT - *(volatile uint16_t*)0x10006024 = 0x20; - *(volatile uint16_t*)0x10006028 = 0x40EE; -#else - *(volatile uint16_t*)0x10006024 = 0x40; //Nintendo sets this to 0x20 - *(volatile uint16_t*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE -#endif - *(volatile uint16_t*)0x10006002 &= 0xFFFCu; ////SDPORTSEL - *(volatile uint16_t*)0x10006026 = 512; //SDBLKLEN - *(volatile uint16_t*)0x10006008 = 0; //SDSTOP -} - -int Nand_Init() -{ - set_target(&handleNAND); - wait(0xF000); - - sdmmc_send_command(&handleNAND,0,0); - - do - { - do - { - sdmmc_send_command(&handleNAND,0x10701,0x100000); - } while ( !(handleNAND.error & 1) ); - } - while((handleNAND.ret[0] & 0x80000000) == 0); - - sdmmc_send_command(&handleNAND,0x10602,0x0); - if((handleNAND.error & 0x4))return -1; - - sdmmc_send_command(&handleNAND,0x10403,handleNAND.initarg << 0x10); - if((handleNAND.error & 0x4))return -1; - - sdmmc_send_command(&handleNAND,0x10609,handleNAND.initarg << 0x10); - if((handleNAND.error & 0x4))return -1; - - handleNAND.total_size = sdmmc_calc_size((uint8_t*)&handleNAND.ret[0],0); - handleNAND.clk = 1; - setckl(1); - - sdmmc_send_command(&handleNAND,0x10407,handleNAND.initarg << 0x10); - if((handleNAND.error & 0x4))return -1; - - handleNAND.SDOPT = 1; - - sdmmc_send_command(&handleNAND,0x10506,0x3B70100); - if((handleNAND.error & 0x4))return -1; - - sdmmc_send_command(&handleNAND,0x10506,0x3B90100); - if((handleNAND.error & 0x4))return -1; - - sdmmc_send_command(&handleNAND,0x1040D,handleNAND.initarg << 0x10); - if((handleNAND.error & 0x4))return -1; - - sdmmc_send_command(&handleNAND,0x10410,0x200); - if((handleNAND.error & 0x4))return -1; - - handleNAND.clk |= 0x200; - - return 0; -} - -int SD_Init() -{ - set_target(&handleSD); - - wait(0xF000); - - sdmmc_send_command(&handleSD,0,0); - sdmmc_send_command(&handleSD,0x10408,0x1AA); - uint32_t temp = (handleSD.error & 0x1) << 0x1E; - - uint32_t temp2 = 0; - - do - { - do - { - sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10); - sdmmc_send_command(&handleSD,0x10769,0x00FF8000 | temp); - temp2 = 1; - } while ( !(handleSD.error & 1) ); - } - while((handleSD.ret[0] & 0x80000000) == 0); - - if(!((handleSD.ret[0] >> 30) & 1) || !temp) - temp2 = 0; - - handleSD.isSDHC = temp2; - - sdmmc_send_command(&handleSD,0x10602,0); - if((handleSD.error & 0x4)) return -1; - - sdmmc_send_command(&handleSD,0x10403,0); - if((handleSD.error & 0x4)) return -2; - handleSD.initarg = handleSD.ret[0] >> 0x10; - - sdmmc_send_command(&handleSD,0x10609,handleSD.initarg << 0x10); - if((handleSD.error & 0x4)) return -3; - - handleSD.total_size = sdmmc_calc_size((uint8_t*)&handleSD.ret[0],-1); - handleSD.clk = 1; - setckl(1); - - sdmmc_send_command(&handleSD,0x10507,handleSD.initarg << 0x10); - if((handleSD.error & 0x4)) return -4; - - sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10); - if((handleSD.error & 0x4)) return -5; - - handleSD.SDOPT = 1; - sdmmc_send_command(&handleSD,0x10446,0x2); - if((handleSD.error & 0x4)) return -6; - - sdmmc_send_command(&handleSD,0x1040D,handleSD.initarg << 0x10); - if((handleSD.error & 0x4)) return -7; - - sdmmc_send_command(&handleSD,0x10410,0x200); - if((handleSD.error & 0x4)) return -8; - handleSD.clk |= 0x200; - - return 0; -} - -int sdmmc_get_cid(bool isNand, uint32_t *info) -{ - struct mmcdevice *device; - if(isNand) - device = &handleNAND; - else - device = &handleSD; - - set_target(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; - } - - return 0; -} diff --git a/source/arm9/spiflash.c b/source/arm9/spiflash.c deleted file mode 100644 index 0fcaa9d..0000000 --- a/source/arm9/spiflash.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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 . - */ - -#include "mem_map.h" -#include "types.h" -#include "arm9/spiflash.h" - - -#define SPI_REGS_BUS2_BASE (IO_MEM_ARM9_ARM11 + 0x60000) -#define REG_SPI_BUS2_CNT *((vu16*)(SPI_REGS_BUS2_BASE + 0x00)) -#define REG_SPI_BUS2_DATA *((vu8* )(SPI_REGS_BUS2_BASE + 0x02)) - - - -static void spi_busy_wait() -{ - while(REG_SPI_BUS2_CNT & 0x80); -} - -static void spi_put_byte(u8 data) -{ - REG_SPI_BUS2_DATA = data; - spi_busy_wait(); -} - -static u8 spi_receive_byte() -{ - // clock out a dummy byte - REG_SPI_BUS2_DATA = 0x00; - spi_busy_wait(); - return REG_SPI_BUS2_DATA; -} - -// select spiflash if select=true, deselect otherwise -static void spiflash_select(bool select) -{ - // select device 1, enable SPI bus - REG_SPI_BUS2_CNT = 0x8100 | (select << 11); -} - -bool spiflash_get_status() -{ - u8 resp; - - spi_busy_wait(); - spiflash_select(1); - spi_put_byte(SPIFLASH_CMD_RDSR); - spiflash_select(0); - resp = spi_receive_byte(); - - if(resp & 1) return false; - return true; -} - -void spiflash_read(u32 offset, u32 size, u8 *buf) -{ - spi_busy_wait(); - spiflash_select(1); - spi_put_byte(SPIFLASH_CMD_READ); - - // write addr (24-bit, msb first) - for(int i=0; i<3; i++) - { - offset <<= 8; - spi_put_byte((offset >> 24) & 0xFF); - } - - // read bytes - for(u32 i=0; i. - */ - -#include -#include -#include -#include "types.h" -#include "arm9/splash.h" -#include "arm9/fmt.h" -#include "gfx.h" - - - -void lz11Decompress(const void *in, void *out, u32 size); - -void getSplashDimensions(const void *const data, u32 *const width, u32 *const height) -{ - const SplashHeader *const header = (const SplashHeader *const)data; - - if(width) *width = header->width; - if(height) *height = header->height; -} - -static bool validateSplashHeader(const SplashHeader *const header) -{ - if(memcmp(&header->magic, "SPLA", 4)) return false; - - const u32 width = header->width, height = header->height; - if(width == 0 || width > SCREEN_WIDTH_TOP || height == 0 || height > SCREEN_HEIGHT_TOP) - return false; - - const u32 flags = header->flags; - if((flags & FORMAT_INVALID) != FORMAT_RGB565) return false; - if(!(flags & FLAG_ROTATED) || flags & FLAG_SWAPPED) return false; - - return true; -} - -bool drawSplashscreen(const void *const data, s32 startX, s32 startY) -{ - const SplashHeader *const header = (const SplashHeader *const)data; - if(!validateSplashHeader(header)) return false; - - const u32 width = header->width, height = header->height; - const u32 flags = header->flags; - const bool isCompressed = flags & FLAG_COMPRESSED; - - u16 *imgData; - if(isCompressed) - { - imgData = (u16*)malloc(width * height * 2); - if(!imgData) return false; - lz11Decompress(data + sizeof(SplashHeader), imgData, width * height * 2); - } - else imgData = (u16*)(data + sizeof(SplashHeader)); - - u32 xx, yy; - if(startX < 0 || (u32)startX > SCREEN_WIDTH_TOP - width) xx = (SCREEN_WIDTH_TOP - width) / 2; - else xx = (u32)startX; - if(startY < 0 || (u32)startY > SCREEN_HEIGHT_TOP - height) yy = (SCREEN_HEIGHT_TOP - height) / 2; - else yy = (u32)startY; - - u16 *fb = (u16*)FRAMEBUF_TOP_A_1; - for(u32 x = 0; x < width; x++) - { - for(u32 y = 0; y < height; y++) - { - fb[(x + xx) * SCREEN_HEIGHT_TOP + y + yy] = imgData[x * height + y]; - } - } - - if(isCompressed) free(imgData); - - return true; -} diff --git a/source/arm9/timer.c b/source/arm9/timer.c deleted file mode 100644 index c90d4a1..0000000 --- a/source/arm9/timer.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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 . - */ - -#include "mem_map.h" -#include "types.h" -#include "arm9/timer.h" -#include "arm9/interrupt.h" - - -#define TIMER_REGS_BASE (IO_MEM_ARM9_ONLY + 0x3000) -#define REG_TIMER0_VAL *((vu16*)(TIMER_REGS_BASE + 0x00)) -#define REG_TIMER0_CNT *((vu16*)(TIMER_REGS_BASE + 0x02)) - -#define REG_TIMER1_VAL *((vu16*)(TIMER_REGS_BASE + 0x04)) -#define REG_TIMER1_CNT *((vu16*)(TIMER_REGS_BASE + 0x06)) - -#define REG_TIMER2_VAL *((vu16*)(TIMER_REGS_BASE + 0x08)) -#define REG_TIMER2_CNT *((vu16*)(TIMER_REGS_BASE + 0x0A)) - -#define REG_TIMER3_VAL *((vu16*)(TIMER_REGS_BASE + 0x0C)) -#define REG_TIMER3_CNT *((vu16*)(TIMER_REGS_BASE + 0x0E)) - -#define REG_TIMER_VAL(n) *((vu16*)(TIMER_REGS_BASE + 0x00 + (n * 4))) -#define REG_TIMER_CNT(n) *((vu16*)(TIMER_REGS_BASE + 0x02 + (n * 4))) - - -// For TIMER_sleep() -static u32 overflows; - - - -static void timerSleepHandler(UNUSED u32 id); - -void TIMER_init(void) -{ - for(u32 i = 0; i < 4; i++) - { - REG_TIMER_CNT(i) = 0; - } - - IRQ_registerHandler(IRQ_TIMER_3, timerSleepHandler); -} - -void TIMER_start(Timer timer, TimerPrescaler prescaler, u16 ticks, bool enableIrq) -{ - REG_TIMER_VAL(timer) = ticks; - REG_TIMER_CNT(timer) = TIMER_ENABLE | (enableIrq ? TIMER_IRQ_ENABLE : 0) | prescaler; -} - -void TIMER_stop(Timer timer) -{ - REG_TIMER_CNT(timer) = 0; -} - -void TIMER_sleep(u32 ms) -{ - REG_TIMER3_VAL = TIMER_FREQ_1024(1000.0); - overflows = ms; - - REG_TIMER3_CNT = TIMER_ENABLE | TIMER_IRQ_ENABLE | TIMER_PRESCALER_1024; - - while(REG_TIMER3_CNT & TIMER_ENABLE) - { - waitForInterrupt(); - } -} - -static void timerSleepHandler(UNUSED u32 id) -{ - overflows--; - if(!overflows) REG_TIMER3_CNT = 0; -}