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;
-}