diff --git a/include/arm11/hardware/cfg11.h b/include/arm11/hardware/cfg11.h
index ddce226..db9dcbf 100644
--- a/include/arm11/hardware/cfg11.h
+++ b/include/arm11/hardware/cfg11.h
@@ -22,13 +22,59 @@
#define CFG11_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x40000)
-#define REG_CFG11_FIQ_CNT *((vu8* )(CFG11_REGS_BASE + 0x0104))
-#define REG_CFG11_SPI_CNT *((vu16*)(CFG11_REGS_BASE + 0x01C0))
-#define REG_UNK_10140400 *((vu8* )(CFG11_REGS_BASE + 0x0400))
-#define REG_UNK_10140410 *((vu32*)(CFG11_REGS_BASE + 0x0410))
-#define REG_CFG11_BOOTROM_OVERLAY_CNT *((vu8* )(CFG11_REGS_BASE + 0x0420))
-#define REG_CFG11_BOOTROM_OVERLAY_VAL *((vu32*)(CFG11_REGS_BASE + 0x0424))
-#define REG_CFG11_SOCINFO *((vu16*)(CFG11_REGS_BASE + 0x0FFC))
-#define REG_CFG11_MPCORE_CLKCNT *((vu16*)(CFG11_REGS_BASE + 0x1300))
-#define REG_CFG11_MPCORE_CNT *((vu16*)(CFG11_REGS_BASE + 0x1304))
-#define REGs_CFG11_MPCORE_BOOTCNT ((vu8* )(CFG11_REGS_BASE + 0x1310))
+#define REG_CFG11_FIQ_MASK *(( vu8*)(CFG11_REGS_BASE + 0x104))
+#define REG_CFG11_UNK105 *(( vu8*)(CFG11_REGS_BASE + 0x105)) // Debug related? Mask?
+#define REG_CFG11_UNK108 *(( vu8*)(CFG11_REGS_BASE + 0x108)) // LGY gamecard related?
+#define REG_CFG11_CDMA_CNT *(( vu8*)(CFG11_REGS_BASE + 0x10C))
+#define REG_CFG11_UNK110 *(( vu8*)(CFG11_REGS_BASE + 0x110)) // VRAM related?
+#define REG_CFG11_GPUPROT *(( vu16*)(CFG11_REGS_BASE + 0x140))
+#define REG_CFG11_WIFI_POWER *(( vu8*)(CFG11_REGS_BASE + 0x180)) // Used for flight mode?
+#define REG_CFG11_SPI_CNT *(( vu16*)(CFG11_REGS_BASE + 0x1C0))
+#define REG_CFG11_UNK200 *(( vu32*)(CFG11_REGS_BASE + 0x200)) // GPIO3 related? 8x4 bits.
+#define REG_CFG11_GPU_N3DS_CNT *(( vu8*)(CFG11_REGS_BASE + 0x400)) // New3DS-only.
+#define REG_CFG11_CDMA_PERIPHERALS *(( vu32*)(CFG11_REGS_BASE + 0x410)) // New3DS-only.
+#define REG_CFG11_BOOTROM_OVERLAY_CNT *(( vu8*)(CFG11_REGS_BASE + 0x420)) // New3DS-only.
+#define REG_CFG11_BOOTROM_OVERLAY_VAL *(( vu32*)(CFG11_REGS_BASE + 0x424)) // New3DS-only.
+#define REG_CFG11_UNK428 *(( vu8*)(CFG11_REGS_BASE + 0x428)) // New3DS-only. 1 bit. Enable CPU core 1 access to overlay regs?
+#define REG_CFG11_SOCINFO *((const vu16*)(CFG11_REGS_BASE + 0xFFC))
+
+
+// REG_CFG11_FIQ_MASK
+#define FIQ_MASK_CPU0 (1u)
+#define FIQ_MASK_CPU1 (1u<<1)
+#define FIQ_MASK_CPU2 (1u<<2) // New3DS-only.
+#define FIQ_MASK_CPU3 (1u<<3) // New3DS-only.
+
+// REG_CFG11_CDMA_CNT
+#define CDMA_CNT_MIC_E (1u)
+#define CDMA_CNT_NTRCARD_E (1u<<1)
+#define CDMA_CNT_CAM1_E (1u<<2)
+#define CDMA_CNT_CAM2_E (1u<<3)
+#define CDMA_CNT_SDIO2_E (1u<<4) // WiFi
+#define CDMA_CNT_SDIO3_E (1u<<5)
+
+// REG_CFG11_GPUPROT
+// TODO
+
+// REG_CFG11_WIFI_POWER
+#define WIFI_POWER_ON (1u)
+
+// REG_CFG11_SPI_CNT
+#define SPI_CNT_SPI1_NEW_IF (1u) // New interface (NSPI).
+#define SPI_CNT_SPI2_NEW_IF (1u<<1)
+#define SPI_CNT_SPI3_NEW_IF (1u<<2)
+
+// REG_CFG11_GPU_N3DS_CNT
+#define GPU_N3DS_CNT_N3DS_MODE (1u) // Enable access to mem extensions.
+#define GPU_N3DS_CNT_TEX_FIX (1u<<1) // Fixes some texture glitches in New3DS mode.
+
+// REG_CFG11_CDMA_PERIPHERALS
+#define CDMA_PERIPHERALS_ALL (0x3FFFFu)
+
+// REG_CFG11_BOOTROM_OVERLAY_CNT
+#define BOOTROM_OVERLAY_CNT_E (1u)
+
+// REG_CFG11_SOCINFO
+#define SOCINFO_O3DS (1u) // Also set on New3DS.
+#define SOCINFO_N3DS_PROTO (1u<<1) // Never saw the daylight?
+#define SOCINFO_N3DS (1u<<2) // Set on New3DS.
diff --git a/include/arm11/hardware/pdn.h b/include/arm11/hardware/pdn.h
new file mode 100644
index 0000000..f46f3c3
--- /dev/null
+++ b/include/arm11/hardware/pdn.h
@@ -0,0 +1,136 @@
+#pragma once
+
+/*
+ * This file is part of fastboot 3DS
+ * Copyright (C) 2020 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 PDN_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x41000)
+#define REG_PDN_CNT *((vu16*)(PDN_REGS_BASE + 0x000))
+#define REG_PDN_WAKE_ENABLE *((vu32*)(PDN_REGS_BASE + 0x008))
+#define REG_PDN_WAKE_REASON *((vu32*)(PDN_REGS_BASE + 0x00C)) // Write 1 to acknowledge and 0 to clear?
+#define REG_PDN_GPU_CNT *((vu32*)(PDN_REGS_BASE + 0x200))
+#define REG_PDN_VRAM_CNT *((vu8* )(PDN_REGS_BASE + 0x204)) // This reg doesn't seem to exist on retail hardware.
+#define REG_PDN_LCD_CNT *((vu8* )(PDN_REGS_BASE + 0x208)) // This reg doesn't seem to exist on retail hardware.
+#define REG_PDN_FCRAM_CNT *((vu8* )(PDN_REGS_BASE + 0x210))
+#define REG_PDN_I2S_CNT *((vu8* )(PDN_REGS_BASE + 0x220))
+#define REG_PDN_CAM_CNT *((vu8* )(PDN_REGS_BASE + 0x224))
+#define REG_PDN_DSP_CNT *((vu8* )(PDN_REGS_BASE + 0x230))
+#define REG_PDN_G1_CNT *((vu8* )(PDN_REGS_BASE + 0x240)) // Hantro G1 decoder.
+#define REG_PDN_MPCORE_SOCMODE *((vu16*)(PDN_REGS_BASE + 0x300))
+#define REG_PDN_MPCORE_CNT *((vu16*)(PDN_REGS_BASE + 0x304)) // Is this reg actually only vu8?
+#define REGs_PDN_MPCORE_BOOTCNT ((vu8* )(PDN_REGS_BASE + 0x310))
+
+
+// REG_PDN_CNT
+#define PDN_CNT_SLEEP (1u) // Set this bit to enter sleep mode.
+#define PDN_CNT_VRAM_OFF (1u<<15) // Set when VRAM is powered off.
+
+// REG_PDN_WAKE_ENABLE and REG_PDN_WAKE_REASON
+enum
+{
+ PDN_WAKE_PADCNT = 1u,
+ PDN_WAKE_SHELL_OPENED = 1u<<3,
+ PDN_WAKE_HEADPH_NOT_PLUGGED_IN = 1u<<4, // Really?
+ PDN_WAKE_UNK6 = 1u<<6, // DSi mode related.
+ PDN_WAKE_SDIO1 = 1u<<7,
+ PDN_WAKE_SDIO2 = 1u<<8,
+ PDN_WAKE_SDIO3 = 1u<<16,
+ // 17-28 maybe GPIO3 0-11?
+ PDN_WAKE_GAMECARD_INSERT = 1u<<29, // ?
+ PDN_WAKE_TOUCHPEN_DOWN = 1u<<30,
+ PDN_WAKE_UNK31 = 1u<<31 // Also shell related?
+};
+
+// REG_PDN_GPU_CNT
+// Note: The resets are active low.
+enum
+{
+ PDN_GPU_CNT_RST_REGS = 1u, // And more?
+ PDN_GPU_CNT_RST_PSC = 1u<<1, // ?
+ PDN_GPU_CNT_RST_GEOSHADER = 1u<<2, // ?
+ PDN_GPU_CNT_RST_RASTERIZER = 1u<<3, // ?
+ PDN_GPU_CNT_RST_PPF = 1u<<4,
+ PDN_GPU_CNT_RST_PDC = 1u<<5, // ?
+ PDN_GPU_CNT_RST_PDC2 = 1u<<6, // Maybe pixel pipeline or so?
+
+ PDN_GPU_CNT_RST_ALL = (PDN_GPU_CNT_RST_PDC2<<1) - 1
+};
+
+#define PDN_GPU_CNT_CLK_E (1u<<16)
+
+// REG_PDN_VRAM_CNT
+#define PDN_VRAM_CNT_CLK_E (1u)
+
+// REG_PDN_LCD_CNT
+#define PDN_LCD_CNT_PWR_MGR_OFF (1u) // Power management off?
+
+// REG_PDN_FCRAM_CNT
+// Note: Reset is active low.
+#define PDN_FCRAM_CNT_RST (1u)
+#define PDN_FCRAM_CNT_CLK_E (1u<<1)
+#define PDN_FCRAM_CNT_CLK_E_ACK (1u<<2) // Gets set or unset depending on CLK_E.
+
+// REG_PDN_I2S_CNT
+#define PDN_I2S_CNT_I2S_CLK1_E (1u) // ? Unused?
+#define PDN_I2S_CNT_I2S_CLK2_E (1u<<1)
+
+// REG_PDN_CAM_CNT
+#define PDN_CAM_CNT_CLK_E (1u)
+
+// REG_PDN_DSP_CNT
+// Note: Reset is active low.
+#define PDN_DSP_CNT_RST (1u)
+#define PDN_DSP_CNT_CLK_E (1u<<1)
+
+// REG_PDN_G1_CNT
+// TODO: Active low or high?
+#define PDN_G1_CNT_RST (1u)
+
+// REG_PDN_MPCORE_SOCMODE
+typedef enum
+{
+ SOCMODE_O3DS_268MHz = 0u,
+ SOCMODE_N3DS_268MHz = 1u, // Also enables FCRAM extension.
+ SOCMODE_N3DS_PROTO_268MHz = 2u, // Also enables FCRAM extension?
+ SOCMODE_N3DS_PROTO_536MHz = 3u, // Also enables FCRAM extension?
+ SOCMODE_N3DS_804MHz = 5u, // Also enables FCRAM extension.
+
+ SOCMODE_MASK = 7u
+} PdnSocmode;
+
+#define PDN_MPCORE_SOCMODE_ACK (1u<<15)
+
+// REG_PDN_MPCORE_CNT
+#define PDN_MPCORE_CNT_MEM_EXT_E (1u) // Does it actually affect all mem extensions or just QTM?
+#define PDN_MPCORE_CNT_L2C_E (1u<<8)
+
+// REGs_PDN_MPCORE_BOOTCNT
+// Note: Reset is active low.
+#define MPCORE_BOOTCNT_RST (1u) // Core 2/3 only. Reset and instruction overlay enable.
+#define MPCORE_BOOTCNT_D_OVERL_E (1u<<1) // Core 2/3 only. Data overlay enable. Also used to signal a core booted.
+#define MPCORE_BOOTCNT_RST_STAT (1u<<4)
+#define MPCORE_BOOTCNT_UNK (1u<<5)
+
+
+
+void PDN_core123Init(void);
+void PDN_setSocmode(PdnSocmode socmode);
+void PDN_poweroffCore23(void);
diff --git a/include/error_codes.h b/include/error_codes.h
index 6185e3c..b79ec71 100644
--- a/include/error_codes.h
+++ b/include/error_codes.h
@@ -12,16 +12,35 @@ typedef u32 Result;
enum
{
// Common errors.
- RES_OK = 0u,
- RES_SD_CARD_REMOVED = 1u,
- RES_MOUNT_ERR = 2u,
- RES_FILE_OPEN_ERR = 3u,
- RES_FILE_READ_ERR = 4u,
- RES_FILE_WRITE_ERR = 5u,
+ RES_OK = 0u,
+ RES_SD_CARD_REMOVED = 1u,
+ RES_INVALID_ARG = 2u,
+
+ // fatfs errors.
+ // Caution: Update fs.c on ARM9 if this changes!
+ RES_FR_DISK_ERR = 3u, /* (1) A hard error occurred in the low level disk I/O layer */
+ RES_FR_INT_ERR = 4u, /* (2) Assertion failed */
+ RES_FR_NOT_READY = 5u, /* (3) The physical drive cannot work */
+ RES_FR_NO_FILE = 6u, /* (4) Could not find the file */
+ RES_FR_NO_PATH = 7u, /* (5) Could not find the path */
+ RES_FR_INVALID_NAME = 8u, /* (6) The path name format is invalid */
+ RES_FR_DENIED = 9u, /* (7) Access denied due to prohibited access or directory full */
+ RES_FR_EXIST = 10u, /* (8) Access denied due to prohibited access */
+ RES_FR_INVALID_OBJECT = 11u, /* (9) The file/directory object is invalid */
+ RES_FR_WRITE_PROTECTED = 12u, /* (10) The physical drive is write protected */
+ RES_FR_INVALID_DRIVE = 13u, /* (11) The logical drive number is invalid */
+ RES_FR_NOT_ENABLED = 14u, /* (12) The volume has no work area */
+ RES_FR_NO_FILESYSTEM = 15u, /* (13) There is no valid FAT volume */
+ RES_FR_MKFS_ABORTED = 16u, /* (14) The f_mkfs() aborted due to any problem */
+ RES_FR_TIMEOUT = 17u, /* (15) Could not get a grant to access the volume within defined period */
+ RES_FR_LOCKED = 18u, /* (16) The operation is rejected according to the file sharing policy */
+ RES_FR_NOT_ENOUGH_CORE = 19u, /* (17) LFN working buffer could not be allocated */
+ RES_FR_TOO_MANY_OPEN_FILES = 20u, /* (18) Number of open files > FF_FS_LOCK */
+ RES_FR_INVALID_PARAMETER = 21u, /* (19) Given parameter is invalid */
// Custom errors.
- RES_ROM_TOO_BIG = MAKE_CUSTOM_ERR(0),
- RES_GBA_RTC_ERR = MAKE_CUSTOM_ERR(1)
+ RES_ROM_TOO_BIG = MAKE_CUSTOM_ERR(0),
+ RES_GBA_RTC_ERR = MAKE_CUSTOM_ERR(1)
};
#undef MAKE_CUSTOM_ERR
diff --git a/include/fs.h b/include/fs.h
new file mode 100644
index 0000000..fa9d361
--- /dev/null
+++ b/include/fs.h
@@ -0,0 +1,67 @@
+#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"
+#include "error_codes.h"
+#ifdef ARM11
+#include "../thirdparty/fatfs/ff.h"
+#else
+#include "fatfs/ff.h"
+#endif // ifdef ARM11
+
+
+#define FS_MAX_DRIVES (FF_VOLUMES)
+#define FS_DRIVE_NAMES "sdmc:/"
+#define FS_MAX_FILES (1u)
+#define FS_MAX_DIRS (1u)
+
+
+typedef enum
+{
+ FS_DRIVE_SDMC = 0u
+} FsDrive;
+
+typedef u32 FHandle;
+typedef u32 DHandle;
+
+
+
+Result fMount(FsDrive drive);
+Result fUnmount(FsDrive drive);
+Result fGetFree(FsDrive drive, u64 *const size);
+Result fOpen(FHandle *const hOut, const char *const path, u8 mode);
+Result fRead(FHandle h, void *const buf, u32 size, u32 *const bytesRead);
+Result fWrite(FHandle h, const void *const buf, u32 size, u32 *const bytesWritten);
+Result fSync(FHandle h);
+Result fLseek(FHandle h, u32 off);
+u32 fTell(FHandle h);
+u32 fSize(FHandle h);
+Result fClose(FHandle h);
+Result fStat(const char *const path, FILINFO *const fi);
+Result fOpenDir(DHandle *const hOut, const char *const path);
+Result fReadDir(DHandle h, FILINFO *const fi, u32 num, u32 *const entriesRead);
+Result fCloseDir(DHandle h);
+Result fMkdir(const char *const path);
+Result fRename(const char *const old, const char *const _new);
+Result fUnlink(const char *const path);
+
+#ifdef ARM9
+void fsDeinit(void);
+#endif // ifdef ARM9
diff --git a/include/arm11/hardware/cpu.h b/include/fsutil.h
similarity index 84%
rename from include/arm11/hardware/cpu.h
rename to include/fsutil.h
index 85a7005..80f0983 100644
--- a/include/arm11/hardware/cpu.h
+++ b/include/fsutil.h
@@ -2,7 +2,7 @@
/*
* This file is part of fastboot 3DS
- * Copyright (C) 2017 derrek, profi200
+ * Copyright (C) 2020 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
@@ -19,8 +19,8 @@
*/
#include "types.h"
+#include "error_codes.h"
-void CPU_setClock(u16 clk);
-void CPU_poweroffCore23(void);
+Result fsQuickRead(const char *const path, u32 off, void *buf, u32 size);
diff --git a/include/hardware/lgy.h b/include/hardware/lgy.h
index eda83d1..68598f8 100644
--- a/include/hardware/lgy.h
+++ b/include/hardware/lgy.h
@@ -4,9 +4,18 @@
#include "error_codes.h"
+#define MAX_ROM_SIZE (1024u * 1024 * 32)
+#define MAX_SAVE_SIZE (1024u * 128)
+#define ARM7_STUB_LOC (0x3007E00u)
+#define ARM7_STUB_LOC9 (0x80BFE00u)
+#define ROM_LOC (0x20000000u)
+#define SAVE_LOC (0x8080000u)
+
+
// REG_LGY_MODE
-#define LGY_MODE_TWL (1u)
-#define LGY_MODE_AGB (2u)
+#define LGY_MODE_TWL (1u)
+#define LGY_MODE_AGB (2u)
+#define LGY_MODE_START (1u<<15)
// REG_LGY_GBA_SAVE_TYPE
enum
@@ -94,13 +103,14 @@ typedef struct
-Result LGY_prepareGbaMode(bool gbaBios, u16 saveType);
Result LGY_setGbaRtc(const GbaRtc rtc);
Result LGY_getGbaRtc(GbaRtc *const out);
+Result LGY_backupGbaSave(void);
#ifdef ARM11
+Result LGY_prepareGbaMode(bool gbaBios, u16 saveType, const char *const romPath, const char *const savePath);
void LGY_switchMode(void);
void LGY_handleEvents(void);
void LGY_deinit(void);
#elif ARM9
-Result LGY_backupGbaSave(void);
+Result LGY_prepareGbaMode(bool gbaBios, u16 saveType, const char *const savePath);
#endif
diff --git a/include/ipc_handler.h b/include/ipc_handler.h
index c991385..6f1713a 100644
--- a/include/ipc_handler.h
+++ b/include/ipc_handler.h
@@ -37,15 +37,40 @@
enum {_CMD9_C_BASE = __COUNTER__ + 1}; // Start at 0.
typedef enum
{
- IPC_CMD9_PREPARE_GBA = MAKE_CMD9(0, 0, 2),
+ // Filesystem API.
+ IPC_CMD9_FMOUNT = MAKE_CMD9(0, 0, 1),
+ IPC_CMD9_FUNMOUNT = MAKE_CMD9(0, 0, 1),
+ IPC_CMD9_FGETFREE = MAKE_CMD9(0, 1, 1),
+ IPC_CMD9_FOPEN = MAKE_CMD9(1, 1, 1),
+ IPC_CMD9_FREAD = MAKE_CMD9(0, 2, 1),
+ IPC_CMD9_FWRITE = MAKE_CMD9(1, 1, 1),
+ IPC_CMD9_FSYNC = MAKE_CMD9(0, 0, 1),
+ IPC_CMD9_FLSEEK = MAKE_CMD9(0, 0, 2),
+ IPC_CMD9_FTELL = MAKE_CMD9(0, 0, 1),
+ IPC_CMD9_FSIZE = MAKE_CMD9(0, 0, 1),
+ IPC_CMD9_FCLOSE = MAKE_CMD9(0, 0, 1),
+ IPC_CMD9_FSTAT = MAKE_CMD9(1, 1, 0),
+ IPC_CMD9_FOPEN_DIR = MAKE_CMD9(1, 1, 0),
+ IPC_CMD9_FREAD_DIR = MAKE_CMD9(0, 2, 2),
+ IPC_CMD9_FCLOSE_DIR = MAKE_CMD9(0, 0, 1),
+ IPC_CMD9_FMKDIR = MAKE_CMD9(1, 0, 0),
+ IPC_CMD9_FRENAME = MAKE_CMD9(2, 0, 0),
+ IPC_CMD9_FUNLINK = MAKE_CMD9(1, 0, 0),
+
+ // open_agb_firm specific API.
+ IPC_CMD9_PREPARE_GBA = MAKE_CMD9(1, 0, 2),
IPC_CMD9_SET_GBA_RTC = MAKE_CMD9(0, 0, 2),
IPC_CMD9_GET_GBA_RTC = MAKE_CMD9(0, 1, 0),
+ IPC_CMD9_BACKUP_GBA_SAVE = MAKE_CMD9(0, 0, 0),
+
+ // Miscellaneous API.
IPC_CMD9_PREPARE_POWER = MAKE_CMD9(0, 0, 0)
} IpcCmd9;
enum {_CMD11_C_BASE = __COUNTER__ + 1}; // Start at 0.
typedef enum
{
+ // Miscellaneous API.
IPC_CMD11_PRINT_MSG = MAKE_CMD11(0, 0, 0), // Invalid on purpose. Will be decided later.
IPC_CMD11_PANIC = MAKE_CMD11(0, 0, 0),
IPC_CMD11_EXCEPTION = MAKE_CMD11(0, 0, 0)
diff --git a/source/arm11/fs.c b/source/arm11/fs.c
new file mode 100644
index 0000000..2bd7022
--- /dev/null
+++ b/source/arm11/fs.c
@@ -0,0 +1,187 @@
+/*
+ * 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 "types.h"
+#include "error_codes.h"
+#include "fs.h"
+#include "ipc_handler.h"
+#include "hardware/pxi.h"
+
+
+
+Result fMount(FsDrive drive)
+{
+ const u32 cmdBuf = drive;
+ return PXI_sendCmd(IPC_CMD9_FMOUNT, &cmdBuf, 1);
+}
+
+Result fUnmount(FsDrive drive)
+{
+ const u32 cmdBuf = drive;
+ return PXI_sendCmd(IPC_CMD9_FUNMOUNT, &cmdBuf, 1);
+}
+
+Result fGetFree(FsDrive drive, u64 *const size)
+{
+ u32 cmdBuf[3];
+ cmdBuf[0] = (u32)size;
+ cmdBuf[1] = sizeof(u64);
+ cmdBuf[2] = drive;
+
+ return PXI_sendCmd(IPC_CMD9_FGETFREE, cmdBuf, 3);
+}
+
+Result fOpen(FHandle *const hOut, const char *const path, u8 mode)
+{
+ u32 cmdBuf[5];
+ cmdBuf[0] = (u32)path;
+ cmdBuf[1] = strlen(path) + 1;
+ cmdBuf[2] = (u32)hOut;
+ cmdBuf[3] = sizeof(FHandle);
+ cmdBuf[4] = mode;
+
+ return PXI_sendCmd(IPC_CMD9_FOPEN, cmdBuf, 5);
+}
+
+Result fRead(FHandle h, void *const buf, u32 size, u32 *const bytesRead)
+{
+ u32 cmdBuf[5];
+ cmdBuf[0] = (u32)buf;
+ cmdBuf[1] = size;
+ cmdBuf[2] = (u32)bytesRead;
+ cmdBuf[3] = sizeof(u32);
+ cmdBuf[4] = h;
+
+ return PXI_sendCmd(IPC_CMD9_FREAD, cmdBuf, 5);
+}
+
+Result fWrite(FHandle h, const void *const buf, u32 size, u32 *const bytesWritten)
+{
+ u32 cmdBuf[5];
+ cmdBuf[0] = (u32)buf;
+ cmdBuf[1] = size;
+ cmdBuf[2] = (u32)bytesWritten;
+ cmdBuf[3] = sizeof(u32);
+ cmdBuf[4] = h;
+
+ return PXI_sendCmd(IPC_CMD9_FWRITE, cmdBuf, 5);
+}
+
+Result fSync(FHandle h)
+{
+ const u32 cmdBuf = h;
+ return PXI_sendCmd(IPC_CMD9_FSYNC, &cmdBuf, 1);
+}
+
+Result fLseek(FHandle h, u32 off)
+{
+ u32 cmdBuf[2];
+ cmdBuf[0] = h;
+ cmdBuf[1] = off;
+
+ return PXI_sendCmd(IPC_CMD9_FLSEEK, cmdBuf, 2);
+}
+
+u32 fTell(FHandle h)
+{
+ const u32 cmdBuf = h;
+ return PXI_sendCmd(IPC_CMD9_FTELL, &cmdBuf, 1);
+}
+
+u32 fSize(FHandle h)
+{
+ const u32 cmdBuf = h;
+ return PXI_sendCmd(IPC_CMD9_FSIZE, &cmdBuf, 1);
+}
+
+Result fClose(FHandle h)
+{
+ const u32 cmdBuf = h;
+ return PXI_sendCmd(IPC_CMD9_FCLOSE, &cmdBuf, 1);
+}
+
+Result fStat(const char *const path, FILINFO *const fi)
+{
+ u32 cmdBuf[4];
+ cmdBuf[0] = (u32)path;
+ cmdBuf[1] = strlen(path) + 1;
+ cmdBuf[2] = (u32)fi;
+ cmdBuf[3] = sizeof(FILINFO);
+
+ return PXI_sendCmd(IPC_CMD9_FSTAT, cmdBuf, 4);
+}
+
+Result fOpenDir(DHandle *const hOut, const char *const path)
+{
+ u32 cmdBuf[4];
+ cmdBuf[0] = (u32)path;
+ cmdBuf[1] = strlen(path) + 1;
+ cmdBuf[2] = (u32)hOut;
+ cmdBuf[3] = sizeof(DHandle);
+
+ return PXI_sendCmd(IPC_CMD9_FOPEN_DIR, cmdBuf, 4);
+}
+
+Result fReadDir(DHandle h, FILINFO *const fi, u32 num, u32 *const entriesRead)
+{
+ u32 cmdBuf[6];
+ cmdBuf[0] = (u32)fi;
+ cmdBuf[1] = sizeof(FILINFO) * num;
+ cmdBuf[2] = (u32)entriesRead;
+ cmdBuf[3] = sizeof(u32);
+ cmdBuf[4] = h;
+ cmdBuf[5] = num;
+
+ return PXI_sendCmd(IPC_CMD9_FREAD_DIR, cmdBuf, 6);
+}
+
+Result fCloseDir(DHandle h)
+{
+ const u32 cmdBuf = h;
+ return PXI_sendCmd(IPC_CMD9_FCLOSE_DIR, &cmdBuf, 1);
+}
+
+Result fMkdir(const char *const path)
+{
+ u32 cmdBuf[2];
+ cmdBuf[0] = (u32)path;
+ cmdBuf[1] = strlen(path) + 1;
+
+ return PXI_sendCmd(IPC_CMD9_FMKDIR, cmdBuf, 2);
+}
+
+Result fRename(const char *const old, const char *const _new)
+{
+ u32 cmdBuf[4];
+ cmdBuf[0] = (u32)old;
+ cmdBuf[1] = strlen(old) + 1;
+ cmdBuf[2] = (u32)_new;
+ cmdBuf[3] = strlen(_new) + 1;
+
+ return PXI_sendCmd(IPC_CMD9_FRENAME, cmdBuf, 4);
+}
+
+Result fUnlink(const char *const path)
+{
+ u32 cmdBuf[2];
+ cmdBuf[0] = (u32)path;
+ cmdBuf[1] = strlen(path) + 1;
+
+ return PXI_sendCmd(IPC_CMD9_FUNLINK, cmdBuf, 2);
+}
diff --git a/source/arm11/hardware/codec.c b/source/arm11/hardware/codec.c
index 0dafa73..4bce237 100644
--- a/source/arm11/hardware/codec.c
+++ b/source/arm11/hardware/codec.c
@@ -21,6 +21,7 @@
#include "types.h"
#include "arm11/hardware/codec.h"
#include "arm11/hardware/spi.h"
+#include "arm11/hardware/pdn.h"
#include "arm11/hardware/timer.h"
#include "arm11/hardware/gpio.h"
@@ -240,7 +241,7 @@ void CODEC_init(void)
codecSwapCalibrationData(cal); // Come the fuck on. Why is this not stored in the correct endianness?
// General codec reset + init?
- *((vu8*)0x10141220) = 2;
+ REG_PDN_I2S_CNT = PDN_I2S_CNT_I2S_CLK2_E;
codecWriteReg(0x64, 1, 1);
TIMER_sleepMs(40);
codecSwitchBank(0); // What? Dummy switch after reset?
@@ -406,7 +407,7 @@ void CODEC_deinit(void)
}
*((vu16*)0x10145000) &= ~0x8000u;
*((vu16*)0x10145002) &= ~0x8000u;
- *((vu8* )0x10141220) = 0;
+ REG_PDN_I2S_CNT = 0;
GPIO_write(GPIO_3_0, 0); // GPIO bitmask 0x40
TIMER_sleepMs(18); // Fixed 18 ms delay when unsetting this GPIO.
}
@@ -415,7 +416,7 @@ void CODEC_wakeup(void)
{
GPIO_write(GPIO_3_0, 1); // GPIO bitmask 0x40
TIMER_sleepMs(10); // Fixed 10 ms delay when setting this GPIO.
- *((vu8* )0x10141220) = 2u;
+ REG_PDN_I2S_CNT = PDN_I2S_CNT_I2S_CLK2_E;
*((vu16*)0x10145000) |= 0x8000u;
*((vu16*)0x10145002) |= 0x8000u;
//codecMaskReg(0x64, 0x45, 0, 0x30); // Output select automatic
diff --git a/source/arm11/hardware/cpu.c b/source/arm11/hardware/cpu.c
deleted file mode 100644
index b343c5b..0000000
--- a/source/arm11/hardware/cpu.c
+++ /dev/null
@@ -1,160 +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 "arm11/hardware/cpu.h"
-#include "arm.h"
-#include "arm11/hardware/interrupt.h"
-#include "arm11/hardware/cfg11.h"
-#include "arm11/start.h"
-#include "util.h"
-#include "arm11/hardware/scu.h"
-
-
-#ifdef CORE123_INIT
-static void NAKED core23Entry(void)
-{
- __cpsid(aif);
- REG_GIC_CPU_CTRL = 1;
-
- const u32 cpuId = __getCpuId();
- // Tell core 0 we are here
- if(cpuId == 3) REGs_CFG11_MPCORE_BOOTCNT[3] = 1;
- else REGs_CFG11_MPCORE_BOOTCNT[2] = 1;
-
- // Wait for IPI 2 (core 2) or IPI 3 (core 3)
- u32 tmp;
- do
- {
- __wfi();
- tmp = REG_GIC_CPU_INTACK;
- REG_GIC_CPU_EOI = tmp;
- } while(tmp != cpuId);
-
- // Jump to real entrypoint
- _start();
-}
-#endif
-
-void core123Init(void)
-{
- if(REG_CFG11_SOCINFO & 2)
- {
- REG_GIC_CPU_CTRL = 1;
- for(u32 i = 0; i < 4; i++) REGs_GIC_DIST_ENABLE_CLEAR[i] = 0xFFFFFFFFu;
- REGs_GIC_DIST_PENDING_CLEAR[2] = 0x1000000; // Interrupt ID 88
- REGs_GIC_DIST_PRI[22] = 0;
- REGs_GIC_DIST_TARGET[22] = 1;
- REGs_GIC_DIST_ENABLE_SET[2] = 0x1000000;
-
-#ifdef CORE123_INIT
- u16 clkCnt;
- // If clock modifier is 3x use clock 3x. Also enables FCRAM extension?
- if(REG_CFG11_SOCINFO & 4) clkCnt = 2<<1 | 1;
- else clkCnt = 1<<1 | 1;
-
- if((REG_CFG11_MPCORE_CLKCNT & 7) != clkCnt)
- {
- // No idea what this does
- if(REG_CFG11_SOCINFO & 4) REG_CFG11_MPCORE_CNT = 0x101;
- else REG_CFG11_MPCORE_CNT = 1;
-
- // Necessary delay
- wait(403);
-
- CPU_setClock(clkCnt);
- REGs_GIC_DIST_PENDING_CLEAR[2] = 0x1000000;
- REG_UNK_10140400 = 3; // Clock related?
- }
- REG_UNK_10140410 = 0x3FFFF; // Clock related?
-
- if((REG_SCU_CONFIG & 3) == 3)
- {
- // Set core 2/3 to normal mode (running)
- REG_SCU_CPU_STAT &= ~0b11110000;
-
- const u16 clkCnt = REG_CFG11_MPCORE_CLKCNT & 7;
- u16 tmpClkCnt;
- if(REG_CFG11_SOCINFO & 4) tmpClkCnt = 0<<1 | 1;
- else tmpClkCnt = 1<<1 | 0;
-
- if(clkCnt != tmpClkCnt)
- {
- CPU_setClock(tmpClkCnt);
- REGs_GIC_DIST_PENDING_CLEAR[2] = 0x1000000;
- }
-
- REG_CFG11_BOOTROM_OVERLAY_CNT = 1;
- REG_CFG11_BOOTROM_OVERLAY_VAL = (u32)core23Entry;
- // If not already done enable instruction and data overlays
- if(!(REGs_CFG11_MPCORE_BOOTCNT[2] & 0x10)) REGs_CFG11_MPCORE_BOOTCNT[2] = 3;
- if(!(REGs_CFG11_MPCORE_BOOTCNT[3] & 0x10)) REGs_CFG11_MPCORE_BOOTCNT[3] = 3;
- // Wait for core 2/3 to jump out of boot11
- while((REGs_CFG11_MPCORE_BOOTCNT[2] & 0x12) != 0x10);
- while((REGs_CFG11_MPCORE_BOOTCNT[3] & 0x12) != 0x10);
- REG_CFG11_BOOTROM_OVERLAY_CNT = 0; // Disable all overlays
-
- // Set clock back to original one
- if(clkCnt != tmpClkCnt) CPU_setClock(clkCnt);
- }
-
- REGs_GIC_DIST_ENABLE_CLEAR[2] = 0x1000000;
-
- // Wakeup core 2/3 and let them jump to their entrypoint.
- IRQ_softwareInterrupt(2, 0b0100);
- IRQ_softwareInterrupt(3, 0b1000);
-#else
- // Just enables the New 3DS FCRAM extension (if not already done)
- if((REG_CFG11_MPCORE_CLKCNT & 7) != 1) CPU_setClock(1);
-
- REGs_GIC_DIST_ENABLE_CLEAR[2] = 0x1000000;
-#endif
- }
-
- // Wakeup core 1
- *((vu32*)0x1FFFFFDC) = (u32)_start; // Core 1 entrypoint
- IRQ_softwareInterrupt(1, 0b0010);
-}
-
-void CPU_setClock(u16 clk)
-{
- REG_CFG11_MPCORE_CLKCNT = 0x8000 | (clk & 7);
- do
- {
- __wfi();
- } while(!(REG_CFG11_MPCORE_CLKCNT & 0x8000));
-}
-
-void CPU_poweroffCore23(void)
-{
- if(REG_CFG11_SOCINFO & 2)
- {
- REGs_CFG11_MPCORE_BOOTCNT[2] = 0;
- REGs_CFG11_MPCORE_BOOTCNT[3] = 0;
-
- REG_UNK_10140410 = 0;
- REG_UNK_10140400 = 0;
-
- REG_CFG11_MPCORE_CNT = 0;
- CPU_setClock(1);
-
- REG_SCU_CPU_STAT |= 0b1111<<4;
-
- CPU_setClock(0);
- }
-}
diff --git a/source/arm11/hardware/gfx.c b/source/arm11/hardware/gfx.c
index 5f30aeb..ae6e57e 100644
--- a/source/arm11/hardware/gfx.c
+++ b/source/arm11/hardware/gfx.c
@@ -21,6 +21,8 @@
#include "types.h"
#include "fb_assert.h"
#include "hardware/gfx.h"
+#include "arm11/hardware/cfg11.h"
+#include "arm11/hardware/pdn.h"
#include "arm11/hardware/lcd.h"
#include "arm11/hardware/gx.h"
#include "arm11/hardware/gpu_regs.h"
@@ -36,10 +38,6 @@
#include "arm11/allocator/vram.h"
-#define PDN_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x40000)
-#define REG_PDN_GPU_CNT *((vu32*)(PDN_REGS_BASE + 0x1200))
-
-
static struct
{
u16 lcdIds; // Bits 0-7 top screen, 8-15 bottom screen.
@@ -70,12 +68,12 @@ void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot)
g_gfxState.doubleBuf[0] = 1;
g_gfxState.doubleBuf[1] = 1;
- *((vu32*)0x10140140) = 0; // REG_CFG11_GPUPROT
+ REG_CFG11_GPUPROT = 0;
// Reset
- REG_PDN_GPU_CNT = 0x10000;
+ REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E;
wait(12);
- REG_PDN_GPU_CNT = 0x1007F;
+ REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E | PDN_GPU_CNT_RST_ALL;
REG_GX_GPU_CLK = 0x100;
REG_GX_PSC_VRAM = 0;
REG_GX_PSC_FILL0_CNT = 0;
@@ -178,7 +176,7 @@ void GFX_deinit(void)
REG_LCD_RST = 0;
REG_GX_PSC_VRAM = 0xF00;
REG_GX_GPU_CLK = 0;
- REG_PDN_GPU_CNT = 0x10001;
+ REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E | PDN_GPU_CNT_RST_REGS;
deallocFramebufs();
@@ -551,12 +549,12 @@ void GX_processCommandList(u32 size, const u32 *const cmdList)
REG_LCD_PDC1_SWAP = 0x70100;
REG_GX_PSC_VRAM = 0xF00;
- REG_PDN_GPU_CNT = 0x7F;
+ REG_PDN_GPU_CNT = PDN_GPU_CNT_RST_ALL;
}
void GFX_returnFromLowPowerState(void)
{
- REG_PDN_GPU_CNT = 0x1007F;
+ REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E | PDN_GPU_CNT_RST_ALL;
REG_GX_PSC_VRAM = 0;
//REG_GX_GPU_CLK = 0x70100;
REG_GX_PSC_FILL0_CNT = 0;
diff --git a/source/arm11/hardware/interrupt.c b/source/arm11/hardware/interrupt.c
index f7969d6..3dcfad5 100644
--- a/source/arm11/hardware/interrupt.c
+++ b/source/arm11/hardware/interrupt.c
@@ -180,7 +180,7 @@ void IRQ_init(void)
REG_GIC_CPU_BINPOINT = 3; // All priority bits are compared for pre-emption.
REG_GIC_CPU_CTRL = 1; // Enable the interrupt interface for this CPU.
- REG_CFG11_FIQ_CNT = 2; // Disable FIQs.
+ REG_CFG11_FIQ_MASK = FIQ_MASK_CPU3 | FIQ_MASK_CPU2 | FIQ_MASK_CPU1 | FIQ_MASK_CPU0; // Disable FIQs.
}
void IRQ_registerIsr(Interrupt id, u8 prio, u8 cpuMask, IrqIsr isr)
diff --git a/source/arm11/hardware/lgy.c b/source/arm11/hardware/lgy.c
index 64fb127..2860018 100644
--- a/source/arm11/hardware/lgy.c
+++ b/source/arm11/hardware/lgy.c
@@ -1,9 +1,13 @@
+#include
#include "types.h"
#include "hardware/lgy.h"
#include "hardware/pxi.h"
#include "ipc_handler.h"
#include "arm11/hardware/hid.h"
#include "arm11/hardware/interrupt.h"
+#include "fs.h"
+#include "hardware/cache.h"
+#include "arm11/hardware/pdn.h"
#include "arm11/hardware/mcu.h"
#include "arm11/hardware/lgyfb.h"
@@ -34,12 +38,62 @@ static void lgySleepIrqHandler(u32 intSource)
}
}
-Result LGY_prepareGbaMode(bool gbaBios, u16 saveType)
+static Result loadRom(const char *const path)
{
- const u32 cmdBuf[2] = {gbaBios, saveType};
- Result res = PXI_sendCmd(IPC_CMD9_PREPARE_GBA, cmdBuf, 2);
+ Result res;
+ FHandle f;
+ if((res = fOpen(&f, path, FA_OPEN_EXISTING | FA_READ)) == RES_OK)
+ {
+ u32 romSize;
+ if((romSize = fSize(f)) <= MAX_ROM_SIZE)
+ {
+ u8 *ptr = (u8*)ROM_LOC;
+ u32 read;
+ while((res = fRead(f, ptr, 0x100000u, &read)) == RES_OK && read == 0x100000u)
+ ptr += 0x100000u;
+
+ if(res == RES_OK)
+ {
+ // Pad ROM area with "open bus" value.
+ memset((void*)(ROM_LOC + romSize), 0xFFFFFFFFu, romSize);
+ }
+ }
+ else res = RES_ROM_TOO_BIG;
+
+ fClose(f);
+ }
+
+ return res;
+}
+
+static void setupFcramForGbaMode(void)
+{
+ // FCRAM reset and clock disable.
+ flushDCache();
+ // TODO: Unmap FCRAM.
+ while(!REG_LGY_MODE); // Wait until legacy mode is ready.
+ *((vu32*)0x10201000) &= ~1u; // Some kind of bug fix for the GBA cart emu?
+ REG_PDN_FCRAM_CNT = 0; // Set reset low (active).
+ REG_PDN_FCRAM_CNT = PDN_FCRAM_CNT_RST; // Take it out of reset.
+ while(REG_PDN_FCRAM_CNT & PDN_FCRAM_CNT_CLK_E_ACK); // Wait until clock is disabled.
+}
+
+Result LGY_prepareGbaMode(bool gbaBios, u16 saveType, const char *const romPath, const char *const savePath)
+{
+ // Load the ROM image.
+ Result res = loadRom(romPath);
if(res != RES_OK) return res;
+ // Prepare ARM9 for GBA mode + settings and save loading.
+ u32 cmdBuf[2];
+ cmdBuf[0] = (u32)savePath;
+ cmdBuf[1] = strlen(savePath) + 1;
+ cmdBuf[2] = gbaBios;
+ cmdBuf[3] = saveType;
+ res = PXI_sendCmd(IPC_CMD9_PREPARE_GBA, cmdBuf, 4);
+ if(res != RES_OK) return res;
+
+ // Setup GBA Real-Time Clock.
GbaRtc rtc;
MCU_getRTCTime((u8*)&rtc);
rtc.time = __builtin_bswap32(rtc.time)>>8;
@@ -47,18 +101,13 @@ Result LGY_prepareGbaMode(bool gbaBios, u16 saveType)
// TODO: Do we need to set day of week?
LGY_setGbaRtc(rtc);
+ // Setup Legacy Framebuffer.
LGYFB_init();
- //flushInvalidateDCache();
- // Unmap FCRAM if mapped.
-
- while(!REG_LGY_MODE); // Wait until legacy mode is ready.
- // FCRAM reset and disable.
- *((vu32*)0x10201000) &= ~1u; // Disable DRAM controller? If bit 0 set below reg pokes do nothing.
- *((vu8*)0x10141210) = 0; // Set reset low (active).
- *((vu8*)0x10141210) = 1; // Take it out of reset.
- while(*((vu8*)0x10141210) & 4u); // Wait for acknowledge?
+ // Setup FCRAM for GBA mode.
+ setupFcramForGbaMode();
+ // Setup IRQ handlers and sleep mode handling.
REG_LGY_SLEEP = 1u<<15;
IRQ_registerIsr(IRQ_LGY_SLEEP, 14, 0, lgySleepIrqHandler);
IRQ_registerIsr(IRQ_HID_PADCNT, 14, 0, lgySleepIrqHandler);
@@ -79,13 +128,7 @@ Result LGY_getGbaRtc(GbaRtc *const out)
void LGY_switchMode(void)
{
- //ee_puts("Done. Doing final switch...");
- //updateScreens();
- /*do
- {
- while(*((vu16*)0x10008004) & 0x100u); // ARM9 reg pokes
- } while(*((vu32*)0x1000800C) != 0x...);*/
- REG_LGY_MODE = 0x8000u;
+ REG_LGY_MODE = LGY_MODE_START;
}
#ifndef NDEBUG
@@ -126,12 +169,17 @@ void LGY_handleEvents(void)
//if(REG_LGY_SLEEP & 2u) REG_HID_PADCNT = REG_LGY_PADCNT;
}
+Result LGY_backupGbaSave(void)
+{
+ return PXI_sendCmd(IPC_CMD9_BACKUP_GBA_SAVE, NULL, 0);
+}
+
void LGY_deinit(void)
{
//REG_LGY_PAD_VAL = 0x1FFF; // Force all buttons not pressed.
//REG_LGY_PAD_SEL = 0x1FFF;
- // TODO: Tell ARM9 to backup the savegame instead of handling it on poweroff.
+ LGY_backupGbaSave();
LGYFB_deinit();
IRQ_unregisterIsr(IRQ_LGY_SLEEP);
diff --git a/source/arm11/hardware/mmu.c b/source/arm11/hardware/mmu.c
index 8f2c8ef..2599a7f 100644
--- a/source/arm11/hardware/mmu.c
+++ b/source/arm11/hardware/mmu.c
@@ -214,8 +214,8 @@ void setupMmu(void)
L1_TO_L2(ATTR_NORM_WRITE_BACK_ALLOC));
// FCRAM with New 3DS extension
- //mmuMapSupersections(FCRAM_BASE, FCRAM_BASE, 16, PERM_PRIV_RW_USR_NA, true,
- // ATTR_NORM_WRITE_BACK_ALLOC);
+ mmuMapSupersections(FCRAM_BASE, FCRAM_BASE, 16, PERM_PRIV_RW_USR_NA, true,
+ ATTR_NORM_WRITE_BACK_ALLOC);
// Map fastboot executable start to boot11 mirror (exception vectors)
mmuMapPages(BOOT11_MIRROR2, (u32)__start__, 1, mmuTables->l2Boot11, true,
diff --git a/source/arm11/hardware/pdn.c b/source/arm11/hardware/pdn.c
new file mode 100644
index 0000000..fb36109
--- /dev/null
+++ b/source/arm11/hardware/pdn.c
@@ -0,0 +1,170 @@
+/*
+ * This file is part of fastboot 3DS
+ * Copyright (C) 2020 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 "arm11/hardware/pdn.h"
+#include "arm11/hardware/cfg11.h"
+#include "arm.h"
+#include "arm11/hardware/interrupt.h"
+#include "arm11/start.h"
+#include "util.h"
+#include "arm11/hardware/scu.h"
+
+
+
+#ifdef CORE123_INIT
+static void NAKED core23Entry(void)
+{
+ __cpsid(aif);
+ REG_GIC_CPU_CTRL = 1;
+
+ const u32 cpuId = __getCpuId();
+ // Tell core 0 we are here
+ if(cpuId == 3) REGs_PDN_MPCORE_BOOTCNT[3] = MPCORE_BOOTCNT_RST;
+ else REGs_PDN_MPCORE_BOOTCNT[2] = MPCORE_BOOTCNT_RST;
+
+ // Wait for IPI 2 (core 2) or IPI 3 (core 3)
+ u32 tmp;
+ do
+ {
+ __wfi();
+ tmp = REG_GIC_CPU_INTACK;
+ REG_GIC_CPU_EOI = tmp;
+ } while(tmp != cpuId);
+
+ // Jump to real entrypoint
+ _start();
+}
+#endif
+
+void PDN_core123Init(void)
+{
+ if(REG_CFG11_SOCINFO & SOCINFO_N3DS_PROTO)
+ {
+ REG_GIC_CPU_CTRL = 1;
+ for(u32 i = 0; i < 4; i++) REGs_GIC_DIST_ENABLE_CLEAR[i] = 0xFFFFFFFFu;
+ REGs_GIC_DIST_PENDING_CLEAR[2] = 0x1000000; // Interrupt ID 88
+ REGs_GIC_DIST_PRI[22] = 0;
+ REGs_GIC_DIST_TARGET[22] = 1;
+ REGs_GIC_DIST_ENABLE_SET[2] = 0x1000000;
+
+#ifdef CORE123_INIT
+ u16 socmode;
+ // If non-prototype SoC use 804 MHz.
+ if(REG_CFG11_SOCINFO & SOCINFO_N3DS) socmode = SOCMODE_N3DS_804MHz;
+ else socmode = SOCMODE_N3DS_PROTO_536MHz;
+
+ if((REG_PDN_MPCORE_SOCMODE & SOCMODE_MASK) != socmode)
+ {
+ // No idea what this does
+ if(REG_CFG11_SOCINFO & SOCINFO_N3DS) REG_PDN_MPCORE_CNT = PDN_MPCORE_CNT_L2C_E | PDN_MPCORE_CNT_MEM_EXT_E;
+ else REG_PDN_MPCORE_CNT = PDN_MPCORE_CNT_MEM_EXT_E;
+
+ // Necessary delay.
+ wait(403);
+
+ PDN_setSocmode(socmode);
+ REGs_GIC_DIST_PENDING_CLEAR[2] = 0x1000000;
+ REG_CFG11_GPU_N3DS_CNT = GPU_N3DS_CNT_TEX_FIX | GPU_N3DS_CNT_N3DS_MODE;
+ }
+ REG_CFG11_CDMA_PERIPHERALS = CDMA_PERIPHERALS_ALL; // Redirect all to CDMA2.
+
+ if((REG_SCU_CONFIG & 3) == 3)
+ {
+ // Set core 2/3 to normal mode (running)
+ REG_SCU_CPU_STAT &= ~0b11110000;
+
+ const u16 socmode = REG_PDN_MPCORE_SOCMODE & SOCMODE_MASK;
+ u16 tmpSocmode;
+ if(REG_CFG11_SOCINFO & SOCINFO_N3DS) tmpSocmode = SOCMODE_N3DS_268MHz;
+ else tmpSocmode = SOCMODE_N3DS_PROTO_268MHz;
+
+ if(socmode != tmpSocmode)
+ {
+ PDN_setSocmode(tmpSocmode);
+ REGs_GIC_DIST_PENDING_CLEAR[2] = 0x1000000;
+ }
+
+ REG_CFG11_BOOTROM_OVERLAY_CNT = BOOTROM_OVERLAY_CNT_E;
+ REG_CFG11_BOOTROM_OVERLAY_VAL = (u32)core23Entry;
+ // If not already done enable instruction and data overlays
+ if(!(REGs_PDN_MPCORE_BOOTCNT[2] & MPCORE_BOOTCNT_RST_STAT))
+ {
+ REGs_PDN_MPCORE_BOOTCNT[2] = MPCORE_BOOTCNT_D_OVERL_E | MPCORE_BOOTCNT_RST;
+ }
+ if(!(REGs_PDN_MPCORE_BOOTCNT[3] & MPCORE_BOOTCNT_RST_STAT))
+ {
+ REGs_PDN_MPCORE_BOOTCNT[3] = MPCORE_BOOTCNT_D_OVERL_E | MPCORE_BOOTCNT_RST;
+ }
+ // Wait for core 2/3 to jump out of boot11
+ while((REGs_PDN_MPCORE_BOOTCNT[2] & (MPCORE_BOOTCNT_RST_STAT | MPCORE_BOOTCNT_D_OVERL_E))
+ != MPCORE_BOOTCNT_RST_STAT);
+ while((REGs_PDN_MPCORE_BOOTCNT[3] & (MPCORE_BOOTCNT_RST_STAT | MPCORE_BOOTCNT_D_OVERL_E))
+ != MPCORE_BOOTCNT_RST_STAT);
+ REG_CFG11_BOOTROM_OVERLAY_CNT = 0; // Disable all overlays
+
+ // Set clock back to original one
+ if(socmode != tmpSocmode) PDN_setSocmode(socmode);
+ }
+
+ REGs_GIC_DIST_ENABLE_CLEAR[2] = 0x1000000;
+
+ // Wakeup core 2/3 and let them jump to their entrypoint.
+ IRQ_softwareInterrupt(2, 0b0100);
+ IRQ_softwareInterrupt(3, 0b1000);
+#else
+ // Just enables the New3DS FCRAM extension (if not already done).
+ if((REG_PDN_MPCORE_SOCMODE & SOCMODE_MASK) != SOCMODE_N3DS_268MHz)
+ PDN_setSocmode(SOCMODE_N3DS_268MHz);
+
+ REGs_GIC_DIST_ENABLE_CLEAR[2] = 0x1000000;
+#endif
+ }
+
+ // Wakeup core 1
+ *((vu32*)0x1FFFFFDC) = (u32)_start; // Core 1 entrypoint
+ IRQ_softwareInterrupt(1, 0b0010);
+}
+
+void PDN_setSocmode(PdnSocmode socmode)
+{
+ REG_PDN_MPCORE_SOCMODE = PDN_MPCORE_SOCMODE_ACK | socmode;
+ do
+ {
+ __wfi();
+ } while(!(REG_PDN_MPCORE_SOCMODE & PDN_MPCORE_SOCMODE_ACK));
+}
+
+void PDN_poweroffCore23(void)
+{
+ if(REG_CFG11_SOCINFO & SOCINFO_N3DS_PROTO)
+ {
+ REGs_PDN_MPCORE_BOOTCNT[2] = 0;
+ REGs_PDN_MPCORE_BOOTCNT[3] = 0;
+
+ REG_CFG11_CDMA_PERIPHERALS = 0;
+ REG_CFG11_GPU_N3DS_CNT = 0;
+
+ REG_PDN_MPCORE_CNT = 0;
+ PDN_setSocmode(SOCMODE_N3DS_268MHz);
+
+ REG_SCU_CPU_STAT |= 0b1111<<4;
+
+ PDN_setSocmode(SOCMODE_O3DS_268MHz);
+ }
+}
diff --git a/source/arm11/hardware/spi.c b/source/arm11/hardware/spi.c
index 35c2229..0c1bdf8 100644
--- a/source/arm11/hardware/spi.c
+++ b/source/arm11/hardware/spi.c
@@ -112,7 +112,7 @@ void NSPI_init(void)
inited = true;
// Switch all 3 buses to the new interface
- REG_CFG11_SPI_CNT = 1u<<2 | 1u<<1 | 1u;
+ REG_CFG11_SPI_CNT = SPI_CNT_SPI3_NEW_IF | SPI_CNT_SPI2_NEW_IF | SPI_CNT_SPI1_NEW_IF;
SpiRegs *regs = nspiGetBusRegsBase(SPI_BUS1);
regs->NSPI_INT_MASK = NSPI_INT_TRANSF_END; // Disable interrupt 1
diff --git a/source/arm11/main.c b/source/arm11/main.c
index 8823d61..1c30f00 100644
--- a/source/arm11/main.c
+++ b/source/arm11/main.c
@@ -24,6 +24,7 @@
#include "arm11/fmt.h"
#include "arm11/power.h"
#include "hardware/gfx.h"
+#include "fs.h"
#include "arm.h"
@@ -34,10 +35,11 @@ int main(void)
GFX_setBrightness(DEFAULT_BRIGHTNESS, DEFAULT_BRIGHTNESS);
consoleInit(SCREEN_BOT, NULL);
//CODEC_init();
+ fMount(FS_DRIVE_SDMC);
ee_puts("Reading ROM and save...");
Result res;
- if((res = LGY_prepareGbaMode(false, SAVE_TYPE_SRAM_256k)) == RES_OK)
+ if((res = LGY_prepareGbaMode(false, SAVE_TYPE_SRAM_256k, "sdmc:/rom.gba", "sdmc:/rom.sav")) == RES_OK)
{
#ifdef NDEBUG
GFX_setForceBlack(false, true);
@@ -60,6 +62,7 @@ int main(void)
else printErrorWaitInput(res, 0);
LGY_deinit();
+ fUnmount(FS_DRIVE_SDMC);
CODEC_deinit();
GFX_deinit();
power_off();
diff --git a/source/arm11/start.s b/source/arm11/start.s
index 977bad4..c5c3b2c 100644
--- a/source/arm11/start.s
+++ b/source/arm11/start.s
@@ -125,7 +125,7 @@ BEGIN_ASM_FUNC _start
ldr r1, =fake_heap_end
str r0, [r1]
blx __libc_init_array @ Initialize ctors and dtors
- blx core123Init
+ blx PDN_core123Init
_start_skip_bss_init_array:
ldrh r2, =0x706 @ Disable + reset all counters. Cycle counter divider 1. IRQs disabled.
mcr p15, 0, r2, c15, c12, 0 @ Write Performance Monitor Control Register
diff --git a/source/arm11/system.c b/source/arm11/system.c
index c641590..24f44b3 100644
--- a/source/arm11/system.c
+++ b/source/arm11/system.c
@@ -25,7 +25,6 @@
#include "arm11/hardware/i2c.h"
#include "arm11/hardware/mcu.h"
#include "arm11/hardware/hid.h"
-#include "arm11/hardware/cpu.h"
#include "arm.h"
diff --git a/source/arm9/fs.c b/source/arm9/fs.c
new file mode 100644
index 0000000..b553fbf
--- /dev/null
+++ b/source/arm9/fs.c
@@ -0,0 +1,274 @@
+/*
+ * 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 "types.h"
+#include "error_codes.h"
+#include "util.h"
+#include "fs.h"
+#include "arm9/debug.h"
+#include "fatfs/ff.h"
+
+
+static const char *const g_fsPathTable[FS_MAX_DRIVES] = {FS_DRIVE_NAMES};
+static struct
+{
+ FATFS fsTable[FS_MAX_DRIVES];
+
+ FIL fTable[FS_MAX_FILES];
+ u32 fBitmap;
+ u32 fHandles;
+
+ DIR dTable[FS_MAX_DIRS];
+ u32 dBitmap;
+ u32 dHandles;
+} g_fsState = {0};
+
+
+
+static Result fres2Res(FRESULT fr)
+{
+ if(fr != FR_OK) return fr + 2;
+ else return RES_OK;
+}
+
+static u32 findUnusedFileSlot(void)
+{
+ if(g_fsState.fHandles >= FS_MAX_FILES) return (u32)-1;
+
+ u32 i = 0;
+ do
+ {
+ if((g_fsState.fBitmap & 1u< g_fsState.fHandles) return false;
+ else return true;
+}
+
+static u32 findUnusedDirSlot(void)
+{
+ if(g_fsState.dHandles >= FS_MAX_DIRS) return (u32)-1;
+
+ u32 i = 0;
+ do
+ {
+ if((g_fsState.dBitmap & 1u< g_fsState.dHandles) return false;
+ else return true;
+}
+
+Result fMount(FsDrive drive)
+{
+ if(drive >= FS_MAX_DRIVES) return RES_FR_INVALID_DRIVE;
+
+ return fres2Res(f_mount(&g_fsState.fsTable[drive], g_fsPathTable[drive], 1));
+}
+
+Result fUnmount(FsDrive drive)
+{
+ if(drive >= FS_MAX_DRIVES) return RES_FR_INVALID_DRIVE;
+
+ return fres2Res(f_mount(NULL, g_fsPathTable[drive], 0));
+}
+
+Result fGetFree(FsDrive drive, u64 *const size)
+{
+ if(drive >= FS_MAX_DRIVES) return RES_FR_INVALID_DRIVE;
+
+ DWORD freeClusters;
+ FATFS *fs;
+ Result res = fres2Res(f_getfree(g_fsPathTable[drive], &freeClusters, &fs));
+ if(res == RES_OK)
+ {
+ if(size) *size = (u64)(freeClusters * fs->csize) * 512u;
+ }
+
+ return res;
+}
+
+Result fOpen(FHandle *const hOut, const char *const path, u8 mode)
+{
+ if(hOut == NULL) return RES_INVALID_ARG;
+ const u32 slot = findUnusedFileSlot();
+ if(slot == (u32)-1) return RES_FR_TOO_MANY_OPEN_FILES;
+
+ Result res = fres2Res(f_open(&g_fsState.fTable[slot], path, mode));
+ if(res == RES_OK)
+ {
+ g_fsState.fBitmap |= 1u< MAX_ROM_SIZE)
- {
- f_close(&f);
- res = RES_ROM_TOO_BIG;
- break;
- }
-
- u8 *ptr = (u8*)ROM_LOC;
- UINT read;
- FRESULT fres;
- while((fres = f_read(&f, ptr, 0x100000u, &read)) == FR_OK && read == 0x100000u)
- ptr += 0x100000u;
-
- f_close(&f);
-
- if(fres != FR_OK)
- {
- res = RES_FILE_READ_ERR;
- break;
- }
- }
- else
- {
- res = RES_FILE_OPEN_ERR;
- break;
- }
-
- if(g_saveSize != 0)
- {
- if(f_open(&f, "sdmc:/rom.sav", FA_OPEN_EXISTING | FA_READ) == FR_OK)
- {
- UINT read;
- FRESULT fres = f_read(&f, (void*)SAVE_LOC, MAX_SAVE_SIZE, &read);
-
- f_close(&f);
-
- if(fres != FR_OK)
- {
- res = RES_FILE_READ_ERR;
- break;
- }
-
- sha((u32*)SAVE_LOC, g_saveSize, g_saveHash, SHA_INPUT_BIG | SHA_MODE_256, SHA_OUTPUT_BIG);
- }
- else NDMA_fill((u32*)SAVE_LOC, 0xFFFFFFFFu, g_saveSize);
+ sha((u32*)SAVE_LOC, g_saveSize, g_saveHash, SHA_INPUT_BIG | SHA_MODE_256, SHA_OUTPUT_BIG);
+ strncpy_s(g_savePath, savePath, 255, 256);
}
}
- else
- {
- res = RES_MOUNT_ERR;
- break;
- }
-
- // Pad ROM area with "open bus" value.
- if(romSize < MAX_ROM_SIZE)
- NDMA_fill((u32*)(ROM_LOC + romSize), 0xFFFFFFFFu, MAX_ROM_SIZE - romSize);
- } while(0);
-
- // Should we unmount on non-mount error here?
+ else NDMA_fill((u32*)SAVE_LOC, 0xFFFFFFFFu, g_saveSize);
+ }
return res;
}
@@ -197,7 +140,6 @@ Result LGY_getGbaRtc(GbaRtc *const out)
Result LGY_backupGbaSave(void)
{
Result res = RES_OK;
-
if(g_saveSize != 0)
{
// Enable savegame mem region.
@@ -205,25 +147,19 @@ Result LGY_backupGbaSave(void)
u32 newHash[8];
sha((u32*)SAVE_LOC, g_saveSize, newHash, SHA_INPUT_BIG | SHA_MODE_256, SHA_OUTPUT_BIG);
- if(memcmp(g_saveHash, newHash, 32) != 0) // Backup save if it changed.
+ if(memcmp(g_saveHash, newHash, 32) != 0) // Backup save if changed.
{
- FIL f;
- if(f_open(&f, "sdmc:/rom.sav", FA_OPEN_ALWAYS | FA_WRITE) == FR_OK)
+ FHandle f;
+ if((res = fOpen(&f, g_savePath, FA_OPEN_ALWAYS | FA_WRITE)) == RES_OK)
{
- UINT written;
- if(f_write(&f, (void*)SAVE_LOC, g_saveSize, &written) != FR_OK)
- res = RES_FILE_WRITE_ERR;
-
- f_close(&f);
+ res = fWrite(f, (void*)SAVE_LOC, g_saveSize, NULL);
+ fClose(f);
}
- else res = RES_FILE_OPEN_ERR;
}
// Disable savegame mem region.
REG_LGY_GBA_SAVE_MAP = LGY_SAVE_MAP_7;
}
- f_mount(NULL, "sdmc:", 0);
-
return res;
}
diff --git a/source/arm9/ipc_handler.c b/source/arm9/ipc_handler.c
index b4f8cfa..440abd9 100644
--- a/source/arm9/ipc_handler.c
+++ b/source/arm9/ipc_handler.c
@@ -19,6 +19,7 @@
#include "types.h"
#include "ipc_handler.h"
#include "hardware/cache.h"
+#include "fs.h"
#include "hardware/lgy.h"
#include "arm9/debug.h"
@@ -35,8 +36,65 @@ u32 IPC_handleCmd(u8 cmdId, u32 inBufs, u32 outBufs, const u32 *const buf)
u32 result = 0;
switch(cmdId)
{
+ // Filesystem API.
+ case IPC_CMD_ID_MASK(IPC_CMD9_FMOUNT):
+ result = fMount(buf[0]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FUNMOUNT):
+ result = fUnmount(buf[0]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FGETFREE):
+ result = fGetFree(buf[2], (u64*)buf[0]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FOPEN):
+ result = fOpen((FHandle*)buf[2], (const char *const)buf[0], buf[4]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FREAD):
+ result = fRead(buf[4], (void *const)buf[0], buf[1], (u32 *const)buf[2]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FWRITE):
+ result = fWrite(buf[4], (const void *const)buf[0], buf[1], (u32 *const)buf[2]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FSYNC):
+ result = fSync(buf[0]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FLSEEK):
+ result = fLseek(buf[0], buf[1]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FTELL):
+ result = fTell(buf[0]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FSIZE):
+ result = fSize(buf[0]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FCLOSE):
+ result = fClose(buf[0]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FSTAT):
+ result = fStat((const char *const)buf[0], (FILINFO *const)buf[2]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FOPEN_DIR):
+ result = fOpenDir((DHandle *const)buf[2], (const char *const)buf[0]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FREAD_DIR):
+ result = fReadDir(buf[4], (FILINFO *const)buf[0], buf[5], (u32 *const)buf[2]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FCLOSE_DIR):
+ result = fCloseDir(buf[0]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FMKDIR):
+ result = fMkdir((const char *const)buf[0]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FRENAME):
+ result = fRename((const char *const)buf[0], (const char *const)buf[2]);
+ break;
+ case IPC_CMD_ID_MASK(IPC_CMD9_FUNLINK):
+ result = fUnlink((const char *const)buf[0]);
+ break;
+
+ // open_agb_firm specific API.
case IPC_CMD_ID_MASK(IPC_CMD9_PREPARE_GBA):
- result = LGY_prepareGbaMode(buf[0], buf[1]);
+ result = LGY_prepareGbaMode(buf[2], buf[3], (const char *const)buf[0]);
break;
case IPC_CMD_ID_MASK(IPC_CMD9_SET_GBA_RTC):
result = LGY_setGbaRtc(*((GbaRtc*)buf));
@@ -44,9 +102,13 @@ u32 IPC_handleCmd(u8 cmdId, u32 inBufs, u32 outBufs, const u32 *const buf)
case IPC_CMD_ID_MASK(IPC_CMD9_GET_GBA_RTC):
result = LGY_getGbaRtc((GbaRtc*)buf[0]);
break;
- case IPC_CMD_ID_MASK(IPC_CMD9_PREPARE_POWER):
+ case IPC_CMD_ID_MASK(IPC_CMD9_BACKUP_GBA_SAVE):
result = LGY_backupGbaSave();
break;
+
+ // Miscellaneous API.
+ case IPC_CMD_ID_MASK(IPC_CMD9_PREPARE_POWER):
+ break;
default:
panic();
}
diff --git a/source/error_codes.c b/source/error_codes.c
index 806a474..57ad618 100644
--- a/source/error_codes.c
+++ b/source/error_codes.c
@@ -15,10 +15,28 @@ void printError(Result res)
{
"OK",
"SD card removed",
- "Failed to mount drive",
- "Failed to open file",
- "Failed to read file",
- "Failed to write file"
+ "Invalid argument",
+
+ // fatfs errors.
+ "fatfs disk error",
+ "fatfs assertion failed",
+ "fatfs disk not ready",
+ "fatfs file not found",
+ "fatfs path not found",
+ "fatfs invalid path name",
+ "fatfs access denied",
+ "fatfs already exists",
+ "fatfs invalid file/directory object",
+ "fatfs drive write protected",
+ "fatfs invalid drive",
+ "fatfs drive not mounted",
+ "fatfs no filesystem",
+ "fatfs f_mkfs() aborted",
+ "fatfs thread lock timeout",
+ "fatfs file locked",
+ "fatfs not enough memory",
+ "fatfs too many open objects",
+ "fatfs invalid parameter"
};
static const char *const custom[] =
{
diff --git a/source/fsutil.c b/source/fsutil.c
new file mode 100644
index 0000000..d42da94
--- /dev/null
+++ b/source/fsutil.c
@@ -0,0 +1,49 @@
+/*
+ * This file is part of fastboot 3DS
+ * Copyright (C) 2020 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 "fsutil.h"
+#include "fs.h"
+
+
+#define BLOCK_SIZE (1024u * 1024)
+
+
+
+Result fsQuickRead(const char *const path, u32 off, void *buf, u32 size)
+{
+ Result res;
+ FHandle f;
+ if((res = fOpen(&f, path, FA_OPEN_EXISTING | FA_READ)) == RES_OK)
+ {
+ if((res = fLseek(f, off)) == RES_OK)
+ {
+ u32 totalRead = 0;
+ u32 read;
+ while(size > totalRead && (res = fRead(f, buf, BLOCK_SIZE, &read)) == RES_OK && read == BLOCK_SIZE)
+ {
+ buf += read;
+ totalRead += read;
+ }
+ }
+
+ fClose(f);
+ }
+
+ return res;
+}
diff --git a/source/hardware/pxi.c b/source/hardware/pxi.c
index 2185bde..ad71416 100644
--- a/source/hardware/pxi.c
+++ b/source/hardware/pxi.c
@@ -114,6 +114,10 @@ u32 PXI_sendCmd(u32 cmd, const u32 *buf, u32 words)
const IpcBuffer *const inBuf = (IpcBuffer*)&buf[i * sizeof(IpcBuffer) / 4];
if(inBuf->ptr && inBuf->size) cleanDCacheRange(inBuf->ptr, inBuf->size);
}
+ // Edge case:
+ // memset() 256 bytes string buffer, fRead() 256 bytes from 10 bytes file and fWrite() them to another
+ // file. The buffer will be filled with garbage where it wasn't overwritten because of the invalidate.
+ // TODO: Should we flush here instead?
for(u32 i = inBufs; i < inBufs + outBufs; i++)
{
const IpcBuffer *const outBuf = (IpcBuffer*)&buf[i * sizeof(IpcBuffer) / 4];
@@ -132,7 +136,7 @@ u32 PXI_sendCmd(u32 cmd, const u32 *buf, u32 words)
#ifdef ARM11
// The CPU may do speculative prefetches of data after the first invalidation
- // so we need to do it again. Not sure if this is a ARMv6+ thing.
+ // so we need to do it again.
for(u32 i = inBufs; i < inBufs + outBufs; i++)
{
const IpcBuffer *const outBuf = (IpcBuffer*)&buf[i * sizeof(IpcBuffer) / 4];
diff --git a/thirdparty/fatfs/ffconf.h b/thirdparty/fatfs/ffconf.h
index e377cab..dc04940 100644
--- a/thirdparty/fatfs/ffconf.h
+++ b/thirdparty/fatfs/ffconf.h
@@ -15,7 +15,7 @@
/ and optional writing functions as well. */
-#define FF_FS_MINIMIZE 1
+#define FF_FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions.
/
/ 0: Basic functions are fully enabled.