2 BootMii - a Free Software replacement for the Nintendo/BroadOn IOS.
5 NAND filesystem support
7 Copyright (C) 2008, 2009 Sven Peter <svenpeter@gmail.com>
9 # This code is licensed to you under the terms of the GNU GPL, version 2;
10 # see file COPYING or http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
13 #include "bootmii_ppc.h"
19 #define PAGE_SIZE 2048
20 #define NANDFS_FREE 0xFFFE
24 struct _nandfs_file_node {
25 char name[NANDFS_NAME_LEN];
37 } __attribute__((packed));
44 u16 cluster_table[32768];
45 struct _nandfs_file_node files[6143];
46 } __attribute__((packed));
51 struct _nandfs_sffs sffs;
54 static union _sffs_t sffs __attribute__((aligned(32)));
56 /*static u8 _sffs_buffer[16*8*2048] __attribute__((aligned(32)));
57 static struct _nandfs_sffs *sffs = (struct _nandfs_sffs *)&_sffs_buffer;*/
58 static u8 buffer[8*2048] __attribute__((aligned(32)));
59 static s32 initialized = 0;
61 void nand_read_cluster(u32 pageno, u8 *buffer)
64 for (i = 0; i < 8; i++)
65 nand_read(pageno + i, buffer + (i * PAGE_SIZE), NULL);
68 void nand_read_decrypted_cluster(u32 pageno, u8 *buffer)
71 nand_read_cluster(pageno, buffer);
75 aes_set_key(otp.nand_key);
76 aes_decrypt(buffer, buffer, 0x400, 0);
79 s32 nandfs_initialize(void)
83 u32 supercluster_version = 0;
89 for(i = 0x7F00; i < 0x7fff; i++) {
90 nand_read(i*8, sffs.buffer, NULL);
91 if(memcmp(sffs.sffs.magic, "SFFS", 4) != 0)
93 if(supercluster == 0 ||
94 sffs.sffs.version > supercluster_version) {
96 supercluster_version = sffs.sffs.version;
100 if(supercluster == 0) {
101 printf("no supercluster found. "
102 " your nand filesystem is seriously broken...\n");
106 for(i = 0; i < 16; i++) {
107 printf("reading...\n");
108 nand_read_cluster(supercluster + i*8,
109 (sffs.buffer) + (i * PAGE_SIZE * 8));
116 u32 nandfs_get_usage(void) {
118 int used_clusters = 0;
119 for (i=0; i < sizeof(sffs.sffs.cluster_table) / sizeof(u16); i++)
120 if(sffs.sffs.cluster_table[i] != NANDFS_FREE) used_clusters++;
122 printf("Used clusters: %d\n", used_clusters);
123 return 1000 * used_clusters / (sizeof(sffs.sffs.cluster_table)/sizeof(u16));
126 s32 nandfs_open(struct nandfs_fp *fp, const char *path)
130 struct _nandfs_file_node *cur = sffs.sffs.files;
132 if (initialized != 1)
135 memset(fp, 0, sizeof(*fp));
137 if(strcmp(cur->name, "/") != 0) {
138 printf("your nandfs is corrupted. fixit!\n");
142 cur = &sffs.sffs.files[cur->first_child];
147 ptr2 = strchr(ptr, '/');
152 len = ptr2 - ptr - 1;
156 printf("invalid length: %s %s %s [%d]\n",
157 ptr, ptr2, path, len);
162 if(ptr2 != NULL && strncmp(cur->name, ptr, len) == 0
163 && strnlen(cur->name, 12) == len
164 && (cur->attr&3) == 2
165 && (s16)(cur->first_child&0xffff) != (s16)0xffff) {
166 cur = &sffs.sffs.files[cur->first_child];
169 } else if(ptr2 == NULL &&
170 strncmp(cur->name, ptr, len) == 0 &&
171 strnlen(cur->name, 12) == len &&
172 (cur->attr&3) == 1) {
174 } else if((cur->sibling&0xffff) != 0xffff) {
175 cur = &sffs.sffs.files[cur->sibling];
181 } while(ptr2 != NULL);
183 fp->first_cluster = cur->first_cluster;
184 fp->cur_cluster = fp->first_cluster;
186 fp->size = cur->size;
190 s32 nandfs_read(void *ptr, u32 size, u32 nmemb, struct nandfs_fp *fp)
192 u32 total = size*nmemb;
193 u32 copy_offset, copy_len;
195 if (initialized != 1)
198 if (fp->offset + total > fp->size)
199 total = fp->size - fp->offset;
205 nand_read_decrypted_cluster(fp->cur_cluster*8, buffer);
206 copy_offset = fp->offset % (PAGE_SIZE * 8);
207 copy_len = (PAGE_SIZE * 8) - copy_offset;
210 memcpy(ptr, buffer + copy_offset, copy_len);
212 fp->offset += copy_len;
214 if ((copy_offset + copy_len) >= (PAGE_SIZE * 8))
215 fp->cur_cluster = sffs.sffs.cluster_table[fp->cur_cluster];
221 s32 nandfs_seek(struct nandfs_fp *fp, s32 offset, u32 whence)
223 if (initialized != 1)
227 case NANDFS_SEEK_SET:
230 if ((u32)offset > fp->size)
236 case NANDFS_SEEK_CUR:
237 if ((fp->offset + offset) > fp->size ||
238 (s32)(fp->offset + offset) < 0)
240 fp->offset += offset;
243 case NANDFS_SEEK_END:
245 if ((fp->size + offset) > fp->size ||
246 (s32)(fp->size + offset) < 0)
248 fp->offset = fp->size + offset;
252 int skip = fp->offset;
253 fp->cur_cluster = fp->first_cluster;
254 while (skip > (2048*8)) {
255 fp->cur_cluster = sffs.sffs.cluster_table[fp->cur_cluster];