Hardcode buffers, lock sector cache, use fastfs

This commit is contained in:
shchmue 2020-05-10 13:28:54 -06:00
parent 9130c4b69c
commit 3705b5f228
6 changed files with 325 additions and 57 deletions

View file

@ -28,60 +28,74 @@
/* --- DRAM START --- */ /* --- DRAM START --- */
#define DRAM_START 0x80000000 #define DRAM_START 0x80000000
/* Do not write anything in this area */ #define HOS_RSVD 0x1000000 // Do not write anything in this area.
#define NYX_LOAD_ADDR 0x81000000
#define NYX_SZ_MAX 0x1000000
/* Stack theoretical max: 220MB */
#define IPL_STACK_TOP 0x90010000
#define IPL_HEAP_START 0x90020000
#define IPL_HEAP_SZ 0x24FE0000 // 592MB.
/* --- Gap: 0xB5000000 - 0xB5FFFFFF --- */
// SDMMC DMA buffers #define NYX_LOAD_ADDR 0x81000000
#define SDXC_BUF_ALIGNED 0xB6000000 #define NYX_SZ_MAX 0x1000000 // 16MB
#define MIXD_BUF_ALIGNED 0xB7000000 /* --- Gap: 0x82000000 - 0x82FFFFFF --- */
#define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED
#define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used). /* Stack theoretical max: 33MB */
#define SDMMC_UPPER_BUFFER 0xB8000000 #define IPL_STACK_TOP 0x83100000
#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB. #define IPL_HEAP_START 0x84000000
#define IPL_HEAP_SZ 0x20000000 // 512MB.
/* --- Gap: 1040MB 0xA4000000 - 0xE4FFFFFF --- */
// Virtual disk / Chainloader buffers. // Virtual disk / Chainloader buffers.
#define RAM_DISK_ADDR 0xC1000000 #define RAM_DISK_ADDR 0xA4000000
#define RAM_DISK_SZ 0x20000000 #define RAM_DISK_SZ 0x41000000 // 1040MB.
//#define DRAM_LIB_ADDR 0xE0000000 //#define DRAM_LIB_ADDR 0xE0000000
/* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading. /* --- Chnldr: 252MB 0xC03C0000 - 0xCFFFFFFF --- */ //! Only used when chainloading.
/* --- Gap: 464MB 0xD0000000 - 0xECFFFFFF --- */
// SDMMC DMA buffers 1
#define SDMMC_UPPER_BUFFER 0xE5000000
#define SDMMC_UP_BUF_SZ 0x8000000 // 128MB.
// Nyx buffers. // Nyx buffers.
#define NYX_STORAGE_ADDR 0xED000000 #define NYX_STORAGE_ADDR 0xED000000
#define NYX_RES_ADDR 0xEE000000 #define NYX_RES_ADDR 0xEE000000
#define NYX_RES_SZ 0x1000000 // 16MB.
// Framebuffer addresses. // SDMMC DMA buffers 2
#define IPL_FB_ADDRESS 0xF0000000 #define SDXC_BUF_ALIGNED 0xEF000000
#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4. #define MIXD_BUF_ALIGNED 0xF0000000
#define LOG_FB_ADDRESS 0xF0400000 #define EMMC_BUF_ALIGNED MIXD_BUF_ALIGNED
#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4. #define SDMMC_DMA_BUF_SZ 0x1000000 // 16MB (4MB currently used).
#define NYX_FB_ADDRESS 0xF0800000
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
// Nyx LvGL buffers. // Nyx LvGL buffers.
#define NYX_LV_VDB_ADR 0xF0C00000 #define NYX_LV_VDB_ADR 0xF1000000
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4. #define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
#define NYX_LV_MEM_ADR 0xF1000000 #define NYX_LV_MEM_ADR 0xF1400000
#define NYX_LV_MEM_SZ 0x8000000 #define NYX_LV_MEM_SZ 0x6600000 // 70MB.
// Framebuffer addresses.
#define IPL_FB_ADDRESS 0xF5A00000
#define IPL_FB_SZ 0x384000 // 720 x 1280 x 4.
#define LOG_FB_ADDRESS 0xF5E00000
#define LOG_FB_SZ 0x334000 // 1280 x 656 x 4.
#define NYX_FB_ADDRESS 0xF6200000
#define NYX_FB2_ADDRESS 0xF6600000
#define NYX_FB_SZ 0x384000 // 1280 x 720 x 4.
#define DRAM_MEM_HOLE_ADR 0xF6A00000
#define DRAM_MEM_HOLE_SZ 0x8140000
/* --- Hole: 129MB 0xF6A00000 - 0xFEB3FFFF --- */
#define DRAM_START2 0xFEB40000
// NX BIS driver sector cache. // NX BIS driver sector cache.
#define NX_BIS_CACHE_ADDR 0xF9000000 #define NX_BIS_CACHE_ADDR 0xFEE00000
#define NX_BIS_CACHE_SZ 0x8800 #define NX_BIS_CACHE_SZ 0x8800
/* --- Gap: 111MB 0xF9008800 - 0xFFFFFFFF --- */
// #define EXT_PAYLOAD_ADDR 0xC03C0000 // USB buffers.
// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) #define USBD_ADDR 0xFEF00000
// #define COREBOOT_ADDR (0xD0000000 - 0x100000) #define USB_DESCRIPTOR_ADDR 0xFEF40000
#define USB_EP_CONTROL_BUF_ADDR 0xFEF80000
#define USB_EP_BULK_IN_BUF_ADDR 0xFF000000
#define USB_EP_BULK_OUT_BUF_ADDR 0xFF800000
#define USB_EP_BULK_OUT_MAX_XFER 0x800000
// NYX
// #define EXT_PAYLOAD_ADDR 0xC0000000 // #define EXT_PAYLOAD_ADDR 0xC0000000
// #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) // #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10))
// #define COREBOOT_ADDR (0xD0000000 - 0x100000) // #define COREBOOT_ADDR (0xD0000000 - rom_size)
#endif #endif

