diff options
author | Made <made111@gmx.de> | 2020-05-09 19:44:50 +0200 |
---|---|---|
committer | Made <made111@gmx.de> | 2020-05-09 19:44:50 +0200 |
commit | eff30d81b4785428ca4e86383f665f9f03c76b9f (patch) | |
tree | a168324f6cb3f88716e1a630b58ac93e8a0b42c9 /arm9/lib/src | |
parent | 4abf7d45568d93040fdb86993e915ffdfc4c4a9e (diff) | |
parent | e1c517d34810fe83865e896a23e46a2ea089261f (diff) |
Merge branch 'master' of https://github.com/martmists/pokediamond
Diffstat (limited to 'arm9/lib/src')
-rw-r--r-- | arm9/lib/src/FS_archive.c | 445 | ||||
-rw-r--r-- | arm9/lib/src/FS_command.c | 75 | ||||
-rw-r--r-- | arm9/lib/src/FS_command_default.c | 468 | ||||
-rw-r--r-- | arm9/lib/src/FS_file.c | 242 | ||||
-rw-r--r-- | arm9/lib/src/FS_overlay.c | 320 | ||||
-rw-r--r-- | arm9/lib/src/FS_rom.c | 118 | ||||
-rw-r--r-- | arm9/lib/src/OS_reset.c | 1 |
7 files changed, 1668 insertions, 1 deletions
diff --git a/arm9/lib/src/FS_archive.c b/arm9/lib/src/FS_archive.c new file mode 100644 index 00000000..6c0f01f1 --- /dev/null +++ b/arm9/lib/src/FS_archive.c @@ -0,0 +1,445 @@ +#include "FS_archive.h" +#include "FS_file.h" +#include "FS_command.h" +#include "FSi_util.h" +#include "MI_memory.h" +#include "MI_byteAccess.h" +#include "OS_printf.h" + +FSArchive * arc_list = NULL; +FSDirPos current_dir_pos; + +ARM_FUNC 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; +} + +ARM_FUNC FSResult FSi_ReadMemCallback(struct FSArchive * p_arc, void * dest, u32 pos, u32 size) +{ + MI_CpuCopy8((const void *)FS_GetArchiveOffset(p_arc, pos), dest, size); + return FS_RESULT_SUCCESS; +} + +ARM_FUNC FSResult FSi_WriteMemCallback(struct FSArchive * p_arc, const void * src, u32 pos, u32 size) +{ + MI_CpuCopy8(src, (void *)FS_GetArchiveOffset(p_arc, pos), size); + return FS_RESULT_SUCCESS; +} + +ARM_FUNC FSResult FSi_ReadMemoryCore(FSArchive * p_arc, void * dest, u32 pos, u32 size) +{ + MI_CpuCopy8((const void *)pos, dest, size); + return FS_RESULT_SUCCESS; +} + +ARM_FUNC 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; +} + +ARM_FUNC 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); + } +} + +ARM_FUNC 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); +} + +ARM_FUNC BOOL FSi_SendCommand(FSFile * p_file, FSCommandType command) +{ + FSArchive * p_arc = p_file->arc; + const int bit = 1 << command; + p_file->command = command; + p_file->error = FS_RESULT_BUSY; + p_file->stat |= FS_FILE_STATUS_BUSY; + { + OSIntrMode bak_psr = OS_DisableInterrupts(); + if (FSi_IsArchiveUnloading(p_arc)) + { + FSi_ReleaseCommand(p_file, FS_RESULT_CANCELLED); + OS_RestoreInterrupts(bak_psr); + return FALSE; + } + if ((bit & FS_ARCHIVE_PROC_SYNC) != 0) + p_file->stat |= FS_FILE_STATUS_SYNC; + FSi_AppendToList(p_file, (FSFile *)&p_arc->list); + if (!FS_IsArchiveSuspended(p_arc) && !FSi_IsArchiveRunning(p_arc)) + { + p_arc->flag |= FS_ARCHIVE_FLAG_RUNNING; + OS_RestoreInterrupts(bak_psr); + if ((p_arc->proc_flag & FS_ARCHIVE_PROC_ACTIVATE)) + (*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_RestoreInterrupts(bak_psr); + FSi_ExecuteAsyncCommand(p_file); + return TRUE; + } + OS_RestoreInterrupts(bak_psr); + } + else if (!FS_IsFileSyncMode(p_file)) + { + OS_RestoreInterrupts(bak_psr); + return TRUE; + } + else + { + do + { + OS_SleepThread(p_file->queue); + } while (!(p_file->stat & FS_FILE_STATUS_OPERATING)); + OS_RestoreInterrupts(bak_psr); + } + } + return FSi_ExecuteSyncCommand(p_file); +} + +ARM_FUNC void FS_InitArchive(FSArchive * p_arc) +{ + MI_CpuClear8(p_arc, sizeof(FSArchive)); + p_arc->sync_q.head = p_arc->sync_q.tail = NULL; + p_arc->stat_q.head = p_arc->stat_q.tail = NULL; +} + +ARM_FUNC FSArchive * const FS_FindArchive(const char * name, int name_len) +{ + u32 pack = FSi_GetPackedName(name, name_len); + OSIntrMode bak_psr = OS_DisableInterrupts(); + FSArchive * p_arc = arc_list; + while (p_arc && (p_arc->name.pack != pack)) + p_arc = p_arc->next; + OS_RestoreInterrupts(bak_psr); + return p_arc; +} + +ARM_FUNC BOOL FS_RegisterArchiveName(FSArchive * p_arc, const char * name, int name_len) +{ + BOOL ret = FALSE; + OSIntrMode bak_psr = OS_DisableInterrupts(); + if (!FS_FindArchive(name, name_len)) + { + FSArchive * p_tail = arc_list; + if (!p_tail) + { + arc_list = p_arc; + current_dir_pos.arc = p_arc; + current_dir_pos.pos = 0; + current_dir_pos.index = 0; + current_dir_pos.own_id = 0; + } + else + { + while (p_tail->next) + p_tail = p_tail->next; + p_tail->next = p_arc; + p_arc->prev = p_tail; + } + p_arc->name.pack = FSi_GetPackedName(name, name_len); + p_arc->flag |= FS_ARCHIVE_FLAG_REGISTER; + ret = TRUE; + } + OS_RestoreInterrupts(bak_psr); + return ret; +} + +ARM_FUNC void FS_ReleaseArchiveName(FSArchive * p_arc) +{ + if (p_arc->name.pack) + { + OSIntrMode bak_psr = OS_DisableInterrupts(); + if (p_arc->next) + p_arc->next->prev = p_arc->prev; + if (p_arc->prev) + p_arc->prev->next = p_arc->next; + p_arc->name.pack = 0; + p_arc->next = p_arc->prev = NULL; + p_arc->flag &= ~FS_ARCHIVE_FLAG_REGISTER; + if (current_dir_pos.arc == p_arc) + { + current_dir_pos.arc = arc_list; + current_dir_pos.pos = 0; + current_dir_pos.index = 0; + current_dir_pos.own_id = 0; + } + OS_RestoreInterrupts(bak_psr); + } +} + +ARM_FUNC BOOL FS_LoadArchive(FSArchive * p_arc, u32 base, u32 fat, u32 fat_size, u32 fnt, u32 fnt_size, FS_ARCHIVE_READ_FUNC read_func, FS_ARCHIVE_WRITE_FUNC write_func) +{ + p_arc->base = base; + p_arc->fat_size = fat_size; + p_arc->fat = p_arc->fat_bak = fat; + p_arc->fnt_size = fnt_size; + p_arc->fnt = p_arc->fnt_bak = fnt; + p_arc->read_func = (read_func != NULL) ? read_func : FSi_ReadMemCallback; + p_arc->write_func = (write_func != NULL) ? write_func : FSi_WriteMemCallback; + p_arc->table_func = p_arc->read_func; + p_arc->load_mem = NULL; + p_arc->flag |= FS_ARCHIVE_FLAG_LOADED; + return TRUE; +} + +ARM_FUNC BOOL FS_UnloadArchive(FSArchive * p_arc) +{ + OSIntrMode bak_psr = OS_DisableInterrupts(); + if (FS_IsArchiveLoaded(p_arc)) + { + if (FS_IsArchiveTableLoaded(p_arc)) + { + OS_TWarning("memory may leak. preloaded-table of archive \"%s\" (0x%08X)", p_arc->name.ptr, p_arc->load_mem); + } + { + FSFile *p, *q; + BOOL bak_state = FS_SuspendArchive(p_arc); + p_arc->flag |= FS_ARCHIVE_FLAG_UNLOADING; + for (p = p_arc->list.next; p; p = q) + { + q = p->link.next; + FSi_ReleaseCommand(p, FS_RESULT_CANCELED); + } + p_arc->list.next = NULL; + if (bak_state) + FS_ResumeArchive(p_arc); + } + p_arc->base = 0; + p_arc->fat = 0; + p_arc->fat_size = 0; + p_arc->fnt = 0; + p_arc->fnt_size = 0; + p_arc->fat_bak = p_arc->fnt_bak = 0; + p_arc->flag &= ~(FS_ARCHIVE_FLAG_CANCELING | FS_ARCHIVE_FLAG_LOADED | FS_ARCHIVE_FLAG_UNLOADING); + } + OS_RestoreInterrupts(bak_psr); + return TRUE; +} + +ARM_FUNC u32 FS_LoadArchiveTables(FSArchive *p_arc, void *p_mem, u32 max_size) +{ + u32 total_size = ALIGN_BYTE(p_arc->fat_size + p_arc->fnt_size + 32, 32); + if (total_size <= max_size) + { + u8 *p_cache = (u8 *)ALIGN_BYTE((u32)p_mem, 32); + FSFile tmp; + FS_InitFile(&tmp); + if (FS_OpenFileDirect(&tmp, p_arc, p_arc->fat, p_arc->fat + p_arc->fat_size, (u32)~0)) + { + if (FS_ReadFile(&tmp, p_cache, (s32)p_arc->fat_size) < 0) + { + MI_CpuFill8(p_cache, 0x00, p_arc->fat_size); + } + FS_CloseFile(&tmp); + } + p_arc->fat = (u32)p_cache; + p_cache += p_arc->fat_size; + if (FS_OpenFileDirect(&tmp, p_arc, p_arc->fnt, p_arc->fnt + p_arc->fnt_size, (u32)~0)) + { + if (FS_ReadFile(&tmp, p_cache, (s32)p_arc->fnt_size) < 0) + { + MI_CpuFill8(p_cache, 0x00, p_arc->fnt_size); + } + FS_CloseFile(&tmp); + } + p_arc->fnt = (u32)p_cache; + p_arc->load_mem = p_mem; + p_arc->table_func = FSi_ReadMemoryCore; + p_arc->flag |= FS_ARCHIVE_FLAG_TABLE_LOAD; + } + return total_size; +} + +ARM_FUNC void * FS_UnloadArchiveTables(FSArchive * p_arc) +{ + void *ret = NULL; + if (FS_IsArchiveLoaded(p_arc)) + { + BOOL bak_stat = FS_SuspendArchive(p_arc); + if (FS_IsArchiveTableLoaded(p_arc)) + { + p_arc->flag &= ~FS_ARCHIVE_FLAG_TABLE_LOAD; + ret = p_arc->load_mem; + p_arc->load_mem = NULL; + p_arc->fat = p_arc->fat_bak; + p_arc->fnt = p_arc->fnt_bak; + p_arc->table_func = p_arc->read_func; + } + if (bak_stat) + FS_ResumeArchive(p_arc); + } + return ret; +} + +ARM_FUNC BOOL FS_SuspendArchive(FSArchive * p_arc) +{ + OSIntrMode bak_psr = OS_DisableInterrupts(); + const BOOL bak_stat = !FS_IsArchiveSuspended(p_arc); + if (bak_stat) + { + if (FSi_IsArchiveRunning(p_arc)) + { + p_arc->flag |= FS_ARCHIVE_FLAG_SUSPENDING; + do { + OS_SleepThread(&p_arc->stat_q); + } while (FSi_IsArchiveSuspending(p_arc)); + } + else + { + p_arc->flag |= FS_ARCHIVE_FLAG_SUSPEND; + } + } + OS_RestoreInterrupts(bak_psr); + return bak_stat; +} + +ARM_FUNC BOOL FS_ResumeArchive(FSArchive * p_arc) +{ + FSFile * p_target = NULL; + OSIntrMode bak_psr = OS_DisableInterrupts(); + const BOOL bak_stat = !FS_IsArchiveSuspended(p_arc); + if (!bak_stat) + { + p_arc->flag &= ~FS_ARCHIVE_FLAG_SUSPEND; + p_target = FSi_NextCommand(p_arc); + } + OS_RestoreInterrupts(bak_psr); + if (p_target) + FSi_ExecuteAsyncCommand(p_target); + return bak_stat; +} + +ARM_FUNC void FS_SetArchiveProc(struct FSArchive * p_arc, FS_ARCHIVE_PROC_FUNC proc, u32 flags) +{ + if (!flags) + proc = NULL; + else if (!proc) + flags = 0; + p_arc->proc = proc; + p_arc->proc_flag = flags; +} + +ARM_FUNC void FS_NotifyArchiveAsyncEnd(FSArchive *p_arc, FSResult ret) +{ + if (FSi_IsArchiveAsync(p_arc)) + { + FSFile *p_file = p_arc->list.next; + p_arc->flag &= ~FS_ARCHIVE_FLAG_IS_ASYNC; + FSi_ReleaseCommand(p_file, ret); + p_file = FSi_NextCommand(p_arc); + if (p_file) + FSi_ExecuteAsyncCommand(p_file); + } + else + { + FSFile *p_file = p_arc->list.next; + OSIntrMode bak_psr = OS_DisableInterrupts(); + p_file->error = ret; + p_arc->flag &= ~FS_ARCHIVE_FLAG_IS_SYNC; + OS_WakeupThread(&p_arc->sync_q); + (void)OS_RestoreInterrupts(bak_psr); + } +} diff --git a/arm9/lib/src/FS_command.c b/arm9/lib/src/FS_command.c new file mode 100644 index 00000000..818a65ea --- /dev/null +++ b/arm9/lib/src/FS_command.c @@ -0,0 +1,75 @@ +#include "FS_file.h" +#include "FS_archive.h" +#include "FSi_util.h" +#include "FS_command.h" + +ARM_FUNC void FSi_ReleaseCommand(FSFile * p_file, FSResult ret) +{ + OSIntrMode bak_psr = OS_DisableInterrupts(); + FSi_CutFromList(p_file); + p_file->stat &= ~(FS_FILE_STATUS_CANCEL | FS_FILE_STATUS_BUSY | FS_FILE_STATUS_SYNC | FS_FILE_STATUS_ASYNC | FS_FILE_STATUS_OPERATING); + p_file->error = ret; + OS_WakeupThread(p_file->queue); + OS_RestoreInterrupts(bak_psr); +} + +ARM_FUNC FSResult FSi_TranslateCommand(FSFile *p_file, FSCommandType command) +{ + FSResult ret; + + FSArchive *const p_arc = p_file->arc; + const int bit = (1 << command); + + if (FS_IsFileSyncMode(p_file)) + p_arc->flag |= FS_ARCHIVE_FLAG_IS_SYNC; + else + p_arc->flag |= FS_ARCHIVE_FLAG_IS_ASYNC; + + if ((p_arc->proc_flag & bit) != 0) + { + switch (ret = (*p_arc->proc) (p_file, command)) + { + case FS_RESULT_SUCCESS: + case FS_RESULT_FAILURE: + case FS_RESULT_UNSUPPORTED: + p_file->error = ret; + break; + case FS_RESULT_PROC_ASYNC: + break; + case FS_RESULT_PROC_UNKNOWN: + ret = FS_RESULT_PROC_DEFAULT; + p_arc->proc_flag &= ~bit; + break; + } + } + else + { + ret = FS_RESULT_PROC_DEFAULT; + } + if (ret == FS_RESULT_PROC_DEFAULT) + { + ret = (*fsi_default_command[command]) (p_file); + } + if (ret == FS_RESULT_PROC_ASYNC) + { + if (FS_IsFileSyncMode(p_file)) + { + OSIntrMode bak_psr = OS_DisableInterrupts(); + while (FSi_IsArchiveSync(p_arc)) + OS_SleepThread(&p_arc->sync_q); + ret = p_file->error; + OS_RestoreInterrupts(bak_psr); + } + } + else if (!FS_IsFileSyncMode(p_file)) + { + p_arc->flag &= ~FS_ARCHIVE_FLAG_IS_ASYNC; + FSi_ReleaseCommand(p_file, ret); + } + else + { + p_arc->flag &= ~FS_ARCHIVE_FLAG_IS_SYNC; + p_file->error = ret; + } + return ret; +} diff --git a/arm9/lib/src/FS_command_default.c b/arm9/lib/src/FS_command_default.c new file mode 100644 index 00000000..002e1d53 --- /dev/null +++ b/arm9/lib/src/FS_command_default.c @@ -0,0 +1,468 @@ +#include "nitro.h" +#include "FS_file.h" +#include "FS_command.h" +#include "FS_archive.h" +#include "MI_byteAccess.h" +#include "MI_memory.h" +#include "FSi_util.h" + +typedef struct +{ + FSArchive *arc; + u32 pos; +} +FSiSyncReadParam; + +ARM_FUNC FSResult FSi_ReadFileCommand(FSFile * p_file); +ARM_FUNC FSResult FSi_WriteFileCommand(FSFile * p_file); +ARM_FUNC FSResult FSi_SeekDirCommand(FSFile * p_file); +ARM_FUNC FSResult FSi_ReadDirCommand(FSFile * p_file); +ARM_FUNC FSResult FSi_FindPathCommand(FSFile * p_file); +ARM_FUNC FSResult FSi_GetPathCommand(FSFile * p_file); +ARM_FUNC FSResult FSi_OpenFileFastCommand(FSFile * p_file); +ARM_FUNC FSResult FSi_OpenFileDirectCommand(FSFile * p_file); +ARM_FUNC FSResult FSi_CloseFileCommand(FSFile * p_file); + +FSResult (*const fsi_default_command[])(FSFile *) = { + [FS_COMMAND_READFILE] = FSi_ReadFileCommand, + [FS_COMMAND_WRITEFILE] = FSi_WriteFileCommand, + [FS_COMMAND_SEEKDIR] = FSi_SeekDirCommand, + [FS_COMMAND_READDIR] = FSi_ReadDirCommand, + [FS_COMMAND_FINDPATH] = FSi_FindPathCommand, + [FS_COMMAND_GETPATH] = FSi_GetPathCommand, + [FS_COMMAND_OPENFILEFAST] = FSi_OpenFileFastCommand, + [FS_COMMAND_OPENFILEDIRECT] = FSi_OpenFileDirectCommand, + [FS_COMMAND_CLOSEFILE] = FSi_CloseFileCommand, +}; + +// Case-insensitive string comparison +ARM_FUNC u32 FSi_StrNICmp(const char * str1, const char * str2, u32 len) +{ + int i; + for (i = 0; i < len; i++) + { + u32 c = MI_ReadByte(str1 + i) - 'A'; + u32 d = MI_ReadByte(str2 + i) - 'A'; + if (c <= 'Z' - 'A') + c += 'a' - 'A'; + if (d <= 'Z' - 'A') + d += 'a' - 'A'; + if (c != d) + return c - d; + } + return 0; +} + +ARM_FUNC FSResult FSi_ReadTable(FSiSyncReadParam * p, void * dst, u32 len) +{ + FSResult ret; + FSArchive * const p_arc = p->arc; + p_arc->flag |= FS_ARCHIVE_FLAG_IS_SYNC; + switch (ret = (*p_arc->table_func)(p_arc, dst, p->pos, len)) + { + case FS_RESULT_SUCCESS: + case FS_RESULT_FAILURE: + p_arc->flag &= ~FS_ARCHIVE_FLAG_IS_SYNC; + break; + case FS_RESULT_PROC_ASYNC: + { + OSIntrMode bak_psr = OS_DisableInterrupts(); + while (FSi_IsArchiveSync(p_arc)) + OS_SleepThread(&p_arc->sync_q); + OS_RestoreInterrupts(bak_psr); + ret = p_arc->list.next->error; + } + break; + } + p->pos += len; + return ret; +} + +ARM_FUNC FSResult FSi_SeekDirDirect(FSFile * p_dir, u32 id) +{ + p_dir->stat |= FS_FILE_STATUS_SYNC; + p_dir->arg.seekdir.pos.arc = p_dir->arc; + p_dir->arg.seekdir.pos.pos = 0; + p_dir->arg.seekdir.pos.index = 0; + p_dir->arg.seekdir.pos.own_id = (u16)id; + return FSi_TranslateCommand(p_dir, FS_COMMAND_SEEKDIR); +} + +// The actual commands +ARM_FUNC FSResult FSi_ReadFileCommand(FSFile * p_file) +{ + FSArchive *const p_arc = p_file->arc; + const u32 pos = p_file->prop.file.pos; + const u32 len = p_file->arg.readfile.len; + void *const dst = p_file->arg.readfile.dst; + p_file->prop.file.pos += len; + return (*p_arc->read_func)(p_arc, dst, pos, len); +} + +ARM_FUNC FSResult FSi_WriteFileCommand(FSFile * p_file) +{ + FSArchive *const p_arc = p_file->arc; + const u32 pos = p_file->prop.file.pos; + const u32 len = p_file->arg.writefile.len; + const void *const src = p_file->arg.writefile.src; + p_file->prop.file.pos += len; + return (*p_arc->write_func)(p_arc, src, pos, len); +} + +ARM_FUNC FSResult FSi_SeekDirCommand(FSFile * p_dir) +{ + FSResult ret; + FSArchive *const p_arc = p_dir->arc; + const FSDirPos *const arg = &p_dir->arg.seekdir.pos; + + FSArchiveFNT fnt_entry; + FSiSyncReadParam param; + param.arc = p_arc; + param.pos = p_arc->fnt + arg->own_id * sizeof(fnt_entry); + ret = FSi_ReadTable(¶m, &fnt_entry, sizeof(fnt_entry)); + if (ret == FS_RESULT_SUCCESS) + { + p_dir->prop.dir.pos = *arg; + if ((arg->index == 0) && (arg->pos == 0)) + { + p_dir->prop.dir.pos.index = fnt_entry.index; + p_dir->prop.dir.pos.pos = p_arc->fnt + fnt_entry.start; + } + p_dir->prop.dir.parent = (u32) (fnt_entry.parent & BIT_MASK(12)); + } + return ret; +} + +ARM_FUNC FSResult FSi_ReadDirCommand(FSFile *p_dir) +{ + FSDirEntry *p_entry = p_dir->arg.readdir.p_entry; + FSResult ret; + + FSiSyncReadParam param; + param.arc = p_dir->arc; + param.pos = p_dir->prop.dir.pos.pos; + + { + u8 len; + ret = FSi_ReadTable(¶m, &len, sizeof(len)); + if (ret != FS_RESULT_SUCCESS) + return ret; + p_entry->name_len = (u32)(len & BIT_MASK(7)); + p_entry->is_directory = (u32)((len >> 7) & 1); + } + if (p_entry->name_len == 0) + return FS_RESULT_FAILURE; + + if (!p_dir->arg.readdir.skip_string) + { + ret = FSi_ReadTable(¶m, p_entry->name, p_entry->name_len); + if (ret != FS_RESULT_SUCCESS) + return ret; + MI_WriteByte((u8 *)p_entry->name + p_entry->name_len, (u8)'\0'); + } + else + { + param.pos += p_entry->name_len; + } + + if (p_entry->is_directory) + { + u16 id; + ret = FSi_ReadTable(¶m, &id, sizeof(id)); + if (ret != FS_RESULT_SUCCESS) + return ret; + p_entry->dir_id.arc = p_dir->arc; + p_entry->dir_id.own_id = (u16)(id & BIT_MASK(12)); + p_entry->dir_id.index = 0; + p_entry->dir_id.pos = 0; + } + else + { + p_entry->file_id.arc = p_dir->arc; + p_entry->file_id.file_id = p_dir->prop.dir.pos.index; + ++p_dir->prop.dir.pos.index; + } + p_dir->prop.dir.pos.pos = param.pos; + + return ret; +} + +ARM_FUNC FSResult FSi_FindPathCommand(FSFile *p_dir) +{ + const char *path = p_dir->arg.findpath.path; + const BOOL is_dir = p_dir->arg.findpath.find_directory; + p_dir->arg.seekdir.pos = p_dir->arg.findpath.pos; + (void)FSi_TranslateCommand(p_dir, FS_COMMAND_SEEKDIR); + for (; MI_ReadByte(path); path += (MI_ReadByte(path) ? 1 : 0)) + { + u32 is_directory; + int name_len = 0; + while ((is_directory = MI_ReadByte(path + name_len)), + (is_directory && !FSi_IsSlash(is_directory))) + ++name_len; + if (is_directory || is_dir) + is_directory = 1; + if (name_len == 0) + { + return FS_RESULT_FAILURE; + } + else if (MI_ReadByte(path) == '.') + { + if (name_len == 1) + { + path += 1; + continue; + } + else if ((name_len == 2) & (MI_ReadByte(path + 1) == '.')) + { + if (p_dir->prop.dir.pos.own_id != 0) + FSi_SeekDirDirect(p_dir, p_dir->prop.dir.parent); + path += 2; + continue; + } + } + if (name_len > FS_FILE_NAME_MAX) + { + return FS_RESULT_FAILURE; + } + else + { + FSDirEntry etr; + p_dir->arg.readdir.p_entry = &etr; + p_dir->arg.readdir.skip_string = FALSE; + for (;;) + { + if (FSi_TranslateCommand(p_dir, FS_COMMAND_READDIR) != FS_RESULT_SUCCESS) + return FS_RESULT_FAILURE; + if ((is_directory != etr.is_directory) || + (name_len != etr.name_len) || FSi_StrNICmp(path, etr.name, (u32)name_len)) + continue; + if (is_directory) + { + path += name_len; + p_dir->arg.seekdir.pos = etr.dir_id; + (void)FSi_TranslateCommand(p_dir, FS_COMMAND_SEEKDIR); + break; + } + else if (is_dir) + { + return FS_RESULT_FAILURE; + } + else + { + *p_dir->arg.findpath.result.file = etr.file_id; + return FS_RESULT_SUCCESS; + } + } + } + } + if (!is_dir) + return FS_RESULT_FAILURE; + *p_dir->arg.findpath.result.dir = p_dir->prop.dir.pos; + return FS_RESULT_SUCCESS; +} + +ARM_FUNC FSResult FSi_GetPathCommand(FSFile *p_file) +{ + FSArchive *const p_arc = p_file->arc; + + FSGetPathInfo *p_info = &p_file->arg.getpath; + + FSDirEntry entry; + FSFile tmp; + u32 dir_id; + u32 file_id; + u32 id; + u32 len; + + enum + { INVALID_ID = 0x10000 }; + + FS_InitFile(&tmp); + tmp.arc = p_file->arc; + + if (FS_IsDir(p_file)) + { + dir_id = p_file->prop.dir.pos.own_id; + file_id = INVALID_ID; + } + else + { + file_id = p_file->prop.file.own_id; + if (p_info->total_len != 0) + { + dir_id = p_info->dir_id; + } + else + { + u32 pos = 0; + u32 num_dir = 0; + dir_id = INVALID_ID; + do + { + FSi_SeekDirDirect(&tmp, pos); + if (!pos) + num_dir = tmp.prop.dir.parent; + tmp.arg.readdir.p_entry = &entry; + tmp.arg.readdir.skip_string = TRUE; + while (FSi_TranslateCommand(&tmp, FS_COMMAND_READDIR) == FS_RESULT_SUCCESS) + { + if (!entry.is_directory && (entry.file_id.file_id == file_id)) + { + dir_id = tmp.prop.dir.pos.own_id; + break; + } + } + } + while ((dir_id == INVALID_ID) && (++pos < num_dir)); + } + } + if (dir_id == INVALID_ID) + { + p_info->total_len = 0; + return FS_RESULT_FAILURE; + } + if (p_info->total_len == 0) + { + len = 0; + if (p_arc->name.pack <= 0x000000FF) + len += 1; + else if (p_arc->name.pack <= 0x0000FF00) + len += 2; + else + len += 3; + len += 1 + 1; + if (file_id != INVALID_ID) + len += entry.name_len; + id = dir_id; + if (id != 0) + { + FSi_SeekDirDirect(&tmp, id); + do + { + FSi_SeekDirDirect(&tmp, tmp.prop.dir.parent); + tmp.arg.readdir.p_entry = &entry; + tmp.arg.readdir.skip_string = TRUE; + while (FSi_TranslateCommand(&tmp, FS_COMMAND_READDIR) == FS_RESULT_SUCCESS) + { + if (entry.is_directory && (entry.dir_id.own_id == id)) + { + len += entry.name_len + 1; + break; + } + } + id = tmp.prop.dir.pos.own_id; + } + while (id != 0); + } + p_info->total_len = (u16)(len + 1); + p_info->dir_id = (u16)dir_id; + } + if (!p_info->buf) + return FS_RESULT_SUCCESS; + if (p_info->buf_len < p_info->total_len) + return FS_RESULT_FAILURE; + else + { + u8 *dst = p_info->buf; + u32 total = p_info->total_len; + u32 pos = 0; + if (p_arc->name.pack <= 0x000000FF) + len = 1; + else if (p_arc->name.pack <= 0x0000FF00) + len = 2; + else + len = 3; + MI_CpuCopy8(p_arc->name.ptr, dst + pos, len); + pos += len; + MI_CpuCopy8(":/", dst + pos, 2); + pos += 2; + id = dir_id; + FSi_SeekDirDirect(&tmp, id); + if (file_id != INVALID_ID) + { + tmp.arg.readdir.p_entry = &entry; + tmp.arg.readdir.skip_string = FALSE; + while (FSi_TranslateCommand(&tmp, FS_COMMAND_READDIR) == FS_RESULT_SUCCESS) + { + if (!entry.is_directory && (entry.file_id.file_id == file_id)) + break; + } + len = entry.name_len + 1; + MI_CpuCopy8(entry.name, dst + total - len, len); + total -= len; + } + else + { + MI_WriteByte(dst + total - 1, '\0'); + total -= 1; + } + if (id != 0) + { + do + { + FSi_SeekDirDirect(&tmp, tmp.prop.dir.parent); + tmp.arg.readdir.p_entry = &entry; + tmp.arg.readdir.skip_string = FALSE; + MI_WriteByte(dst + total - 1, '/'); + total -= 1; + while (FSi_TranslateCommand(&tmp, FS_COMMAND_READDIR) == FS_RESULT_SUCCESS) + { + if (entry.is_directory && (entry.dir_id.own_id == id)) + { + len = entry.name_len; + MI_CpuCopy8(entry.name, dst + total - len, len); + total -= len; + break; + } + } + id = tmp.prop.dir.pos.own_id; + } + while (id != 0); + } + } + + return FS_RESULT_SUCCESS; +} + +ARM_FUNC FSResult FSi_OpenFileFastCommand(FSFile * p_file) +{ + FSArchive *const p_arc = p_file->arc; + const FSFileID *p_id = &p_file->arg.openfilefast.id; + const u32 index = p_id->file_id; + FSResult ret; + + { + u32 pos = (u32)(index * sizeof(FSArchiveFAT)); + if (pos >= p_arc->fat_size) + return FS_RESULT_FAILURE; + else + { + FSArchiveFAT fat; + FSiSyncReadParam param; + param.arc = p_arc; + param.pos = p_arc->fat + pos; + ret = FSi_ReadTable(¶m, &fat, sizeof(fat)); + if (ret != FS_RESULT_SUCCESS) + return ret; + p_file->arg.openfiledirect.top = fat.top; + p_file->arg.openfiledirect.bottom = fat.bottom; + p_file->arg.openfiledirect.index = index; + return FSi_TranslateCommand(p_file, FS_COMMAND_OPENFILEDIRECT); + } + } +} + +ARM_FUNC FSResult FSi_OpenFileDirectCommand(FSFile * p_file) +{ + p_file->prop.file.top = p_file->arg.openfiledirect.top; + p_file->prop.file.pos = p_file->arg.openfiledirect.top; + p_file->prop.file.bottom = p_file->arg.openfiledirect.bottom; + p_file->prop.file.own_id = p_file->arg.openfiledirect.index; + return FS_RESULT_SUCCESS; +} + +ARM_FUNC FSResult FSi_CloseFileCommand(FSFile * p_file) +{ + return FS_RESULT_SUCCESS; +} diff --git a/arm9/lib/src/FS_file.c b/arm9/lib/src/FS_file.c new file mode 100644 index 00000000..8bca5c8e --- /dev/null +++ b/arm9/lib/src/FS_file.c @@ -0,0 +1,242 @@ +#include "nitro.h" +#include "MI_byteAccess.h" +#include "FS_rom.h" +#include "FS_file.h" +#include "FSi_util.h" + +extern FSDirPos current_dir_pos; +BOOL is_init = FALSE; + +ARM_FUNC void FS_Init(u32 default_dma_no) +{ + if (!is_init) + { + is_init = TRUE; + FSi_InitRom(default_dma_no); + } +} + +ARM_FUNC BOOL FS_IsAvailable(void) +{ + return is_init; +} + +ARM_FUNC void FS_InitFile(FSFile * p_file) +{ + p_file->link.next = p_file->link.prev = NULL; + OS_InitThreadQueue(p_file->queue); + p_file->arc = NULL; + p_file->command = FS_COMMAND_INVALID; + p_file->stat = 0; +} + +static BOOL FSi_FindPath(FSFile * p_dir, const char * path, FSFileID * p_file_id, FSDirPos * p_dir_pos) +{ + FSDirPos pos; + if (FSi_IsSlash(MI_ReadByte(path))) + { + pos.arc = current_dir_pos.arc; + pos.own_id = 0; + pos.pos = 0; + pos.index = 0; + path++; + } + else + { + int i; + pos = current_dir_pos; + for (i = 0; i <= FS_ARCHIVE_NAME_LEN_MAX; ++i) + { + u32 c = MI_ReadByte(path + i); + if (!c || FSi_IsSlash(c)) + break; + else if (c == ':') + { + FSArchive * const p_arc = FS_FindArchive(path, i); + if (!p_arc) + { + return FALSE; + } + else if (!FS_IsArchiveLoaded(p_arc)) + { + return FALSE; + } + pos.arc = p_arc; + pos.pos = 0; + pos.index = 0; + pos.own_id = 0; + path += i + 1; + if (FSi_IsSlash(MI_ReadByte(path))) + ++path; + break; + } + } + } + p_dir->arc = pos.arc; + p_dir->arg.findpath.path = path; + p_dir->arg.findpath.pos = pos; + if (p_dir_pos) + { + p_dir->arg.findpath.find_directory = TRUE; + p_dir->arg.findpath.result.dir = p_dir_pos; + } + else + { + p_dir->arg.findpath.find_directory = FALSE; + p_dir->arg.findpath.result.file = p_file_id; + } + return FSi_SendCommand(p_dir, FS_COMMAND_FINDPATH); +} + +ARM_FUNC int FSi_ReadFileCore(FSFile * p_file, void * dst, s32 len, BOOL async) +{ + const s32 pos = p_file->prop.file.pos; + const s32 rest = p_file->prop.file.bottom - pos; + const u32 org = len; + if (len > rest) + len = rest; + if (len < 0) + len = 0; + p_file->arg.readfile.dst = dst; + p_file->arg.readfile.len_org = org; + p_file->arg.readfile.len = len; + if (!async) + p_file->stat |= FS_FILE_STATUS_SYNC; + FSi_SendCommand(p_file, FS_COMMAND_READFILE); + if (!async) + { + if (FS_WaitAsync(p_file)) + len = p_file->prop.file.pos - pos; + else + len = -1; + } + return len; +} + +ARM_FUNC BOOL FS_ConvertPathToFileID(FSFileID * p_file_id, const char * path) +{ + FSFile dir; + FS_InitFile(&dir); + if (!FSi_FindPath(&dir, path, p_file_id, NULL)) + return FALSE; + return TRUE; +} + +ARM_FUNC BOOL FS_OpenFileDirect(FSFile * p_file, FSArchive * p_arc, u32 image_top, u32 image_bottom, u32 file_index) +{ + p_file->arc = p_arc; + p_file->arg.openfiledirect.index = file_index; + p_file->arg.openfiledirect.top = image_top; + p_file->arg.openfiledirect.bottom = image_bottom; + if (!FSi_SendCommand(p_file, FS_COMMAND_OPENFILEDIRECT)) + return FALSE; + p_file->stat |= FS_FILE_STATUS_IS_FILE; + p_file->stat &= ~FS_FILE_STATUS_IS_DIR; + return TRUE; +} + +ARM_FUNC BOOL FS_OpenFileFast(FSFile * p_file, FSFileID file_id) +{ + if (!file_id.arc) + return FALSE; + p_file->arc = file_id.arc; + p_file->arg.openfilefast.id = file_id; + if (!FSi_SendCommand(p_file, FS_COMMAND_OPENFILEFAST)) + return FALSE; + p_file->stat |= FS_FILE_STATUS_IS_FILE; + p_file->stat &= ~FS_FILE_STATUS_IS_DIR; + return TRUE; +} + +ARM_FUNC BOOL FS_OpenFile(FSFile * p_file, const char * path) +{ + FSFileID file_id; + return FS_ConvertPathToFileID(&file_id, path) && FS_OpenFileFast(p_file, file_id); +} + +ARM_FUNC BOOL FS_CloseFile(FSFile * p_file) +{ + if (!FSi_SendCommand(p_file, FS_COMMAND_CLOSEFILE)) + return FALSE; + p_file->arc = NULL; + p_file->command = FS_COMMAND_INVALID; + p_file->stat &= ~(FS_FILE_STATUS_IS_FILE | FS_FILE_STATUS_IS_DIR); + return TRUE; +} + +ARM_FUNC BOOL FS_WaitAsync(FSFile * p_file) +{ + BOOL is_owner = FALSE; + OSIntrMode bak_par = OS_DisableInterrupts(); + if (FS_IsBusy(p_file)) + { + is_owner = !(p_file->stat & (FS_FILE_STATUS_SYNC | FS_FILE_STATUS_OPERATING)); + if (is_owner) + { + p_file->stat |= FS_FILE_STATUS_SYNC; + do + { + OS_SleepThread(p_file->queue); + } while (!(p_file->stat & FS_FILE_STATUS_OPERATING)); + } + else + { + do + { + OS_SleepThread(p_file->queue); + } while (FS_IsBusy(p_file)); + } + } + (void)OS_RestoreInterrupts(bak_par); + if (is_owner) + { + return FSi_ExecuteSyncCommand(p_file); + } + + return FS_IsSucceeded(p_file); +} + +ARM_FUNC int FS_ReadFileAsync(FSFile * p_file, void * dst, s32 len) +{ + return FSi_ReadFileCore(p_file, dst, len, TRUE); +} + +ARM_FUNC int FS_ReadFile(FSFile * p_file, void * dst, s32 len) +{ + return FSi_ReadFileCore(p_file, dst, len, FALSE); +} + +ARM_FUNC BOOL FS_SeekFile(FSFile * p_file, int offset, FSSeekFileMode origin) +{ + switch (origin) + { + case FS_SEEK_SET: + offset += p_file->prop.file.top; + break; + case FS_SEEK_CUR: + offset += p_file->prop.file.pos; + break; + case FS_SEEK_END: + offset += p_file->prop.file.bottom; + break; + default: + return FALSE; + } + if (offset < (s32)p_file->prop.file.top) + offset = (s32)p_file->prop.file.top; + if (offset > (s32)p_file->prop.file.bottom) + offset = (s32)p_file->prop.file.bottom; + p_file->prop.file.pos = offset; + return TRUE; +} + +ARM_FUNC BOOL FS_ChangeDir(const char * path) +{ + FSDirPos pos; + FSFile dir; + FS_InitFile(&dir); + if (!FSi_FindPath(&dir, path, NULL, &pos)) + return FALSE; + current_dir_pos = pos; + return TRUE; +} diff --git a/arm9/lib/src/FS_overlay.c b/arm9/lib/src/FS_overlay.c new file mode 100644 index 00000000..79a3b43e --- /dev/null +++ b/arm9/lib/src/FS_overlay.c @@ -0,0 +1,320 @@ +#include "nitro.h" +#include "DGT_common.h" +#include "DGT_dgt.h" +#include "OS_cache.h" +#include "OS_system.h" +#include "OS_printf.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 + +ARM_FUNC 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; +} + +ARM_FUNC 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); +} + +ARM_FUNC FSFileID FS_GetOverlayFileID(FSOverlayInfo * p_ovi) +{ + FSFileID ret; + ret.arc = &fsi_arc_rom; + ret.file_id = p_ovi->header.file_id; + return ret; +} + +ARM_FUNC 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; +} + +ARM_FUNC 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); + } +} + +ARM_FUNC 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; + } +} + +ARM_FUNC 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; + } +} + +static const u8 fsi_def_digest_key[64] = { + 0x21, 0x06, 0xc0, 0xde, + 0xba, 0x98, 0xce, 0x3f, + 0xa6, 0x92, 0xe3, 0x9d, + 0x46, 0xf2, 0xed, 0x01, + + 0x76, 0xe3, 0xcc, 0x08, + 0x56, 0x23, 0x63, 0xfa, + 0xca, 0xd4, 0xec, 0xdf, + 0x9a, 0x62, 0x78, 0x34, + + 0x8f, 0x6d, 0x63, 0x3c, + 0xfe, 0x22, 0xca, 0x92, + 0x20, 0x88, 0x97, 0x23, + 0xd2, 0xcf, 0xae, 0xc2, + + 0x32, 0x67, 0x8d, 0xfe, + 0xca, 0x83, 0x64, 0x98, + 0xac, 0xfd, 0x3e, 0x37, + 0x87, 0x46, 0x58, 0x24, +}; + +static const void *fsi_digest_key_ptr = fsi_def_digest_key; +static int fsi_digest_key_len = sizeof(fsi_def_digest_key); + +ARM_FUNC 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[]; + +ARM_FUNC 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)(); + } + } +} + +ARM_FUNC 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); + } +} + +ARM_FUNC BOOL FS_UnloadOverlayImage(FSOverlayInfo * p_ovi) +{ + FS_EndOverlay(p_ovi); + return TRUE; +} + +ARM_FUNC 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; +} + +ARM_FUNC BOOL FS_UnloadOverlay(MIProcessor target, FSOverlayID id) +{ + FSOverlayInfo ovi; + if (!FS_LoadOverlayInfo(&ovi, target, id) || !FS_UnloadOverlayImage(&ovi)) + return FALSE; + return TRUE; +} diff --git a/arm9/lib/src/FS_rom.c b/arm9/lib/src/FS_rom.c new file mode 100644 index 00000000..32f66c10 --- /dev/null +++ b/arm9/lib/src/FS_rom.c @@ -0,0 +1,118 @@ +#include "FS_rom.h" +#include "FS_archive.h" +#include "FS_file.h" +#include "CARD_pullOut.h" +#include "CARD_rom.h" +#include "CARD_common.h" +#include "MB_mb.h" +#include "OS_printf.h" + +u32 fsi_default_dma_no; + +ARM_FUNC void FSi_OnRomReadDone(void * p_arc) +{ + FS_NotifyArchiveAsyncEnd(p_arc, CARD_IsPulledOut() ? FS_RESULT_ERROR : FS_RESULT_SUCCESS); +} + +ARM_FUNC FSResult FSi_ReadRomCallback(FSArchive * p_arc, void * dst, u32 src, u32 len) +{ + CARD_ReadRomAsync(fsi_default_dma_no, (const void *)src, dst, len, FSi_OnRomReadDone, p_arc); + return FS_RESULT_PROC_ASYNC; +} + +ARM_FUNC FSResult FSi_WriteDummyCallback(FSArchive * p_arc, const void *src, u32 dst, u32 len) +{ + return FS_RESULT_FAILURE; +} + +ARM_FUNC FSResult FSi_RomArchiveProc(FSFile * p_arc, FSCommandType cmd) +{ + switch (cmd) + { + case FS_COMMAND_ACTIVATE: + CARD_LockRom(fsi_card_lock_id); + return FS_RESULT_SUCCESS; + case FS_COMMAND_IDLE: + CARD_UnlockRom(fsi_card_lock_id); + return FS_RESULT_SUCCESS; + case FS_COMMAND_WRITEFILE: + return FS_RESULT_UNSUPPORTED; + default: + return FS_RESULT_PROC_UNKNOWN; + } +} + +ARM_FUNC FSResult FSi_ReadDummyCallback(FSArchive *p_arc, void *dst, u32 src, u32 len) +{ + return FS_RESULT_FAILURE; +} + +ARM_FUNC FSResult FSi_EmptyArchiveProc(FSFile *p_file, FSCommandType cmd) +{ + return FS_RESULT_UNSUPPORTED; +} + +ARM_FUNC void FSi_InitRom(u32 default_dma_no) +{ + fsi_default_dma_no = default_dma_no; + fsi_card_lock_id = OS_GetLockID(); + fsi_ovt9.offset = 0; + fsi_ovt9.length = 0; + fsi_ovt7.offset = 0; + fsi_ovt7.length = 0; + + CARD_Init(); + + FS_InitArchive(&fsi_arc_rom); + FS_RegisterArchiveName(&fsi_arc_rom, "rom", 3); + + if (MB_IsMultiBootChild()) + { + fsi_ovt9.offset = (u32)~0; + fsi_ovt9.length = 0; + fsi_ovt7.offset = (u32)~0; + fsi_ovt7.length = 0; + FS_SetArchiveProc(&fsi_arc_rom, FSi_EmptyArchiveProc, (u32)FS_ARCHIVE_PROC_ALL); + FS_LoadArchive(&fsi_arc_rom, 0x00000000, 0, 0, 0, 0, FSi_ReadDummyCallback, FSi_WriteDummyCallback); + } + else + { + const CARDRomRegion *const fnt = CARD_GetRomRegionFNT(); + const CARDRomRegion *const fat = CARD_GetRomRegionFAT(); + + FS_SetArchiveProc(&fsi_arc_rom, FSi_RomArchiveProc, + FS_ARCHIVE_PROC_WRITEFILE | + FS_ARCHIVE_PROC_ACTIVATE | FS_ARCHIVE_PROC_IDLE); + + if ((fnt->offset == 0xFFFFFFFF) || (fnt->offset == 0x00000000) || + (fat->offset == 0xFFFFFFFF) || (fat->offset == 0x00000000)) + { + OS_Warning("file-system : no MAKEROM-information in rom header."); + } + else + { + FS_LoadArchive(&fsi_arc_rom, 0x00000000, + fat->offset, fat->length, + fnt->offset, fnt->length, + FSi_ReadRomCallback, FSi_WriteDummyCallback); + } + } +} + +ARM_FUNC u32 FS_SetDefaultDMA(u32 dma_no) +{ + OSIntrMode bak_psr = OS_DisableInterrupts(); + u32 bak_dma_no = fsi_default_dma_no; + BOOL bak_stat = FS_SuspendArchive(&fsi_arc_rom); + fsi_default_dma_no = dma_no; + if (bak_stat) + FS_ResumeArchive(&fsi_arc_rom); + OS_RestoreInterrupts(bak_psr); + return bak_dma_no; +} + +ARM_FUNC u32 FS_TryLoadTable(void * p_mem, u32 size) +{ + return FS_LoadArchiveTables(&fsi_arc_rom, p_mem, size); +} + diff --git a/arm9/lib/src/OS_reset.c b/arm9/lib/src/OS_reset.c index 28d815a9..c21d20ab 100644 --- a/arm9/lib/src/OS_reset.c +++ b/arm9/lib/src/OS_reset.c @@ -14,7 +14,6 @@ extern u32 PXI_IsCallbackReady(u32 param1, u32 param2); extern void PXI_SetFifoRecvCallback(u32 param1, void* callback); extern u32 PXI_SendWordByFifo(u32 param1, u32 data, u32 param2); extern void CARD_LockRom(u16 lockId); -extern u32 OS_GetLockID(); extern void MI_StopDma(u32 dma); extern void OS_SetIrqMask(u32 mask); extern void OS_ResetRequestIrqMask(u32 mask); |