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.