View file

@ -54,6 +54,8 @@ extern int sd_save_to_file(void *buf, u32 size, const char *filename);
extern hekate_config h_cfg; extern hekate_config h_cfg;
extern bool clear_sector_cache; extern bool clear_sector_cache;
extern bool lock_sector_cache;
extern u32 secindex;
u32 _key_count = 0, _titlekey_count = 0; u32 _key_count = 0, _titlekey_count = 0;
u32 color_idx = 0; u32 color_idx = 0;
@ -580,6 +582,7 @@ pkg2_done:
goto dismount; goto dismount;
} }
bool pkg1_not_100 = memcmp(pkg1_id->id, "2016", 4);
path[25] = '/'; path[25] = '/';
while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) { while (!f_readdir(&dir, &fno) && fno.fname[0] && titles_found < title_limit) {
minerva_periodic_training(); minerva_periodic_training();
@ -594,7 +597,7 @@ pkg2_done:
} }
se_aes_xts_crypt(5, 4, 0, 1, dec_header + 0x200, dec_header, 32, 1); se_aes_xts_crypt(5, 4, 0, 1, dec_header + 0x200, dec_header, 32, 1);
// es doesn't contain es key sources on 1.0.0 // es doesn't contain es key sources on 1.0.0
if (memcmp(pkg1_id->id, "2016", 4) && _read_le_u32(dec_header, 0x210) == 0x33 && dec_header[0x205] == 0) { if (pkg1_not_100 && _read_le_u32(dec_header, 0x210) == 0x33 && dec_header[0x205] == 0) {
u8 hash_order[3] = {0, 1, 2}; u8 hash_order[3] = {0, 1, 2};
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) { if (pkg1_id->kb >= KB_FIRMWARE_VERSION_500) {
hash_order[0] = 1; hash_order[0] = 1;
@ -602,6 +605,7 @@ pkg2_done:
} }
hash_index = 0; hash_index = 0;
// decrypt only what is needed to locate needed keys // decrypt only what is needed to locate needed keys
lock_sector_cache = true;
temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.es_offset, 0xc0, key_area_key); temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.es_offset, 0xc0, key_area_key);
for (u32 i = 0; i <= 0xb0; ) { for (u32 i = 0; i <= 0xb0; ) {
se_calc_sha256(temp_hash, temp_file + i, 0x10); se_calc_sha256(temp_hash, temp_file + i, 0x10);
@ -618,7 +622,9 @@ pkg2_done:
free(temp_file); free(temp_file);
temp_file = NULL; temp_file = NULL;
titles_found++; titles_found++;
lock_sector_cache = false;
} else if (_read_le_u32(dec_header, 0x210) == 0x24 && dec_header[0x205] == 0) { } else if (_read_le_u32(dec_header, 0x210) == 0x24 && dec_header[0x205] == 0) {
lock_sector_cache = true;
temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.ssl_offset, 0x70, key_area_key); temp_file = (u8*)_nca_process(5, 4, &fp, pkg1_id->key_info.ssl_offset, 0x70, key_area_key);
for (u32 i = 0; i <= 0x60; i++) { for (u32 i = 0; i <= 0x60; i++) {
se_calc_sha256(temp_hash, temp_file + i, 0x10); se_calc_sha256(temp_hash, temp_file + i, 0x10);
@ -638,6 +644,7 @@ pkg2_done:
free(temp_file); free(temp_file);
temp_file = NULL; temp_file = NULL;
titles_found++; titles_found++;
lock_sector_cache = false;
} }
f_close(&fp); f_close(&fp);
} }
@ -717,8 +724,8 @@ get_titlekeys:
se_aes_key_set(8, bis_key[0] + 0x00, 0x10); se_aes_key_set(8, bis_key[0] + 0x00, 0x10);
se_aes_key_set(9, bis_key[0] + 0x10, 0x10); se_aes_key_set(9, bis_key[0] + 0x10, 0x10);
u32 buf_size = 0x4000; u32 buf_size = 0x40000;
u8 *buffer = (u8 *)malloc(buf_size); u8 *buffer = (u8 *)MIXD_BUF_ALIGNED;
u8 keypair[0x230] = {0}; u8 keypair[0x230] = {0};
@ -731,7 +738,6 @@ get_titlekeys:
if (_read_le_u32(buffer, 0) != 0x304C4143) { if (_read_le_u32(buffer, 0) != 0x304C4143) {
EPRINTF("CAL0 magic not found. Check BIS key 0."); EPRINTF("CAL0 magic not found. Check BIS key 0.");
free(buffer);
goto dismount; goto dismount;
} }
@ -761,13 +767,11 @@ get_titlekeys:
// Check public exponent is 0x10001 big endian // Check public exponent is 0x10001 big endian
if (E[0] != 0 || E[1] != 1 || E[2] != 0 || E[3] != 1) { if (E[0] != 0 || E[1] != 1 || E[2] != 0 || E[3] != 1) {
EPRINTF("Invalid public exponent."); EPRINTF("Invalid public exponent.");
free(buffer);
goto dismount; goto dismount;
} }
if (!_test_key_pair(E, D, N)) { if (!_test_key_pair(E, D, N)) {
EPRINTF("Invalid keypair. Check eticket_rsa_kek."); EPRINTF("Invalid keypair. Check eticket_rsa_kek.");
free(buffer);
goto dismount; goto dismount;
} }
@ -776,25 +780,28 @@ get_titlekeys:
u32 br = buf_size; u32 br = buf_size;
u32 file_tkey_count = 0; u32 file_tkey_count = 0;
u64 total_br = 0; u64 total_br = 0;
rights_ids = (u8 *)malloc(0x40000); rights_ids = (u8 *)(MIXD_BUF_ALIGNED + 0x40000);
titlekeys = (u8 *)malloc(0x40000); titlekeys = (u8 *)(MIXD_BUF_ALIGNED + 0x80000);
save_ctx = calloc(1, sizeof(save_ctx_t)); save_ctx = calloc(1, sizeof(save_ctx_t));
u8 M[0x100]; u8 M[0x100];
if (f_open(&fp, "emmc:/save/80000000000000E1", FA_READ | FA_OPEN_EXISTING)) { if (f_open(&fp, "emmc:/save/80000000000000E1", FA_READ | FA_OPEN_EXISTING)) {
EPRINTF("Unable to open e1 save. Skipping."); EPRINTF("Unable to open e1 save. Skipping.");
free(buffer);
goto dismount; goto dismount;
} }
DWORD *clmt = f_expand_cltbl(&fp, buf_size, 0);
u32 pct = 0, last_pct = 0; u32 pct = 0, last_pct = 0;
tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500); tui_pbar(save_x, save_y, pct, COLOR_GREEN, 0xFF155500);
save_ctx->file = &fp; save_ctx->file = &fp;
save_ctx->tool_ctx.action = 0; save_ctx->tool_ctx.action = 0;
memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); memcpy(save_ctx->save_mac_key, save_mac_key, 0x10);
clear_sector_cache = true;
save_process_success = save_process(save_ctx); save_process_success = save_process(save_ctx);
if (!save_process_success) { if (!save_process_success) {
EPRINTF("Failed to process e1 save."); EPRINTF("Failed to process e1 save.");
f_close(&fp);
free(clmt);
goto dismount; goto dismount;
} }
@ -804,6 +811,8 @@ get_titlekeys:
save_fs_list_entry_t entry = {0, "", {0}, 0}; save_fs_list_entry_t entry = {0, "", {0}, 0};
if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) {
EPRINTF("Unable to locate ticket_list.bin in e1."); EPRINTF("Unable to locate ticket_list.bin in e1.");
f_close(&fp);
free(clmt);
goto dismount; goto dismount;
} }
save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block);
@ -819,6 +828,8 @@ get_titlekeys:
} }
if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) {
EPRINTF("Unable to locate ticket.bin in e1 save."); EPRINTF("Unable to locate ticket.bin in e1 save.");
f_close(&fp);
free(clmt);
goto dismount; goto dismount;
} }
save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block);
@ -859,21 +870,28 @@ get_titlekeys:
u32 common_titlekey_count = _titlekey_count; u32 common_titlekey_count = _titlekey_count;
if (f_open(&fp, "emmc:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) { if (f_open(&fp, "emmc:/save/80000000000000E2", FA_READ | FA_OPEN_EXISTING)) {
EPRINTF("Unable to open e2 save. Skipping."); EPRINTF("Unable to open e2 save. Skipping.");
free(buffer); free(clmt);
goto dismount; goto dismount;
} }
fp.cltbl = clmt;
clmt = f_expand_cltbl(&fp, buf_size, 0);
save_ctx->file = &fp; save_ctx->file = &fp;
save_ctx->tool_ctx.action = 0; save_ctx->tool_ctx.action = 0;
memcpy(save_ctx->save_mac_key, save_mac_key, 0x10); memcpy(save_ctx->save_mac_key, save_mac_key, 0x10);
clear_sector_cache = true;
save_process_success = save_process(save_ctx); save_process_success = save_process(save_ctx);
if (!save_process_success) { if (!save_process_success) {
EPRINTF("Failed to process e2 save."); EPRINTF("Failed to process e2 save.");
f_close(&fp);
free(clmt);
goto dismount; goto dismount;
} }
if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) { if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_list_bin_path, &entry)) {
EPRINTF("Unable to locate ticket_list.bin in e2 save."); EPRINTF("Unable to locate ticket_list.bin in e2 save.");
f_close(&fp);
free(clmt);
goto dismount; goto dismount;
} }
save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block); save_open_fat_storage(&save_ctx->save_filesystem_core, &fat_storage, entry.value.save_file_info.start_block);
@ -892,6 +910,8 @@ get_titlekeys:
} }
if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) { if (!save_hierarchical_file_table_get_file_entry_by_path(&save_ctx->save_filesystem_core.file_table, ticket_bin_path, &entry)) {
EPRINTF("Unable to locate ticket.bin in e2 save."); EPRINTF("Unable to locate ticket.bin in e2 save.");
f_close(&fp);
free(clmt);
goto dismount; goto dismount;
} }
@ -930,8 +950,8 @@ get_titlekeys:
} }
} }
tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500); tui_pbar(save_x, save_y, 100, COLOR_GREEN, 0xFF155500);
free(buffer);
f_close(&fp); f_close(&fp);
free(clmt);
gfx_con_setpos(0, save_y); gfx_con_setpos(0, save_y);
TPRINTFARGS("\n%kPersonalized... ", colors[(color_idx++) % 6]); TPRINTFARGS("\n%kPersonalized... ", colors[(color_idx++) % 6]);
@ -1053,8 +1073,6 @@ key_output: ;
EPRINTF("Unable to save titlekeys to SD."); EPRINTF("Unable to save titlekeys to SD.");
free_buffers: free_buffers:
free(rights_ids);
free(titlekeys);
free(text_buffer); free(text_buffer);
out_wait: out_wait:

