port-work; won't compile or even work
[ppcskel.git] / nandfs.c
1 /*
2         BootMii - a Free Software replacement for the Nintendo/BroadOn IOS.
3         Requires mini.
4
5         NAND filesystem support
6
7 Copyright (C) 2008, 2009        Sven Peter <svenpeter@gmail.com>
8
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
11 */
12
13 #include "bootmii_ppc.h"
14 #include "ipc.h"
15 #include "mini_ipc.h"
16 #include "nandfs.h"
17 #include "string.h"
18
19 #define PAGE_SIZE       2048
20 #define NANDFS_FREE     0xFFFE
21
22 static otp_t otp;
23
24 struct _nandfs_file_node {
25         char name[NANDFS_NAME_LEN];
26         u8 attr;
27         u8 wtf;
28         union {
29                 u16 first_child;
30                 u16 first_cluster;
31         };
32         u16 sibling;
33         u32 size;
34         u32 uid;
35         u16 gid;
36         u32 dummy;
37 } __attribute__((packed));
38
39 struct _nandfs_sffs {
40         u8 magic[4];
41         u32 version;
42         u32 dummy;
43
44         u16 cluster_table[32768];
45         struct _nandfs_file_node files[6143];
46 } __attribute__((packed));
47
48
49 union _sffs_t {
50         u8 buffer[16*8*2048];
51         struct _nandfs_sffs sffs;
52 };
53
54 static union _sffs_t sffs __attribute__((aligned(32)));
55
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;
60
61 void nand_read_cluster(u32 pageno, u8 *buffer)
62 {
63         int i;
64         for (i = 0; i < 8; i++)
65                 nand_read(pageno + i, buffer + (i * PAGE_SIZE), NULL);
66 }
67
68 void nand_read_decrypted_cluster(u32 pageno, u8 *buffer)
69 {
70         u8 iv[16] = {0,};
71         nand_read_cluster(pageno, buffer);
72
73         aes_reset();
74         aes_set_iv(iv);
75         aes_set_key(otp.nand_key);
76         aes_decrypt(buffer, buffer, 0x400, 0);
77 }
78
79 s32 nandfs_initialize(void)
80 {
81         u32 i;
82         u32 supercluster = 0;
83         u32 supercluster_version = 0;
84
85         getotp(&otp);
86
87         nand_reset();
88
89         for(i = 0x7F00; i < 0x7fff; i++) {
90                 nand_read(i*8, sffs.buffer, NULL);
91                 if(memcmp(sffs.sffs.magic, "SFFS", 4) != 0)
92                         continue;
93                 if(supercluster == 0 ||
94                    sffs.sffs.version > supercluster_version) {
95                         supercluster = i*8;
96                         supercluster_version = sffs.sffs.version;
97                 }
98         }
99
100         if(supercluster == 0) {
101                 printf("no supercluster found. "
102                              " your nand filesystem is seriously broken...\n");
103                 return -1;
104         }
105
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));
110         }
111
112         initialized = 1;
113         return 0;
114 }
115
116 u32 nandfs_get_usage(void) {
117         u32 i;
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++;
121                 
122         printf("Used clusters: %d\n", used_clusters);
123         return 1000 * used_clusters / (sizeof(sffs.sffs.cluster_table)/sizeof(u16));
124 }
125
126 s32 nandfs_open(struct nandfs_fp *fp, const char *path)
127 {
128         char *ptr, *ptr2;
129         u32 len;
130         struct _nandfs_file_node *cur = sffs.sffs.files;
131
132         if (initialized != 1)
133                 return -1;
134
135         memset(fp, 0, sizeof(*fp));
136
137         if(strcmp(cur->name, "/") != 0) {
138                 printf("your nandfs is corrupted. fixit!\n");
139                 return -1;
140         }
141
142         cur = &sffs.sffs.files[cur->first_child];
143
144         ptr = (char *)path;
145         do {
146                 ptr++;
147                 ptr2 = strchr(ptr, '/');
148                 if (ptr2 == NULL)
149                         len = strlen(ptr);
150                 else {
151                         ptr2++;
152                         len = ptr2 - ptr - 1;
153                 }
154                 if (len > 12)
155                 {
156                         printf("invalid length: %s %s %s [%d]\n",
157                                         ptr, ptr2, path, len);
158                         return -1;
159                 }
160
161                 for (;;) {
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];
167                                 ptr = ptr2-1;
168                                 break;
169                         } else if(ptr2 == NULL &&
170                                    strncmp(cur->name, ptr, len) == 0 &&
171                                    strnlen(cur->name, 12) == len &&
172                                    (cur->attr&3) == 1) {
173                                 break;
174                         } else if((cur->sibling&0xffff) != 0xffff) {
175                                 cur = &sffs.sffs.files[cur->sibling];
176                         } else {
177                                 return -1;
178                         }
179                 }
180                 
181         } while(ptr2 != NULL);
182
183         fp->first_cluster = cur->first_cluster;
184         fp->cur_cluster = fp->first_cluster;
185         fp->offset = 0;
186         fp->size = cur->size;
187         return 0;
188 }
189
190 s32 nandfs_read(void *ptr, u32 size, u32 nmemb, struct nandfs_fp *fp)
191 {
192         u32 total = size*nmemb;
193         u32 copy_offset, copy_len;
194
195         if (initialized != 1)
196                 return -1;
197
198         if (fp->offset + total > fp->size)
199                 total = fp->size - fp->offset;
200
201         if (total == 0)
202                 return 0;
203
204         while(total > 0) {
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;
208                 if(copy_len > total)
209                         copy_len = total;
210                 memcpy(ptr, buffer + copy_offset, copy_len);
211                 total -= copy_len;
212                 fp->offset += copy_len;
213
214                 if ((copy_offset + copy_len) >= (PAGE_SIZE * 8))
215                         fp->cur_cluster = sffs.sffs.cluster_table[fp->cur_cluster];
216         }
217
218         return size*nmemb;
219 }
220
221 s32 nandfs_seek(struct nandfs_fp *fp, s32 offset, u32 whence)
222 {
223         if (initialized != 1)
224                 return -1;
225
226         switch (whence) {
227         case NANDFS_SEEK_SET:
228                 if (offset < 0)
229                         return -1;
230                 if ((u32)offset > fp->size)
231                         return -1;
232
233                 fp->offset = offset;
234                 break;
235
236         case NANDFS_SEEK_CUR:
237                 if ((fp->offset + offset) > fp->size ||
238                     (s32)(fp->offset + offset) < 0)
239                         return -1;
240                 fp->offset += offset;
241                 break;
242
243         case NANDFS_SEEK_END:
244         default:
245                 if ((fp->size + offset) > fp->size ||
246                     (s32)(fp->size + offset) < 0)
247                         return -1;
248                 fp->offset = fp->size + offset;
249                 break;
250         }
251
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];
256                 skip -= 2048*8;
257         }
258
259         return 0;
260 }
261