From 7ebc6abf53d65a151f9d013946f813ad5f07f28c Mon Sep 17 00:00:00 2001 From: lifehackerhansol Date: Fri, 1 Nov 2024 02:59:00 -0700 Subject: [PATCH] TopToyLauncher: use 8.3 filename for TTMENU.SYS Fixes an issue on some SD card --- arm9/source/launcher/TopToyLauncher.cpp | 8 +- arm9/source/launcher/libfat_ext/cache.h | 129 +++++++++++++ arm9/source/launcher/libfat_ext/directory.h | 182 +++++++++++++++++++ arm9/source/launcher/libfat_ext/fat_ext.h | 28 +++ arm9/source/launcher/libfat_ext/fatcommon.h | 48 +++++ arm9/source/launcher/libfat_ext/libfat_ext.c | 141 ++++++++++++++ arm9/source/launcher/libfat_ext/lock.h | 74 ++++++++ arm9/source/launcher/libfat_ext/partition.h | 108 +++++++++++ arm9/source/launcher/libfat_ext/tonccpy.c | 134 ++++++++++++++ arm9/source/launcher/libfat_ext/tonccpy.h | 45 +++++ arm9_tt/Makefile | 2 +- 11 files changed, 896 insertions(+), 3 deletions(-) create mode 100644 arm9/source/launcher/libfat_ext/cache.h create mode 100644 arm9/source/launcher/libfat_ext/directory.h create mode 100644 arm9/source/launcher/libfat_ext/fat_ext.h create mode 100644 arm9/source/launcher/libfat_ext/fatcommon.h create mode 100644 arm9/source/launcher/libfat_ext/libfat_ext.c create mode 100644 arm9/source/launcher/libfat_ext/lock.h create mode 100644 arm9/source/launcher/libfat_ext/partition.h create mode 100644 arm9/source/launcher/libfat_ext/tonccpy.c create mode 100644 arm9/source/launcher/libfat_ext/tonccpy.h diff --git a/arm9/source/launcher/TopToyLauncher.cpp b/arm9/source/launcher/TopToyLauncher.cpp index ff52ca9..54d1d0a 100644 --- a/arm9/source/launcher/TopToyLauncher.cpp +++ b/arm9/source/launcher/TopToyLauncher.cpp @@ -20,6 +20,7 @@ #include "../ui/progresswnd.h" #include "ILauncher.h" #include "TopToyLauncher.h" +#include "libfat_ext/fat_ext.h" static void resetAndLoop() { DC_FlushAll(); @@ -117,6 +118,7 @@ typedef struct { // TTMENU.SYS file creation. Sets up parameters for ttpatch.dat bool TopToyLauncher::prepareTTSYS(void) { + char fname[0x1004] = {}; TTSYSHeader* ttsys_header = (TTSYSHeader*)malloc(sizeof(TTSYSHeader)); ttsys_header->TTSYSMagic[0] = 't'; ttsys_header->TTSYSMagic[1] = 't'; @@ -132,10 +134,12 @@ bool TopToyLauncher::prepareTTSYS(void) { fseek(TTSYSFile, 0, SEEK_SET); fwrite(ttsys_header, sizeof(TTSYSHeader), 1, TTSYSFile); free(ttsys_header); + fatGetAliasPath("fat:/", mRomPath.c_str(), fname); fseek(TTSYSFile, 0x100, SEEK_SET); - fwrite(mRomPath.c_str() + 4, 1, 0x1000, TTSYSFile); + fwrite(fname + 4, 1, 0x1000, TTSYSFile); + fatGetAliasPath("fat:/", mSavePath.c_str(), fname); fseek(TTSYSFile, 0x1100, SEEK_SET); - fwrite(mSavePath.c_str() + 4, 1, 0x1000, TTSYSFile); + fwrite(fname + 4, 1, 0x1000, TTSYSFile); if (mFlags & PATCH_CHEATS) { fseek(TTSYSFile, 0x2100, SEEK_SET); fwrite("/YSMENU.ARP", 1, 0x12, TTSYSFile); diff --git a/arm9/source/launcher/libfat_ext/cache.h b/arm9/source/launcher/libfat_ext/cache.h new file mode 100644 index 0000000..f3d91f2 --- /dev/null +++ b/arm9/source/launcher/libfat_ext/cache.h @@ -0,0 +1,129 @@ +// clang-format off + +/* + cache.h + The cache is not visible to the user. It should be flushed + when any file is closed or changes are made to the filesystem. + + This cache implements a least-used-page replacement policy. This will + distribute sectors evenly over the pages, so if less than the maximum + pages are used at once, they should all eventually remain in the cache. + This also has the benefit of throwing out old sectors, so as not to keep + too many stale pages around. + + Copyright (c) 2006 Michael "Chishm" Chisholm + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _CACHE_H +#define _CACHE_H + +#include "fatcommon.h" + +typedef struct { + sec_t sector; + unsigned int count; + unsigned int last_access; + bool dirty; + uint8_t* cache; +} CACHE_ENTRY; + +typedef struct { + const DISC_INTERFACE* disc; + sec_t endOfPartition; + unsigned int numberOfPages; + unsigned int sectorsPerPage; + unsigned int bytesPerSector; + CACHE_ENTRY* cacheEntries; +} CACHE; + +/* +Read data from a sector in the cache +If the sector is not in the cache, it will be swapped in +offset is the position to start reading from +size is the amount of data to read +Precondition: offset + size <= BYTES_PER_READ +*/ +bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size); + +bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes); + +/* +Write data to a sector in the cache +If the sector is not in the cache, it will be swapped in. +When the sector is swapped out, the data will be written to the disc +offset is the position to start writing to +size is the amount of data to write +Precondition: offset + size <= BYTES_PER_READ +*/ +bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size); + +bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int num_bytes); + +/* +Write data to a sector in the cache, zeroing the sector first +If the sector is not in the cache, it will be swapped in. +When the sector is swapped out, the data will be written to the disc +offset is the position to start writing to +size is the amount of data to write +Precondition: offset + size <= BYTES_PER_READ +*/ +bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size); + +/* +Read several sectors from the cache +*/ +bool _FAT_cache_readSectors (CACHE* cache, sec_t sector, sec_t numSectors, void* buffer); + +/* +Read a full sector from the cache +*/ +static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, sec_t sector) { + return _FAT_cache_readPartialSector (cache, buffer, sector, 0, cache->bytesPerSector); +} + +/* +Write a full sector to the cache +*/ +static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, sec_t sector) { + return _FAT_cache_writePartialSector (cache, buffer, sector, 0, cache->bytesPerSector); +} + +bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer); + +/* +Write any dirty sectors back to disc and clear out the contents of the cache +*/ +bool _FAT_cache_flush (CACHE* cache); + +/* +Clear out the contents of the cache without writing any dirty sectors first +*/ +void _FAT_cache_invalidate (CACHE* cache); + +CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, unsigned int bytesPerSector); + +void _FAT_cache_destructor (CACHE* cache); + +#endif // _CACHE_H + diff --git a/arm9/source/launcher/libfat_ext/directory.h b/arm9/source/launcher/libfat_ext/directory.h new file mode 100644 index 0000000..56afdcf --- /dev/null +++ b/arm9/source/launcher/libfat_ext/directory.h @@ -0,0 +1,182 @@ +// clang-format off + +/* + directory.h + Reading, writing and manipulation of the directory structure on + a FAT partition + + Copyright (c) 2006 Michael "Chishm" Chisholm + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _DIRECTORY_H +#define _DIRECTORY_H + +#include +#include + +#include "partition.h" + +#define DIR_ENTRY_DATA_SIZE 0x20 +#define MAX_LFN_LENGTH 256 +#define MAX_ALIAS_LENGTH 13 +#define LFN_ENTRY_LENGTH 13 +#define ALIAS_ENTRY_LENGTH 11 +#define MAX_ALIAS_EXT_LENGTH 3 +#define MAX_ALIAS_PRI_LENGTH 8 +#define MAX_NUMERIC_TAIL 999999 +#define FAT16_ROOT_DIR_CLUSTER 0 + +#define DIR_SEPARATOR '/' + +// File attributes +#define ATTRIB_ARCH 0x20 // Archive +#define ATTRIB_DIR 0x10 // Directory +#define ATTRIB_LFN 0x0F // Long file name +#define ATTRIB_VOL 0x08 // Volume +#define ATTRIB_SYS 0x04 // System +#define ATTRIB_HID 0x02 // Hidden +#define ATTRIB_RO 0x01 // Read only + +#define CASE_LOWER_EXT 0x10 // WinNT lowercase extension +#define CASE_LOWER_BASE 0x08 // WinNT lowercase basename + +typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE; + +typedef struct { + uint32_t cluster; + sec_t sector; + int32_t offset; +} DIR_ENTRY_POSITION; + +typedef struct { + uint8_t entryData[DIR_ENTRY_DATA_SIZE]; + DIR_ENTRY_POSITION dataStart; // Points to the start of the LFN entries of a file, or the alias for no LFN + DIR_ENTRY_POSITION dataEnd; // Always points to the file/directory's alias entry + char filename[NAME_MAX]; +} DIR_ENTRY; + +// Directory entry offsets +enum DIR_ENTRY_offset { + DIR_ENTRY_name = 0x00, + DIR_ENTRY_extension = 0x08, + DIR_ENTRY_attributes = 0x0B, + DIR_ENTRY_caseInfo = 0x0C, + DIR_ENTRY_cTime_ms = 0x0D, + DIR_ENTRY_cTime = 0x0E, + DIR_ENTRY_cDate = 0x10, + DIR_ENTRY_aDate = 0x12, + DIR_ENTRY_clusterHigh = 0x14, + DIR_ENTRY_mTime = 0x16, + DIR_ENTRY_mDate = 0x18, + DIR_ENTRY_cluster = 0x1A, + DIR_ENTRY_fileSize = 0x1C +}; + +/* +Returns true if the file specified by entry is a directory +*/ +static inline bool _FAT_directory_isDirectory (DIR_ENTRY* entry) { + return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR) != 0); +} + +static inline bool _FAT_directory_isWritable (DIR_ENTRY* entry) { + return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO) == 0); +} + +static inline bool _FAT_directory_isDot (DIR_ENTRY* entry) { + return ((entry->filename[0] == '.') && ((entry->filename[1] == '\0') || + ((entry->filename[1] == '.') && entry->filename[2] == '\0'))); +} + +/* +Reads the first directory entry from the directory starting at dirCluster +Places result in entry +entry will be destroyed even if no directory entry is found +Returns true on success, false on failure +*/ +bool _FAT_directory_getFirstEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster); + +/* +Reads the next directory entry after the one already pointed to by entry +Places result in entry +entry will be destroyed even if no directory entry is found +Returns true on success, false on failure +*/ +bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry); + +/* +Gets the directory entry corrsponding to the supplied path +entry will be destroyed even if no directory entry is found +pathEnd specifies the end of the path string, for cutting strings short if needed + specify NULL to use the full length of path + pathEnd is only a suggestion, and the path string will be searched up until the next PATH_SEPARATOR + after pathEND. +Returns true on success, false on failure +*/ +bool _FAT_directory_entryFromPath (PARTITION* partition, DIR_ENTRY* entry, const char* path, const char* pathEnd); + +/* +Changes the current directory to the one specified by path +Returns true on success, false on failure +*/ +bool _FAT_directory_chdir (PARTITION* partition, const char* path); + +/* +Removes the directory entry specified by entry +Assumes that entry is valid +Returns true on success, false on failure +*/ +bool _FAT_directory_removeEntry (PARTITION* partition, DIR_ENTRY* entry); + +/* +Add a directory entry to the directory specified by dirCluster +The fileData, dataStart and dataEnd elements of the DIR_ENTRY struct are +updated with the new directory entry position and alias. +Returns true on success, false on failure +*/ +bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster); + +/* +Get the start cluster of a file from it's entry data +*/ +uint32_t _FAT_directory_entryGetCluster (PARTITION* partition, const uint8_t* entryData); + +/* +Fill in the file name and entry data of DIR_ENTRY* entry. +Assumes that the entry's dataStart and dataEnd are correct +Returns true on success, false on failure +*/ +bool _FAT_directory_entryFromPosition (PARTITION* partition, DIR_ENTRY* entry); + +/* +Fill in a stat struct based on a file entry +*/ +void _FAT_directory_entryStat (PARTITION* partition, DIR_ENTRY* entry, struct stat *st); + +/* +Get volume label +*/ +bool _FAT_directory_getVolumeLabel (PARTITION* partition, char *label); + +#endif // _DIRECTORY_H diff --git a/arm9/source/launcher/libfat_ext/fat_ext.h b/arm9/source/launcher/libfat_ext/fat_ext.h new file mode 100644 index 0000000..2384bbb --- /dev/null +++ b/arm9/source/launcher/libfat_ext/fat_ext.h @@ -0,0 +1,28 @@ +// clang-format off + +#ifndef _LIBFAT_EXT_H +#define _LIBFAT_EXT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include + +/* +Get Alias Name +*/ +extern void fatGetAliasName (const char* drive, const char* name, char *alias); + +/* +Get Alias Path +*/ +extern void fatGetAliasPath (const char* drive, const char* path, char *alias); + +#ifdef __cplusplus +} +#endif + +#endif // _LIBFAT_EXT_H diff --git a/arm9/source/launcher/libfat_ext/fatcommon.h b/arm9/source/launcher/libfat_ext/fatcommon.h new file mode 100644 index 0000000..9fd61e8 --- /dev/null +++ b/arm9/source/launcher/libfat_ext/fatcommon.h @@ -0,0 +1,48 @@ +// clang-format off + +/* + common.h + Common definitions and included files for the FATlib + + Copyright (c) 2006 Michael "Chishm" Chisholm + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _FAT_COMMON_H +#define _FAT_COMMON_H + +#include +#include +#include + +// Platform specific includes +#include +#include +#include + +// Platform specific options +#define DEFAULT_CACHE_PAGES 16 +#define DEFAULT_SECTORS_PAGE 8 +#define USE_RTC_TIME + +#endif // _FAT_COMMON_H diff --git a/arm9/source/launcher/libfat_ext/libfat_ext.c b/arm9/source/launcher/libfat_ext/libfat_ext.c new file mode 100644 index 0000000..1962346 --- /dev/null +++ b/arm9/source/launcher/libfat_ext/libfat_ext.c @@ -0,0 +1,141 @@ +// clang-format off + +#include +#include +#include +#include +#include +#include + +static inline void* _FAT_mem_allocate (size_t size) { + return malloc (size); +} + +static inline void* _FAT_mem_align (size_t size) { + return malloc (size); +} + +static inline void _FAT_mem_free (void* mem) { + free (mem); +} + +#include "directory.h" +#include "partition.h" +#include "tonccpy.h" + +//static int timesRan = 0; + +static int fatGetAlias (const char* drive, const char* name, const char* nameEnd, char *alias) { + devoptab_t *devops; + PARTITION* partition; + DIR_ENTRY entry; + char *buf; + int drivelen/*,namelen*/,i; + + if (!drive || !name) + return -1; + + drivelen = strlen(drive); + //namelen = strlen(name); + buf=(char*)_FAT_mem_allocate(sizeof(char)*drivelen+2); + strcpy(buf,drive); + + if (drive[drivelen-1] == '/') { + buf[drivelen-1]='\0'; + drivelen--; + } + + if (drive[drivelen-1] != ':') { + buf[drivelen]=':'; + buf[drivelen+1]='\0'; + } + + /*if (name[namelen-1] == '/') { + name[namelen-1]='\0'; + namelen--; + }*/ + + devops = (devoptab_t*)GetDeviceOpTab(buf); + + for (i=0;buf[i]!='\0' && buf[i]!=':';i++); + if (!devops || strncasecmp(buf,devops->name,i)) { + _FAT_mem_free(buf); + return -1; + } + + _FAT_mem_free(buf); + + partition = (PARTITION*)devops->deviceData; + + int resultLen = 0; + + if (_FAT_directory_entryFromPath(partition, &entry, name, nameEnd)) { + tonccpy(alias,&entry.entryData,8); + int i = 0; + if (strncmp((char*)entry.entryData+8, " ", 3) != 0) { + for (i = 0; i < 8; i++) { + if (entry.entryData[i] == ' ') { + break; + } + } + alias[i] = '.'; + alias[i+1] = entry.entryData[8]; + alias[i+2] = entry.entryData[9]; + alias[i+3] = entry.entryData[10]; + alias[i+4] = '\0'; + resultLen = i+4; + } else { + for (i = 0; i <= 8; i++) { + if (entry.entryData[i] == ' ') { + alias[i] = _FAT_directory_isDirectory(&entry) ? '\x2F' : '\0'; + break; + } + } + resultLen = i+1; + } + /*tonccpy((char*)0x02800000+(timesRan*0x20), entry.entryData, 0x20); + tonccpy((char*)0x02800100+(timesRan*0x10), alias, 12); + timesRan++;*/ + } + + return resultLen; +} + +void fatGetAliasName (const char* drive, const char* name, char *alias) { + fatGetAlias (drive, name, NULL, alias); +} + +void fatGetAliasPath (const char* drive, const char* path, char *alias) { + char dirBak[PATH_MAX]; + getcwd(dirBak, PATH_MAX); + chdir(drive); + + char name[128]; + int len = (int)strlen(drive); + int lfnLen = len; + if (path[0] == '\x2F') { + len = 1; + lfnLen = len; + } + int nameEnd = 0; + tonccpy(alias, drive, len); + + for (int i = len; i < 256; i++) { + for (nameEnd = 0; nameEnd < 128; nameEnd++) { + name[nameEnd] = path[i+nameEnd]; + if (path[i+nameEnd] == '\0' || path[i+nameEnd] == '\x2F' /*|| path[i+nameEnd] == '\x5C'*/) { + name[nameEnd] = '\0'; + break; + } + } + //tonccpy((char*)0x02800040+(timesRan*0x10), name, nameEnd); + len += fatGetAlias (drive, path+lfnLen, path+lfnLen+nameEnd, alias+len); + lfnLen += nameEnd+1; + i += nameEnd; + //timesRan++; + if (path[i] == '\0') break; + chdir(name); + } + + chdir(dirBak); +} diff --git a/arm9/source/launcher/libfat_ext/lock.h b/arm9/source/launcher/libfat_ext/lock.h new file mode 100644 index 0000000..de67bd6 --- /dev/null +++ b/arm9/source/launcher/libfat_ext/lock.h @@ -0,0 +1,74 @@ +// clang-format off + +/* + lock.h + + Copyright (c) 2008 Sven Peter + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef _LOCK_H +#define _LOCK_H + +#include "fatcommon.h" + +#ifdef USE_LWP_LOCK + +static inline void _FAT_lock_init(mutex_t *mutex) +{ + LWP_MutexInit(mutex, false); +} + +static inline void _FAT_lock_deinit(mutex_t *mutex) +{ + LWP_MutexDestroy(*mutex); +} + +static inline void _FAT_lock(mutex_t *mutex) +{ + LWP_MutexLock(*mutex); +} + +static inline void _FAT_unlock(mutex_t *mutex) +{ + LWP_MutexUnlock(*mutex); +} + +#else + +// We still need a blank lock type +#ifndef mutex_t +typedef int mutex_t; +#endif + +void _FAT_lock_init(mutex_t *mutex); +void _FAT_lock_deinit(mutex_t *mutex); +void _FAT_lock(mutex_t *mutex); +void _FAT_unlock(mutex_t *mutex); + +#endif // USE_LWP_LOCK + + +#endif // _LOCK_H + diff --git a/arm9/source/launcher/libfat_ext/partition.h b/arm9/source/launcher/libfat_ext/partition.h new file mode 100644 index 0000000..138178d --- /dev/null +++ b/arm9/source/launcher/libfat_ext/partition.h @@ -0,0 +1,108 @@ +// clang-format off + +/* + partition.h + Functions for mounting and dismounting partitions + on various block devices. + + Copyright (c) 2006 Michael "Chishm" Chisholm + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _PARTITION_H +#define _PARTITION_H + +#include "cache.h" +#include "lock.h" + +#define MIN_SECTOR_SIZE 512 +#define MAX_SECTOR_SIZE 4096 + +// Filesystem type +typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE; + +typedef struct { + sec_t fatStart; + uint32_t sectorsPerFat; + uint32_t lastCluster; + uint32_t firstFree; + uint32_t numberFreeCluster; + uint32_t numberLastAllocCluster; +} FAT; + +typedef struct { + const DISC_INTERFACE* disc; + CACHE* cache; + // Info about the partition + FS_TYPE filesysType; + uint64_t totalSize; + sec_t rootDirStart; + uint32_t rootDirCluster; + uint32_t numberOfSectors; + sec_t dataStart; + uint32_t bytesPerSector; + uint32_t sectorsPerCluster; + uint32_t bytesPerCluster; + uint32_t fsInfoSector; + FAT fat; + // Values that may change after construction + uint32_t cwdCluster; // Current working directory cluster + int openFileCount; + struct _FILE_STRUCT* firstOpenFile; // The start of a linked list of files + mutex_t lock; // A lock for partition operations + bool readOnly; // If this is set, then do not try writing to the disc + char label[12]; // Volume label +} PARTITION; + +/* +Mount the supplied device and return a pointer to the struct necessary to use it +*/ +PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t SectorsPerPage, sec_t startSector); + +/* +Dismount the device and free all structures used. +Will also attempt to synchronise all open files to disc. +*/ +void _FAT_partition_destructor (PARTITION* partition); + +/* +Return the partition specified in a path, as taken from the devoptab. +*/ +PARTITION* _FAT_partition_getPartitionFromPath (const char* path); + +/* +Create the fs info sector. +*/ +void _FAT_partition_createFSinfo(PARTITION * partition); + +/* +Read the fs info sector data. +*/ +void _FAT_partition_readFSinfo(PARTITION * partition); + +/* +Write the fs info sector data. +*/ +void _FAT_partition_writeFSinfo(PARTITION * partition); + +#endif // _PARTITION_H diff --git a/arm9/source/launcher/libfat_ext/tonccpy.c b/arm9/source/launcher/libfat_ext/tonccpy.c new file mode 100644 index 0000000..833644e --- /dev/null +++ b/arm9/source/launcher/libfat_ext/tonccpy.c @@ -0,0 +1,134 @@ +// clang-format off + +#include "tonccpy.h" +#include + +//# tonccpy.c + +//! VRAM-safe cpy. +/*! This version mimics memcpy in functionality, with + the benefit of working for VRAM as well. It is also + slightly faster than the original memcpy, but faster + implementations can be made. + \param dst Destination pointer. + \param src Source pointer. + \param size Fill-length in bytes. + \note The pointers and size need not be word-aligned. +*/ +void tonccpy(void *dst, const void *src, uint size) +{ + if (size == 0 || dst == NULL || src == NULL) + return; + + uint count; + u16 *dst16; // hword destination + u8 *src8; // byte source + + // Ideal case: copy by 4x words. Leaves tail for later. + if (((u32)src|(u32)dst) %4 == 0 && size >= 4) { + u32 *src32= (u32*)src, *dst32= (u32*)dst; + + count = size/4; + uint tmp = count&3; + count /= 4; + + // Duff's Device, good friend! + switch(tmp) { + do { *dst32++ = *src32++; + case 3: *dst32++ = *src32++; + case 2: *dst32++ = *src32++; + case 1: *dst32++ = *src32++; + case 0: ; } while (count--); + } + + // Check for tail + size &= 3; + if (size == 0) + return; + + src8 = (u8*)src32; + dst16 = (u16*)dst32; + } else { + // Unaligned + + uint dstOfs = (u32)dst&1; + src8 = (u8*)src; + dst16 = (u16*)(dst-dstOfs); + + // Head: 1 byte. + if (dstOfs != 0) { + *dst16 = (*dst16 & 0xFF) | *src8++<<8; + dst16++; + if (--size == 0) + return; + } + } + + // Unaligned main: copy by 2x byte. + count = size/2; + while (count--) { + *dst16++ = src8[0] | src8[1]<<8; + src8 += 2; + } + + // Tail: 1 byte. + if (size & 1) + *dst16 = (*dst16 &~ 0xFF) | *src8; +} +//# toncset.c + +//! VRAM-safe memset, internal routine. +/*! This version mimics memset in functionality, with + the benefit of working for VRAM as well. It is also + slightly faster than the original memset. + \param dst Destination pointer. + \param fill Word to fill with. + \param size Fill-length in bytes. + \note The \a dst pointer and \a size need not be + word-aligned. In the case of unaligned fills, \a fill + will be masked off to match the situation. +*/ +void __toncset(void *dst, u32 fill, uint size) +{ + if (size == 0 || dst == NULL) + return; + + uint left = (u32)dst&3; + u32 *dst32 = (u32*)(dst-left); + u32 count, mask; + + // Unaligned head. + if (left != 0) { + // Adjust for very small stint. + if (left + size < 4) { + mask = BIT_MASK(size*8)<<(left*8); + *dst32 = (*dst32 &~ mask) | (fill & mask); + return; + } + + mask = BIT_MASK(left*8); + *dst32 = (*dst32 & mask) | (fill&~mask); + dst32++; + size -= 4 - left; + } + + // Main stint. + count = size/4; + uint tmp = count&3; + count /= 4; + + switch(tmp) { + do { *dst32++ = fill; + case 3: *dst32++ = fill; + case 2: *dst32++ = fill; + case 1: *dst32++ = fill; + case 0: ; } while (count--); + } + + // Tail + size &= 3; + if (size) { + mask= BIT_MASK(size*8); + *dst32= (*dst32 &~ mask) | (fill & mask); + } +} \ No newline at end of file diff --git a/arm9/source/launcher/libfat_ext/tonccpy.h b/arm9/source/launcher/libfat_ext/tonccpy.h new file mode 100644 index 0000000..952b660 --- /dev/null +++ b/arm9/source/launcher/libfat_ext/tonccpy.h @@ -0,0 +1,45 @@ +// clang-format off + +//# Stuff you may not have yet. + +#ifndef TONCCPY_H +#define TONCCPY_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef unsigned int uint; +#define BIT_MASK(len) ( (1<<(len))-1 ) +static inline u32 quad8(u16 x) { x |= x<<8; return x | x<<16; } + + +//# Declarations and inlines. + +void tonccpy(void *dst, const void *src, uint size); + +void __toncset(void *dst, u32 fill, uint size); +static inline void toncset(void *dst, u8 src, uint size); +static inline void toncset16(void *dst, u16 src, uint size); +static inline void toncset32(void *dst, u32 src, uint size); + + +//! VRAM-safe memset, byte version. Size in bytes. +static inline void toncset(void *dst, u8 src, uint size) +{ __toncset(dst, quad8(src), size); } + +//! VRAM-safe memset, halfword version. Size in hwords. +static inline void toncset16(void *dst, u16 src, uint size) +{ __toncset(dst, src|src<<16, size*2); } + +//! VRAM-safe memset, word version. Size in words. +static inline void toncset32(void *dst, u32 src, uint size) +{ __toncset(dst, src, size*4); } + +#ifdef __cplusplus +} +#endif +#endif diff --git a/arm9_tt/Makefile b/arm9_tt/Makefile index 15e3696..9a837cf 100644 --- a/arm9_tt/Makefile +++ b/arm9_tt/Makefile @@ -17,7 +17,7 @@ SOURCE_PATH := ../arm9 # all directories are relative to this makefile #--------------------------------------------------------------------------------- BUILD := build -SOURCES := $(SOURCE_PATH)/source $(SOURCE_PATH)/source/ui $(SOURCE_PATH)/source/font $(SOURCE_PATH)/source/launcher $(SOURCE_PATH)/source/saves +SOURCES := $(SOURCE_PATH)/source $(SOURCE_PATH)/source/ui $(SOURCE_PATH)/source/font $(SOURCE_PATH)/source/launcher $(SOURCE_PATH)/source/launcher/libfat_ext $(SOURCE_PATH)/source/saves INCLUDES := $(SOURCE_PATH)/include ../share $(SOURCES) DATA := $(SOURCE_PATH)/data ../data GRAPHICS :=