View file

@ -45,10 +45,11 @@ typedef struct {
u8 cached_sector[0x200]; u8 cached_sector[0x200];
} sector_cache_t; } sector_cache_t;
#define MAX_SEC_CACHE_ENTRIES 128 #define MAX_SEC_CACHE_ENTRIES 256
static sector_cache_t *sector_cache = NULL; static sector_cache_t *sector_cache = (sector_cache_t *)(MIXD_BUF_ALIGNED + 0x100000); //NULL;
u32 secindex = 0; u32 secindex = 0;
bool clear_sector_cache = false; bool clear_sector_cache = false;
bool lock_sector_cache = false;
DSTATUS disk_status ( DSTATUS disk_status (
BYTE pdrv /* Physical drive number to identify the drive */ BYTE pdrv /* Physical drive number to identify the drive */
@ -154,14 +155,14 @@ DRESULT disk_read (
bool needs_cache_sector = false; bool needs_cache_sector = false;
if (secindex == 0 || clear_sector_cache) { if (secindex == 0 || clear_sector_cache) {
if (!sector_cache)
sector_cache = (sector_cache_t *)malloc(sizeof(sector_cache_t) * MAX_SEC_CACHE_ENTRIES);
clear_sector_cache = false; clear_sector_cache = false;
lock_sector_cache = false;
secindex = 0; secindex = 0;
} }
u32 s = 0; u32 s = 0;
if (count == 1) { // only attempt to cache single-sector reads as these are most likely to be repeated (eg. rereading FAT)
if (!lock_sector_cache && count == 1) {
for ( ; s < secindex; s++) { for ( ; s < secindex; s++) {
if (sector_cache[s].sector == sector) { if (sector_cache[s].sector == sector) {
sector_cache[s].visit_count++; sector_cache[s].visit_count++;

View file

@ -3906,6 +3906,93 @@ FRESULT f_read (
#ifdef FF_FASTFS
/*-----------------------------------------------------------------------*/
/* Fast Read Aligned Sized File Without a Cache */
/*-----------------------------------------------------------------------*/
#if FF_USE_FASTSEEK
FRESULT f_read_fast (
FIL* fp, /* Pointer to the file object */
const void* buff, /* Pointer to the data to be written */
UINT btr /* Number of bytes to read */
)
{
FRESULT res;
FATFS *fs;
UINT csize_bytes;
DWORD clst;
UINT count = 0;
FSIZE_t work_sector = 0;
FSIZE_t sector_base = 0;
BYTE *wbuff = (BYTE*)buff;
// TODO support sector reading inside a cluster
res = validate(&fp->obj, &fs); /* Check validity of the file object */
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
EFSPRINTF("FOV");
LEAVE_FF(fs, res); /* Check validity */
}
if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
FSIZE_t remain = fp->obj.objsize - fp->fptr;
if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
csize_bytes = fs->csize * SS(fs);
if (!fp->fptr) { /* On the top of the file? */
clst = fp->obj.sclust; /* Follow from the origin */
} else {
if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); }
}
if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); }
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); }
fp->clust = clst; /* Set working cluster */
sector_base = clst2sect(fs, fp->clust);
count += fs->csize;
btr -= csize_bytes;
fp->fptr += csize_bytes;
while (btr) {
clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); }
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); }
fp->clust = clst;
work_sector = clst2sect(fs, fp->clust);
if ((work_sector - sector_base) == count) count += fs->csize;
else {
if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
wbuff += count * SS(fs);
sector_base = work_sector;
count = fs->csize;
}
fp->fptr += MIN(btr, csize_bytes);
btr -= MIN(btr, csize_bytes);
// TODO: what about if data is smaller than cluster?
// Must read-write back that cluster.
if (!btr) { /* Final cluster/sectors read. */
if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
}
}
LEAVE_FF(fs, FR_OK);
}
#endif
#endif
#if !FF_FS_READONLY #if !FF_FS_READONLY
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Write File */ /* Write File */
@ -4045,6 +4132,98 @@ FRESULT f_write (
#ifdef FF_FASTFS
/*-----------------------------------------------------------------------*/
/* Fast Write Aligned Sized File Without a Cache */
/*-----------------------------------------------------------------------*/
#if FF_USE_FASTSEEK
FRESULT f_write_fast (
FIL* fp, /* Pointer to the file object */
const void* buff, /* Pointer to the data to be written */
UINT btw /* Number of bytes to write */
)
{
FRESULT res;
FATFS *fs;
UINT csize_bytes;
DWORD clst;
UINT count = 0;
FSIZE_t work_sector = 0;
FSIZE_t sector_base = 0;
const BYTE *wbuff = (const BYTE*)buff;
// TODO support sector writing inside a cluster
res = validate(&fp->obj, &fs); /* Check validity of the file object */
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
EFSPRINTF("FOV");
LEAVE_FF(fs, res); /* Check validity */
}
if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
/* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */
if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {
btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);
}
csize_bytes = fs->csize * SS(fs);
if (!fp->fptr) { /* On the top of the file? */
clst = fp->obj.sclust; /* Follow from the origin */
} else {
if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); }
}
if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); }
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); }
fp->clust = clst; /* Set working cluster */
sector_base = clst2sect(fs, fp->clust);
count += fs->csize;
btw -= csize_bytes;
fp->fptr += csize_bytes;
while (btw) {
clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); }
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); }
fp->clust = clst;
work_sector = clst2sect(fs, fp->clust);
if ((work_sector - sector_base) == count) count += fs->csize;
else {
if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
wbuff += count * SS(fs);
sector_base = work_sector;
count = fs->csize;
}
fp->fptr += MIN(btw, csize_bytes);
btw -= MIN(btw, csize_bytes);
// what about if data is smaller than cluster?
// Probably must read-write back that cluster.
if (!btw) { /* Final cluster/sectors write. */
if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
fp->flag &= (BYTE)~FA_DIRTY;
}
}
fp->flag |= FA_MODIFIED; /* Set file change flag */
LEAVE_FF(fs, FR_OK);
}
#endif
#endif
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Synchronize the File */ /* Synchronize the File */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -4501,6 +4680,39 @@ FRESULT f_lseek (
#ifdef FF_FASTFS
#if FF_USE_FASTSEEK
/*-----------------------------------------------------------------------*/
/* Seek File Read/Write Pointer */
/*-----------------------------------------------------------------------*/
DWORD *f_expand_cltbl (
FIL* fp, /* Pointer to the file object */
UINT tblsz, /* Size of table */
FSIZE_t ofs /* File pointer from top of file */
)
{
if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */
if (!fp->cltbl) { /* Allocate memory for cluster link table */
fp->cltbl = (DWORD *)ff_memalloc(tblsz);
fp->cltbl[0] = tblsz;
}
if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */
ff_memfree(fp->cltbl);
fp->cltbl = NULL;
EFSPRINTF("CLTBLSZ");
return NULL;
}
f_lseek(fp, 0);
return fp->cltbl;
}
#endif
#endif
#if FF_FS_MINIMIZE <= 1 #if FF_FS_MINIMIZE <= 1
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Create a Directory Object */ /* Create a Directory Object */
@ -5630,7 +5842,7 @@ FRESULT f_mkfs (
UINT len /* Size of working buffer [byte] */ UINT len /* Size of working buffer [byte] */
) )
{ {
const UINT n_fats = 1; /* Number of FATs for FAT/FAT32 volume (1 or 2) */ const UINT n_fats = 2; /* Number of FATs for FAT/FAT32 volume (1 or 2) */
const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */ const UINT n_rootdir = 512; /* Number of root directory entries for FAT volume */
static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */
static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */
@ -5694,7 +5906,7 @@ FRESULT f_mkfs (
} else { } else {
/* Create a single-partition in this function */ /* Create a single-partition in this function */
if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) LEAVE_MKFS(FR_DISK_ERR);
b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */ b_vol = (opt & FM_SFD) ? 0 : 32768; /* Volume start sector. Align to 16MB */
if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED); if (sz_vol < b_vol) LEAVE_MKFS(FR_MKFS_ABORTED);
sz_vol -= b_vol; /* Volume size */ sz_vol -= b_vol; /* Volume size */
} }
@ -5918,6 +6130,9 @@ FRESULT f_mkfs (
if (fmt == FS_FAT32) { /* FAT32: Move FAT base */ if (fmt == FS_FAT32) { /* FAT32: Move FAT base */
sz_rsv += n; b_fat += n; sz_rsv += n; b_fat += n;
} else { /* FAT: Expand FAT size */ } else { /* FAT: Expand FAT size */
if (n % n_fats) { /* Adjust fractional error if needed */
n--; sz_rsv++; b_fat++;
}
sz_fat += n / n_fats; sz_fat += n / n_fats;
} }
@ -5981,13 +6196,13 @@ FRESULT f_mkfs (
st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */ st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */
buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */
buf[BS_BootSig32] = 0x29; /* Extended boot signature */ buf[BS_BootSig32] = 0x29; /* Extended boot signature */
mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */ mem_cpy(buf + BS_VolLab32, "SWITCH SD " "FAT32 ", 19); /* Volume label, FAT signature */
} else { } else {
st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */ st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */
st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */ st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */
buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */
buf[BS_BootSig] = 0x29; /* Extended boot signature */ buf[BS_BootSig] = 0x29; /* Extended boot signature */
mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */ mem_cpy(buf + BS_VolLab, "SWITCH SD " "FAT ", 19); /* Volume label, FAT signature */
} }
st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */ st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */
if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */ if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); /* Write it to the VBR sector */

