diff options
author | PikalaxALT <pikalaxalt@gmail.com> | 2020-05-07 13:48:17 -0400 |
---|---|---|
committer | PikalaxALT <pikalaxalt@gmail.com> | 2020-05-07 13:49:50 -0400 |
commit | 5928e2511db179bdc809f252a3b7fcd7798726db (patch) | |
tree | e7ce827057873f803f61a94853d717ed4407e713 /arm9/lib/src | |
parent | 1762253800d072790303d8cd3b047bab25f8eaed (diff) | |
parent | d4575098dbd671e2b6fd27ad65b984502c90465b (diff) |
Merge branch 'libfs' of github.com:PikalaxALT/pokediamond into libfs
Diffstat (limited to 'arm9/lib/src')
-rw-r--r-- | arm9/lib/src/FS_archive.c | 147 | ||||
-rw-r--r-- | arm9/lib/src/FS_file.c | 10 | ||||
-rw-r--r-- | arm9/lib/src/FS_overlay.c | 297 |
3 files changed, 444 insertions, 10 deletions
diff --git a/arm9/lib/src/FS_archive.c b/arm9/lib/src/FS_archive.c new file mode 100644 index 00000000..39daa324 --- /dev/null +++ b/arm9/lib/src/FS_archive.c @@ -0,0 +1,147 @@ +#include "FS_archive.h" +#include "FS_file.h" +#include "FS_command.h" +#include "MI_memory.h" +#include "MI_byteAccess.h" + +FSArchive * arc_list = NULL; +FSDirPos current_dir_pos; + +u32 FSi_GetPackedName(const char * name, int name_len) +{ + u32 ret = 0; + if (name_len <= FS_ARCHIVE_NAME_LEN_MAX) + { + int i = 0; + for (; i < name_len; i++) + { + u32 c = MI_ReadByte(name + i); + if (!c) + break; + c = (u32)(c - 'A'); + if (c <= (u32)('Z' - 'A')) + c = (u32)(c + 'a'); + else + c = (u32)(c + 'A'); + ret |= (u32)(c << (i * 8)); + } + } + return ret; +} + +FSResult FSi_ReadMemCallback(FSArchive * p_arc, u8 * dest, u32 offset, u32 size) +{ + MI_CpuCopy8((const void *)FS_GetArchiveOffset(p_arc, offset), dest, size); + return FS_RESULT_SUCCESS; +} + +FSResult FSi_WriteMemCallback(FSArchive * p_arc, const u8 * src, u32 offset, u32 size) +{ + MI_CpuCopy8(src, (void *)FS_GetArchiveOffset(p_arc, offset), size); + return FS_RESULT_SUCCESS; +} + +FSResult FSi_ReadMemoryCore(FSArchive * p_arc, u8 * dest, u32 offset, u32 size) +{ + MI_CpuCopy8((const void *)offset, dest, size); + return FS_RESULT_SUCCESS; +} + +FSFile * FSi_NextCommand(FSArchive * p_arc) +{ + OSIntrMode bak_psr = OS_DisableInterrupts(); + if (FSi_IsArchiveCanceling(p_arc)) + { + FSFile *p, *q; + p_arc->flag &= ~FS_ARCHIVE_FLAG_CANCELING; + for (p = p_arc->list.next; p; p = q) + { + q = p->link.next; + if (FS_IsCanceling(p)) + { + if (p_arc->list.next == p) + p_arc->list.next = q; + FSi_ReleaseCommand(p, FS_RESULT_CANCELED); + if (!q) + q = p_arc->list.next; + } + } + } + if (!FSi_IsArchiveSuspending(p_arc) && !FS_IsArchiveSuspended(p_arc)) + { + FSFile * p_file = p_arc->list.next; + if (p_file != NULL) + { + const BOOL is_start = !FSi_IsArchiveRunning(p_arc); + if (is_start) + p_arc->flag |= FS_ARCHIVE_FLAG_RUNNING; + OS_RestoreInterrupts(bak_psr); + if (is_start) + { + if ((p_arc->proc_flag & FS_ARCHIVE_PROC_ACTIVATE) != 0) + (*p_arc->proc) (p_file, FS_COMMAND_ACTIVATE); + } + bak_psr = OS_DisableInterrupts(); + p_file->stat |= FS_FILE_STATUS_OPERATING; + if (FS_IsFileSyncMode(p_file)) + { + OS_WakeupThread(p_file->queue); + OS_RestoreInterrupts(bak_psr); + return NULL; + } + OS_RestoreInterrupts(bak_psr); + return p_file; + } + } + if (FSi_IsArchiveRunning(p_arc)) + { + p_arc->flag &= ~FS_ARCHIVE_FLAG_RUNNING; + if (p_arc->proc_flag & FS_ARCHIVE_PROC_IDLE) + { + FSFile tmp; + FS_InitFile(&tmp); + tmp.arc = p_arc; + (*p_arc->proc)(&tmp, FS_COMMAND_IDLE); + } + } + if (FSi_IsArchiveSuspending(p_arc)) + { + p_arc->flag &= ~FS_ARCHIVE_FLAG_SUSPENDING; + p_arc->flag |= FS_ARCHIVE_FLAG_SUSPEND; + OS_WakeupThread(&p_arc->stat_q); + } + OS_RestoreInterrupts(bak_psr); + return NULL; +} + +void FSi_ExecuteAsyncCommand(FSFile * p_file) +{ + FSArchive *const p_arc = p_file->arc; + while (p_file) + { + OSIntrMode bak_psr = OS_DisableInterrupts(); + p_file->stat |= FS_FILE_STATUS_OPERATING; + if (FS_IsFileSyncMode(p_file)) + { + OS_WakeupThread(p_file->queue); + OS_RestoreInterrupts(bak_psr); + break; + } + p_file->stat |= FS_FILE_STATUS_ASYNC; + OS_RestoreInterrupts(bak_psr); + if (FSi_TranslateCommand(p_file, p_file->command) == FS_RESULT_PROC_ASYNC) + break; + p_file = FSi_NextCommand(p_arc); + } +} + +BOOL FSi_ExecuteSyncCommand(FSFile * p_file) +{ + FSFile * p_target; + FSResult ret = FSi_TranslateCommand(p_file, p_file->command); + FSi_ReleaseCommand(p_file, ret); + p_target = FSi_NextCommand(p_file->arc); + if (p_target) + FSi_ExecuteAsyncCommand(p_target); + return FS_IsSucceeded(p_file); +} diff --git a/arm9/lib/src/FS_file.c b/arm9/lib/src/FS_file.c index 8ca89af8..479a5085 100644 --- a/arm9/lib/src/FS_file.c +++ b/arm9/lib/src/FS_file.c @@ -11,16 +11,6 @@ static inline BOOL FSi_IsSlash(u32 c) return (c == '/') || (c == '\\'); } -static inline BOOL FS_IsBusy(volatile const FSFile * p_file) -{ - return p_file->stat & FS_FILE_STATUS_BUSY ? TRUE : FALSE; -} - -static inline BOOL FS_IsSucceeded(volatile const FSFile * p_file) -{ - return p_file->error == FS_RESULT_SUCCESS ? TRUE : FALSE; -} - void FS_Init(u32 default_dma_no) { if (!is_init) diff --git a/arm9/lib/src/FS_overlay.c b/arm9/lib/src/FS_overlay.c new file mode 100644 index 00000000..d8d53570 --- /dev/null +++ b/arm9/lib/src/FS_overlay.c @@ -0,0 +1,297 @@ +#include "nitro.h" +#include "DGT_common.h" +#include "DGT_dgt.h" +#include "OS_cache.h" +#include "OS_system.h" +#include "MI_memory.h" +#include "MI_uncompress.h" +#include "FS_rom.h" +#include "FS_overlay.h" +#include "FS_mw_dtor.h" +#include "MB_mb.h" + +#define FS_OVERLAY_FLAG_COMP 0x0001 +#define FS_OVERLAY_FLAG_AUTH 0x0002 +#define FS_OVERLAY_DIGEST_SIZE DGT_HASH2_DIGEST_SIZE + +u32 FSi_GetOverlayBinarySize(FSOverlayInfo * p_ovi) +{ + u32 size = (p_ovi->header.flag & FS_OVERLAY_FLAG_COMP) + ? p_ovi->header.compressed + : p_ovi->header.ram_size; + return size; +} + +void FS_ClearOverlayImage(FSOverlayInfo * p_ovi) +{ + u8 * const im_start = FS_GetOverlayAddress(p_ovi); + u32 const ram_size = FS_GetOverlayImageSize(p_ovi); + u32 const total_size = FS_GetOverlayTotalSize(p_ovi); + + IC_InvalidateRange(im_start, total_size); + DC_InvalidateRange(im_start, total_size); + MI_CpuFill8(im_start + ram_size, 0, total_size - ram_size); +} + +FSFileID FS_GetOverlayFileID(FSOverlayInfo * p_ovi) +{ + FSFileID ret; + ret.arc = &fsi_arc_rom; + ret.file_id = p_ovi->header.file_id; + return ret; +} + +BOOL FSi_LoadOverlayInfoCore(FSOverlayInfo * p_ovi, MIProcessor target, FSOverlayID id, FSArchive * arc, u32 offset_arm9, u32 len_arm9, u32 offset_arm7, u32 len_arm7) +{ + CARDRomRegion pr[1]; + u32 pos; + if (target == MI_PROCESSOR_ARM9) + { + pr->offset = offset_arm9; + pr->length = len_arm9; + } + else + { + pr->offset = offset_arm7; + pr->length = len_arm7; + } + pos = (u32) id * sizeof(FSOverlayInfoHeader); + if (pos >= pr->length) + return FALSE; + + FSFile file[1]; + FS_InitFile(file); + // BOOL FS_OpenFileDirect(FSFile * p_file, FSArchive * p_arc, u32 image_top, u32 image_bottom, u32 file_index) + if (!FS_OpenFileDirect(file, arc, pr->offset + pos, pr->offset + pr->length, (u32)~0)) + return FALSE; + if (FS_ReadFile(file, p_ovi, sizeof(FSOverlayInfoHeader)) != sizeof(FSOverlayInfoHeader)) + { + FS_CloseFile(file); + return FALSE; + } + FS_CloseFile(file); + p_ovi->target = target; + if (!FS_OpenFileFast(file, FS_GetOverlayFileID(p_ovi))) + return FALSE; + p_ovi->file_pos.offset = FS_GetFileImageTop(file); + p_ovi->file_pos.length = FS_GetLength(file); + FS_CloseFile(file); + return TRUE; +} + +BOOL FS_LoadOverlayInfo(FSOverlayInfo * p_ovi, MIProcessor target, FSOverlayID id) +{ + CARDRomRegion * const pr = (target == MI_PROCESSOR_ARM9) ? &fsi_ovt9 : &fsi_ovt7; + if (pr->offset) + { + FSFile file[1]; + const u32 pos = id * sizeof(FSOverlayInfoHeader); + if (pos >= pr->length) + return FALSE; + MI_CpuCopy8((const void *)(pr->offset + pos), p_ovi, sizeof(FSOverlayInfoHeader)); + p_ovi->target = target; + FS_InitFile(file); + if (!FS_OpenFileFast(file, FS_GetOverlayFileID(p_ovi))) + return FALSE; + p_ovi->file_pos.offset = FS_GetFileImageTop(file); + p_ovi->file_pos.length = FS_GetLength(file); + FS_CloseFile(file); + return TRUE; + } + else + { + const CARDRomRegion * const p_ovt9 = CARD_GetRomRegionOVT(MI_PROCESSOR_ARM9); + const CARDRomRegion * const p_ovt7 = CARD_GetRomRegionOVT(MI_PROCESSOR_ARM7); + return FSi_LoadOverlayInfoCore(p_ovi, target, id, &fsi_arc_rom, p_ovt9->offset, p_ovt9->length, p_ovt7->offset, p_ovt7->length); + } +} + +BOOL FS_LoadOverlayImageAsync(FSOverlayInfo * p_ovi, FSFile * p_file) +{ + FS_InitFile(p_file); + if (!FS_OpenFileFast(p_file, FS_GetOverlayFileID(p_ovi))) + return FALSE; + else + { + s32 size = FSi_GetOverlayBinarySize(p_ovi); + FS_ClearOverlayImage(p_ovi); + if (FS_ReadFileAsync(p_file, FS_GetOverlayAddress(p_ovi), size) != size) + { + FS_CloseFile(p_file); + return FALSE; + } + return TRUE; + } +} + +BOOL FS_LoadOverlayImage(FSOverlayInfo * p_ovi) +{ + FSFile file[1]; + FS_InitFile(file); + if (!FS_OpenFileFast(file, FS_GetOverlayFileID(p_ovi))) + return FALSE; + else + { + s32 size = FSi_GetOverlayBinarySize(p_ovi); + FS_ClearOverlayImage(p_ovi); + if (FS_ReadFile(file, FS_GetOverlayAddress(p_ovi), size) != size) + { + FS_CloseFile(file); + return FALSE; + } + FS_CloseFile(file); + return TRUE; + } +} + +const void *fsi_digest_key_ptr; +u32 fsi_digest_key_len; + +BOOL FSi_CompareDigest(const u8 *spec_digest, void *src, int len) +{ + int i; + u8 digest[FS_OVERLAY_DIGEST_SIZE]; + u8 digest_key[64]; + + MI_CpuClear8(digest, sizeof(digest)); + MI_CpuCopy8(fsi_digest_key_ptr, digest_key, fsi_digest_key_len); + DGT_Hash2CalcHmac(digest, src, len, digest_key, fsi_digest_key_len); + for (i = 0; i < sizeof(digest); i += sizeof(u32)) + { + if (*(const u32 *)(digest + i) != *(const u32 *)(spec_digest + i)) + break; + } + return i == sizeof(digest); +} + +extern u8 SDK_OVERLAY_DIGEST[]; +extern u8 SDK_OVERLAY_DIGEST_END[]; + +void FS_StartOverlay(FSOverlayInfo * p_ovi) +{ + u32 rare_size = FSi_GetOverlayBinarySize(p_ovi); + if (MB_IsMultiBootChild()) + { + BOOL ret = FALSE; + + if (p_ovi->header.flag & FS_OVERLAY_FLAG_AUTH) + { + const u32 odt_max = (u32)((SDK_OVERLAY_DIGEST_END - SDK_OVERLAY_DIGEST) / FS_OVERLAY_DIGEST_SIZE); + if (p_ovi->header.id < odt_max) + { + const u8 * spec_digest = SDK_OVERLAY_DIGEST + FS_OVERLAY_DIGEST_SIZE * p_ovi->header.id; + ret = FSi_CompareDigest(spec_digest, p_ovi->header.ram_address, (int)rare_size); + } + } + if (!ret) + { + MI_CpuClear8(p_ovi->header.ram_address, rare_size); + OS_TPanic("FS_StartOverlay() failed! (invalid overlay-segment data)"); + return; + } + } + if (p_ovi->header.flag & FS_OVERLAY_FLAG_COMP) + { + MIi_UncompressBackward(p_ovi->header.ram_address + rare_size); + } + DC_FlushRange(p_ovi->header.ram_address, p_ovi->header.ram_size); + + { + FSOverlayInitFunc *p = p_ovi->header.sinit_init; + FSOverlayInitFunc *q = p_ovi->header.sinit_init_end; + for (; p < q; ++p) + { + if (*p) + (**p)(); + } + } +} + +void FS_EndOverlay(FSOverlayInfo *p_ovi) +{ + for (;;) + { + MWiDestructorChain *head = NULL, *tail = NULL; + const u32 region_top = (u32)FS_GetOverlayAddress(p_ovi); + const u32 region_bottom = region_top + FS_GetOverlayTotalSize(p_ovi); + + { + OSIntrMode bak_psr = OS_DisableInterrupts(); + MWiDestructorChain *prev = NULL; + MWiDestructorChain *base = __global_destructor_chain; + MWiDestructorChain *p = base; + while (p) + { + MWiDestructorChain *next = p->next; + const u32 dtor = (u32)p->dtor; + const u32 obj = (u32)p->obj; + if (((obj == 0) && (dtor >= region_top) && (dtor < region_bottom)) || + ((obj >= region_top) && (obj < region_bottom))) + { + /* If appropriate, extract*/ + if (!tail) + { + head = p; + } + else + { + tail->next = p; + } + if (base == p) + { + base = __global_destructor_chain = next; + } + tail = p, p->next = NULL; + if (prev) + { + prev->next = next; + } + } + else + { + prev = p; + } + p = next; + } + OS_RestoreInterrupts(bak_psr); + } + + if (!head) + { + break; + } + do + { + MWiDestructorChain *next = head->next; + if (head->dtor) + { + (*head->dtor) (head->obj); + } + head = next; + } + while (head); + } +} + +BOOL FS_UnloadOverlayImage(FSOverlayInfo * p_ovi) +{ + FS_EndOverlay(p_ovi); + return TRUE; +} + +BOOL FS_LoadOverlay(MIProcessor target, FSOverlayID id) +{ + FSOverlayInfo ovi; + if (!FS_LoadOverlayInfo(&ovi, target, id) || !FS_LoadOverlayImage(&ovi)) + return FALSE; + FS_StartOverlay(&ovi); + return TRUE; +} + +BOOL FS_UnloadOverlay(MIProcessor target, FSOverlayID id) +{ + FSOverlayInfo ovi; + if (!FS_LoadOverlayInfo(&ovi, target, id) || !FS_UnloadOverlayImage(&ovi)) + return FALSE; + return TRUE; +} |