Split CFG11 and PDN into separate headers. Also (nearly) completed them.

Reimplemented filesystem access for ARM11.
Moved ROM loading to ARM11.
This commit is contained in:
profi200 2020-06-13 00:49:30 +02:00
parent 4316ad5c85
commit aecbee03e7
No known key found for this signature in database
GPG Key ID: 17B42AE5911139F3
26 changed files with 1211 additions and 319 deletions

View File

@ -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.

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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);

View File

@ -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

67
include/fs.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@ -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);

View File

@ -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

View File

@ -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)

187
source/arm11/fs.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#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);
}

View File

@ -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

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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);
}
}

View File

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

View File

@ -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)

View File

@ -1,9 +1,13 @@
#include <string.h>
#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);

View File

@ -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,

170
source/arm11/hardware/pdn.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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);
}
}

View File

@ -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

View File

@ -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();

View File

@ -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

View File

@ -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"

274
source/arm9/fs.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <malloc.h>
#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<<i) == 0) break;
} while(++i < FS_MAX_FILES);
return i;
}
static bool isFileHandleValid(FHandle h)
{
if(h > 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<<i) == 0) break;
} while(++i < FS_MAX_DIRS);
return i;
}
static bool isDirHandleValid(DHandle h)
{
if(h > 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<<slot;
g_fsState.fHandles++;
*hOut = (FHandle)slot;
}
return res;
}
Result fRead(FHandle h, void *const buf, u32 size, u32 *const bytesRead)
{
if(!isFileHandleValid(h)) return RES_FR_INVALID_OBJECT;
UINT tmpBytesRead;
Result res = fres2Res(f_read(&g_fsState.fTable[h], buf, size, &tmpBytesRead));
if(bytesRead != NULL) *bytesRead = tmpBytesRead;
return res;
}
Result fWrite(FHandle h, const void *const buf, u32 size, u32 *const bytesWritten)
{
if(!isFileHandleValid(h)) return RES_FR_INVALID_OBJECT;
UINT tmpBytesWritten;
Result res = fres2Res(f_write(&g_fsState.fTable[h], buf, size, &tmpBytesWritten));
if(bytesWritten != NULL) *bytesWritten = tmpBytesWritten;
return res;
}
Result fSync(FHandle h)
{
if(!isFileHandleValid(h)) return RES_FR_INVALID_OBJECT;
return fres2Res(f_sync(&g_fsState.fTable[h]));
}
Result fLseek(FHandle h, u32 off)
{
if(!isFileHandleValid(h)) return RES_FR_INVALID_OBJECT;
return fres2Res(f_lseek(&g_fsState.fTable[h], off));
}
u32 fTell(FHandle h)
{
if(!isFileHandleValid(h)) return 0;
return f_tell(&g_fsState.fTable[h]);
}
u32 fSize(FHandle h)
{
if(!isFileHandleValid(h)) return 0;
return f_size(&g_fsState.fTable[h]);
}
Result fClose(FHandle h)
{
if(g_fsState.fHandles == 0 || !isFileHandleValid(h))
return RES_FR_INVALID_OBJECT;
Result res = fres2Res(f_close(&g_fsState.fTable[h]));
g_fsState.fBitmap &= ~(1u<<h);
g_fsState.fHandles--;
return res;
}
Result fStat(const char *const path, FILINFO *const fi)
{
return fres2Res(f_stat(path, fi));
}
Result fOpenDir(DHandle *const hOut, const char *const path)
{
if(hOut == NULL) return RES_INVALID_ARG;
const u32 slot = findUnusedDirSlot();
if(slot == (u32)-1) return RES_FR_TOO_MANY_OPEN_FILES;
Result res = fres2Res(f_opendir(&g_fsState.dTable[slot], path));
if(res == RES_OK)
{
g_fsState.dBitmap |= 1u<<slot;
g_fsState.dHandles++;
*hOut = (DHandle)slot;
}
return res;
}
Result fReadDir(DHandle h, FILINFO *const fi, u32 num, u32 *const entriesRead)
{
if(!isDirHandleValid(h)) return RES_FR_INVALID_OBJECT;
// TODO: Check for insanely high num?
u32 i;
DIR *const dir = &g_fsState.dTable[h];
Result res;
for(i = 0; i < num; i++)
{
res = fres2Res(f_readdir(dir, &fi[i]));
if(res != RES_OK || fi[i].fname[0] == 0) break;
}
if(entriesRead != NULL) *entriesRead = i;
return res;
}
Result fCloseDir(DHandle h)
{
if(g_fsState.dHandles == 0 || !isDirHandleValid(h))
return RES_FR_INVALID_OBJECT;
Result res = fres2Res(f_closedir(&g_fsState.dTable[h]));
g_fsState.dBitmap &= ~(1u<<h);
g_fsState.dHandles--;
return res;
}
Result fMkdir(const char *const path)
{
return fres2Res(f_mkdir(path));
}
Result fRename(const char *const old, const char *const _new)
{
return fres2Res(f_rename(old, _new));
}
Result fUnlink(const char *const path)
{
return fres2Res(f_unlink(path));
}
void fsDeinit(void)
{
for(u32 i = 0; i < FS_MAX_FILES; i++) fClose(i);
for(u32 i = 0; i < FS_MAX_DRIVES; i++) fUnmount(i);
// TODO: Deinit drives.
}

View File

@ -6,9 +6,10 @@
#include "mmio.h"
#include "arm9/hardware/ndma.h"
#include "arm9/arm7_stub.h"
#include "fatfs/ff.h"
#include "fs.h"
#include "arm9/debug.h"
#include "arm9/hardware/crypto.h"
#include "util.h"
#define LGY_REGS_BASE (IO_MEM_ARM9_ONLY + 0x18000)
@ -24,17 +25,9 @@
#define REGs_LGY_GBA_SAVE_TIMING ((vu32*)(LGY_REGS_BASE + 0x120))
#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)
static FATFS g_sd = {0};
static u32 g_saveSize = 0;
static u32 g_saveHash[8] = {0};
static char g_savePath[256] = {0};
@ -80,7 +73,7 @@ static void setupSaveType(u16 saveType)
iomemcpy(REGs_LGY_GBA_SAVE_TIMING, saveTm, 16);
}
Result LGY_prepareGbaMode(bool gbaBios, u16 saveType)
Result LGY_prepareGbaMode(bool gbaBios, u16 saveType, const char *const savePath)
{
REG_LGY_MODE = LGY_MODE_AGB;
@ -88,73 +81,23 @@ Result LGY_prepareGbaMode(bool gbaBios, u16 saveType)
setupSaveType(saveType);
Result res = RES_OK;
do
if(g_saveSize != 0)
{
u32 romSize = 0;
if(f_mount(&g_sd, "sdmc:", 1) == FR_OK)
FHandle f;
if(fOpen(&f, savePath, FA_OPEN_EXISTING | FA_READ) == RES_OK)
{
FIL f;
if(f_open(&f, "sdmc:/rom.gba", FA_OPEN_EXISTING | FA_READ) == FR_OK)
// TODO: Should we handle 0 byte files?
res = fRead(f, (void*)SAVE_LOC, MAX_SAVE_SIZE, NULL);
fClose(f);
if(res == RES_OK)
{
if((romSize = f_size(&f)) > 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;
}

View File

@ -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();
}

View File

@ -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[] =
{

49
source/fsutil.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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;
}

View File

@ -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];

View File

@ -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.