View file

@ -246,7 +246,12 @@ typedef enum {
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
#ifdef FF_FASTFS
FR_INVALID_PARAMETER, /* (19) Given parameter is invalid */
FR_CLTBL_NO_INIT /* (20) The cluster table for fast seek/read/write was not created */
#else
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
#endif
} FRESULT; } FRESULT;
@ -258,6 +263,10 @@ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a f
FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */ FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */ FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
#ifdef FF_FASTFS
FRESULT f_read_fast (FIL* fp, const void* buff, UINT btr); /* Fast read data from the file */
FRESULT f_write_fast (FIL* fp, const void* buff, UINT btw); /* Fast write data to the file */
#endif
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */ FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
FRESULT f_truncate (FIL* fp); /* Truncate the file */ FRESULT f_truncate (FIL* fp); /* Truncate the file */
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */ FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
@ -279,6 +288,9 @@ FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get numbe
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */ FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
#ifdef FF_FASTFS
DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, FSIZE_t ofs); /* Expand file and populate cluster table */
#endif
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */ FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
@ -368,8 +380,11 @@ int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
#define AM_RDO 0x01 /* Read only */ #define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */ #define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */ #define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume */
#define AM_DIR 0x10 /* Directory */ #define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */ #define AM_ARC 0x20 /* Archive */
#define AM_DEV 0x40 /* Device */
#define AM_RVD 0x80 /* Reserved */
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -41,8 +41,13 @@
#define FF_USE_MKFS 0 #define FF_USE_MKFS 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define FF_FASTFS 1
#ifdef FF_FASTFS
#define FF_USE_FASTSEEK 1
#else
#define FF_USE_FASTSEEK 0 #define FF_USE_FASTSEEK 0
#endif
/* This option switches fast seek function. (0:Disable or 1:Enable) */ /* This option switches fast seek function. (0:Disable or 1:Enable) */