blob: 540ee89b548739cd7cfd0a58507f68fd37953c0e [file] [log] [blame]
Frank Gevaerts2b9e9442011-09-02 21:34:28 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: fat32format.c 30351 2011-08-25 19:58:47Z thomasjfox $
9 *
10 *
11 * FAT32 formatting functions. Based on:
12 *
13 * Fat32 formatter version 1.03
14 * (c) Tom Thornhill 2005
15 * This software is covered by the GPL.
16 * By using this tool, you agree to absolve Ridgecrop of an liabilities for
17 * lost data.
18 * Please backup any data you value before using this tool.
19 *
20 *
21 * Modified June 2007 by Dave Chapman for use in ipodpatcher
22 * Modified September 2011 by Frank Gevaerts for use in sansa eraser
23 *
24 *
25 * This program is free software; you can redistribute it and/or
26 * modify it under the terms of the GNU General Public License
27 * as published by the Free Software Foundation; either version 2
28 * of the License, or (at your option) any later version.
29 *
30 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
31 * KIND, either express or implied.
32 *
33 ****************************************************************************/
34
35#include <stdio.h>
36#include <stdlib.h>
37#include "common.h"
38#include "cpu.h"
39#include "file.h"
40#include "system.h"
41#include "kernel.h"
42#include "lcd.h"
43#include "font.h"
44#include "storage.h"
45#include "button.h"
46#include "disk.h"
47#include "crc32-mi4.h"
48#include <string.h>
49#include "i2c.h"
50#include "backlight-target.h"
51#include "power.h"
52
53#define SECTOR_SIZE 512
54
55/* The following functions are not the most efficient, but are
56 self-contained and don't require needing to know endianness of CPU
57 at compile-time.
58
59 Note that htole16/htole32 exist on some platforms, so for
60 simplicity we use different names.
61
62*/
63
64static uint16_t rb_htole16(uint16_t x)
65{
66 uint16_t test = 0x1234;
67 unsigned char* p = (unsigned char*)&test;
68
69 if (p[0]==0x12) {
70 /* Big-endian */
71 return swap16(x);
72 } else {
73 return x;
74 }
75}
76
77static uint32_t rb_htole32(uint32_t x)
78{
79 uint32_t test = 0x12345678;
80 unsigned char* p = (unsigned char*)&test;
81
82 if (p[0]==0x12) {
83 /* Big-endian */
84 return swap32(x);
85 } else {
86 return x;
87 }
88}
89
90
91/* A large aligned buffer for disk I/O */
92unsigned char sectorbuf[128*SECTOR_SIZE];
93
94/* TODO: Pass these as parameters to the various create_ functions */
95
96/* can be zero for default or 1,2,4,8,16,32 or 64 */
97static int sectors_per_cluster = 0;
98
99/* Recommended values */
100static uint32_t ReservedSectCount = 32;
101static uint32_t NumFATs = 2;
102static uint32_t BackupBootSect = 6;
103static uint32_t VolumeId=0; /* calculated before format */
104
105/* Calculated later */
106static uint32_t FatSize=0;
107static uint32_t BytesPerSect=0;
108static uint32_t SectorsPerCluster=0;
109static uint32_t TotalSectors=0;
110static uint32_t SystemAreaSize=0;
111static uint32_t UserAreaSize=0;
112static uint8_t VolId[12] = "NO NAME ";
113
114
115struct FAT_BOOTSECTOR32
116{
117 /* Common fields. */
118 uint8_t sJmpBoot[3];
119 char sOEMName[8];
120 uint16_t wBytsPerSec;
121 uint8_t bSecPerClus;
122 uint16_t wRsvdSecCnt;
123 uint8_t bNumFATs;
124 uint16_t wRootEntCnt;
125 uint16_t wTotSec16; /* if zero, use dTotSec32 instead */
126 uint8_t bMedia;
127 uint16_t wFATSz16;
128 uint16_t wSecPerTrk;
129 uint16_t wNumHeads;
130 uint32_t dHiddSec;
131 uint32_t dTotSec32;
132
133 /* Fat 32/16 only */
134 uint32_t dFATSz32;
135 uint16_t wExtFlags;
136 uint16_t wFSVer;
137 uint32_t dRootClus;
138 uint16_t wFSInfo;
139 uint16_t wBkBootSec;
140 uint8_t Reserved[12];
141 uint8_t bDrvNum;
142 uint8_t Reserved1;
143 uint8_t bBootSig; /* == 0x29 if next three fields are ok */
144 uint32_t dBS_VolID;
145 uint8_t sVolLab[11];
146 uint8_t sBS_FilSysType[8];
147} __attribute__((packed));
148
149struct FAT_FSINFO {
150 uint32_t dLeadSig; // 0x41615252
151 uint8_t sReserved1[480]; // zeros
152 uint32_t dStrucSig; // 0x61417272
153 uint32_t dFree_Count; // 0xFFFFFFFF
154 uint32_t dNxt_Free; // 0xFFFFFFFF
155 uint8_t sReserved2[12]; // zeros
156 uint32_t dTrailSig; // 0xAA550000
157} __attribute__((packed));
158
159
160/* Write "count" zero sectors, starting at sector "sector" */
161static int zero_sectors(uint32_t sector, int count)
162{
163 int n;
164
165 memset(sectorbuf, 0, 128 * SECTOR_SIZE);
166
167 /* Write 128 sectors at a time */
168 while (count) {
169 if (count >= 128)
170 n = 128;
171 else
172 n = count;
173
174 if (storage_write_sectors(sector,n,sectorbuf) < 0) {
175 printf("[ERR] Write failed in zero_sectors\n");
176 return -1;
177 }
178 sector += n;
179 count -= n;
180 }
181
182 return 0;
183}
184
185
186/*
18728.2 CALCULATING THE VOLUME SERIAL NUMBER
188
189For example, say a disk was formatted on 26 Dec 95 at 9:55 PM and 41.94
190seconds. DOS takes the date and time just before it writes it to the
191disk.
192
193Low order word is calculated: Volume Serial Number is:
194 Month & Day 12/26 0c1ah
195 Sec & Hundrenths 41:94 295eh 3578:1d02
196 -----
197 3578h
198
199High order word is calculated:
200 Hours & Minutes 21:55 1537h
201 Year 1995 07cbh
202 -----
203 1d02h
204*/
205static uint32_t get_volume_id ( void )
206{
207 /* TODO */
208#if 0
209 SYSTEMTIME s;
210 uint32_t d;
211 uint16_t lo,hi,tmp;
212
213 GetLocalTime( &s );
214
215 lo = s.wDay + ( s.wMonth << 8 );
216 tmp = (s.wMilliseconds/10) + (s.wSecond << 8 );
217 lo += tmp;
218
219 hi = s.wMinute + ( s.wHour << 8 );
220 hi += s.wYear;
221
222 d = lo + (hi << 16);
223 return(d);
224#endif
225 return(0);
226}
227
228/*
229This is the Microsoft calculation from FATGEN
230
231 uint32_t RootDirSectors = 0;
232 uint32_t TmpVal1, TmpVal2, FATSz;
233
234 TmpVal1 = DskSize - ( ReservedSecCnt + RootDirSectors);
235 TmpVal2 = (256 * SecPerClus) + NumFATs;
236 TmpVal2 = TmpVal2 / 2;
237 FATSz = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
238
239 return( FatSz );
240*/
241
242
243static uint32_t get_fat_size_sectors(uint32_t DskSize, uint32_t ReservedSecCnt,
244 uint32_t SecPerClus, uint32_t NumFATs,
245 uint32_t BytesPerSect)
246{
247 uint32_t Numerator, Denominator;
248 uint32_t FatElementSize = 4;
249 uint32_t FatSz;
250
251 /* This is based on
252 http://hjem.get2net.dk/rune_moeller_barnkob/filesystems/fat.html
253 I've made the obvious changes for FAT32
254 */
255
256 Numerator = FatElementSize * ( DskSize - ReservedSecCnt );
257 Denominator = ( SecPerClus * BytesPerSect ) + ( FatElementSize * NumFATs );
258 FatSz = Numerator / Denominator;
259
260 /* round up */
261 FatSz += 1;
262
263 return((uint32_t)FatSz);
264}
265
266static uint8_t get_spc(uint32_t ClusterSizeKB, uint32_t BytesPerSect)
267{
268 uint32_t spc = ( ClusterSizeKB * 1024 ) / BytesPerSect;
269 return( (uint8_t) spc );
270}
271
272static uint8_t get_sectors_per_cluster(uint32_t DiskSizeSectors,
273 uint32_t BytesPerSect)
274{
275 uint8_t ret = 0x01; /* 1 sector per cluster */
276 int32_t DiskSizeMB = DiskSizeSectors / ( 1024*1024 / SECTOR_SIZE);
277
278 /* 512 MB to 8,191 MB 4 KB */
279 if ( DiskSizeMB > 512 )
280 ret = get_spc( 4, BytesPerSect ); /* ret = 0x8; */
281
282 /* 8,192 MB to 16,383 MB 8 KB */
283 if ( DiskSizeMB > 8192 )
284 ret = get_spc( 8, BytesPerSect ); /* ret = 0x10; */
285
286 /* 16,384 MB to 32,767 MB 16 KB */
287 if ( DiskSizeMB > 16384 )
288 ret = get_spc( 16, BytesPerSect ); /* ret = 0x20; */
289
290 /* Larger than 32,768 MB 32 KB */
291 if ( DiskSizeMB > 32768 )
292 ret = get_spc( 32, BytesPerSect ); /* ret = 0x40; */
293
294 return( ret );
295
296}
297
298static void create_boot_sector(unsigned char* buf)
299{
300 struct FAT_BOOTSECTOR32* pFAT32BootSect = (struct FAT_BOOTSECTOR32*)buf;
301
302 /* fill out the boot sector and fs info */
303 pFAT32BootSect->sJmpBoot[0]=0xEB;
304 pFAT32BootSect->sJmpBoot[1]=0x5A;
305 pFAT32BootSect->sJmpBoot[2]=0x90;
306 memcpy(pFAT32BootSect->sOEMName, "MSWIN4.1", 8 );
307 pFAT32BootSect->wBytsPerSec = rb_htole16(BytesPerSect);
308 pFAT32BootSect->bSecPerClus = SectorsPerCluster ;
309 pFAT32BootSect->wRsvdSecCnt = rb_htole16(ReservedSectCount);
310 pFAT32BootSect->bNumFATs = NumFATs;
311 pFAT32BootSect->wRootEntCnt = rb_htole16(0);
312 pFAT32BootSect->wTotSec16 = rb_htole16(0);
313 pFAT32BootSect->bMedia = 0xF8;
314 pFAT32BootSect->wFATSz16 = rb_htole16(0);
315 pFAT32BootSect->wSecPerTrk = 63;
316 pFAT32BootSect->wNumHeads = 255;
317 pFAT32BootSect->dHiddSec = 0;
318 pFAT32BootSect->dTotSec32 = rb_htole32(TotalSectors);
319 pFAT32BootSect->dFATSz32 = rb_htole32(FatSize);
320 pFAT32BootSect->wExtFlags = rb_htole16(0);
321 pFAT32BootSect->wFSVer = rb_htole16(0);
322 pFAT32BootSect->dRootClus = rb_htole32(2);
323 pFAT32BootSect->wFSInfo = rb_htole16(1);
324 pFAT32BootSect->wBkBootSec = rb_htole16(BackupBootSect);
325 pFAT32BootSect->bDrvNum = 0x80;
326 pFAT32BootSect->Reserved1 = 0;
327 pFAT32BootSect->bBootSig = 0x29;
328 pFAT32BootSect->dBS_VolID = rb_htole32(VolumeId);
329 memcpy(pFAT32BootSect->sVolLab, VolId, 11);
330 memcpy(pFAT32BootSect->sBS_FilSysType, "FAT32 ", 8 );
331
332 buf[510] = 0x55;
333 buf[511] = 0xaa;
334}
335
336static void create_fsinfo(unsigned char* buf)
337{
338 struct FAT_FSINFO* pFAT32FsInfo = (struct FAT_FSINFO*)buf;
339
340 /* FSInfo sect */
341 pFAT32FsInfo->dLeadSig = rb_htole32(0x41615252);
342 pFAT32FsInfo->dStrucSig = rb_htole32(0x61417272);
343 pFAT32FsInfo->dFree_Count = rb_htole32((uint32_t) -1);
344 pFAT32FsInfo->dNxt_Free = rb_htole32((uint32_t) -1);
345 pFAT32FsInfo->dTrailSig = rb_htole32(0xaa550000);
346 pFAT32FsInfo->dFree_Count = rb_htole32((UserAreaSize/SectorsPerCluster)-1);
347
348 /* clusters 0-1 reserved, we used cluster 2 for the root dir */
349 pFAT32FsInfo->dNxt_Free = rb_htole32(3);
350}
351
352static void create_firstfatsector(unsigned char* buf)
353{
354 uint32_t* p = (uint32_t*)buf; /* We know the buffer is aligned */
355
356 /* First FAT Sector */
357 p[0] = rb_htole32(0x0ffffff8); /* Reserved cluster 1 media id in low byte */
358 p[1] = rb_htole32(0x0fffffff); /* Reserved cluster 2 EOC */
359 p[2] = rb_htole32(0x0fffffff); /* end of cluster chain for root dir */
360}
361
362int format_partition(int start, int size)
363{
364 uint32_t i;
365 uint32_t qTotalSectors=0;
366 uint32_t FatNeeded;
367
368 VolumeId = get_volume_id( );
369
370 /* Only support hard disks at the moment */
371 if ( SECTOR_SIZE != 512 )
372 {
373 printf("[ERR] Only disks with 512 bytes per sector are supported.\n");
374 return -1;
375 }
376 BytesPerSect = SECTOR_SIZE;
377
378 /* Checks on Disk Size */
379 qTotalSectors = size;
380
381 /* low end limit - 65536 sectors */
382 if ( qTotalSectors < 65536 )
383 {
384 /* I suspect that most FAT32 implementations would mount this
385 volume just fine, but the spec says that we shouldn't do
386 this, so we won't */
387
388 printf("[ERR] This drive is too small for FAT32 - there must be at least 64K clusters\n" );
389 return -1;
390 }
391
392 if ( qTotalSectors >= 0xffffffff )
393 {
394 /* This is a more fundamental limitation on FAT32 - the total
395 sector count in the root dir is 32bit. With a bit of
396 creativity, FAT32 could be extended to handle at least 2^28
397 clusters There would need to be an extra field in the
398 FSInfo sector, and the old sector count could be set to
399 0xffffffff. This is non standard though, the Windows FAT
400 driver FASTFAT.SYS won't understand this. Perhaps a future
401 version of FAT32 and FASTFAT will handle this. */
402
403 printf("[ERR] This drive is too big for FAT32 - max 2TB supported\n");
404 }
405
406 if ( sectors_per_cluster ) {
407 SectorsPerCluster = sectors_per_cluster;
408 } else {
409 SectorsPerCluster = get_sectors_per_cluster(size,
410 BytesPerSect );
411 }
412
413 TotalSectors = (uint32_t) qTotalSectors;
414
415 FatSize = get_fat_size_sectors(TotalSectors, ReservedSectCount,
416 SectorsPerCluster, NumFATs, BytesPerSect );
417
418 UserAreaSize = TotalSectors - ReservedSectCount - (NumFATs*FatSize);
419
420 /* First zero out ReservedSect + FatSize * NumFats + SectorsPerCluster */
421 SystemAreaSize = (ReservedSectCount+(NumFATs*FatSize) + SectorsPerCluster);
422
423 /* Work out the Cluster count */
424 FatNeeded = UserAreaSize/SectorsPerCluster;
425
426 /* check for a cluster count of >2^28, since the upper 4 bits of
427 the cluster values in the FAT are reserved. */
428 if (FatNeeded > 0x0FFFFFFF) {
429 printf("[ERR] This drive has more than 2^28 clusters, try to specify a larger cluster size\n" );
430 return -1;
431 }
432
433 /* Sanity check, make sure the fat is big enough.
434 Convert the cluster count into a Fat sector count, and check
435 the fat size value we calculated earlier is OK. */
436
437 FatNeeded *=4;
438 FatNeeded += (BytesPerSect-1);
439 FatNeeded /= BytesPerSect;
440
441 if ( FatNeeded > FatSize ) {
442 printf("[ERR] Drive too big to format\n");
443 return -1;
444 }
445
446 /*
447 Write boot sector, fats
448 Sector 0 Boot Sector
449 Sector 1 FSInfo
450 Sector 2 More boot code - we write zeros here
451 Sector 3 unused
452 Sector 4 unused
453 Sector 5 unused
454 Sector 6 Backup boot sector
455 Sector 7 Backup FSInfo sector
456 Sector 8 Backup 'more boot code'
457 zero'd sectors upto ReservedSectCount
458 FAT1 ReservedSectCount to ReservedSectCount + FatSize
459 ...
460 FATn ReservedSectCount to ReservedSectCount + FatSize
461 RootDir - allocated to cluster2
462 */
463
464
465 printf("[INFO] Formatting partition:...");
466
467 /* Once zero_sectors has run, any data on the drive is basically lost... */
468 printf("[INFO] Clearing out %d sectors for Reserved sectors, fats and root cluster...\n", SystemAreaSize );
469
470 zero_sectors(start, SystemAreaSize);
471
472 printf("[INFO] Initialising reserved sectors and FATs...\n" );
473
474 /* Create the boot sector structure */
475 create_boot_sector(sectorbuf);
476 create_fsinfo(sectorbuf + 512);
477
478 if (storage_write_sectors(start,2,sectorbuf)) {
479 printf("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
480 return -1;
481 }
482
483 if (storage_write_sectors(start + BackupBootSect,2,sectorbuf)) {
484 printf("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
485 return -1;
486 }
487
488 /* Create the first FAT sector */
489 create_firstfatsector(sectorbuf);
490
491 /* Write the first fat sector in the right places */
492 for ( i=0; i<NumFATs; i++ ) {
493 int SectorStart = ReservedSectCount + (i * FatSize );
494
495 if (storage_write_sectors(start + SectorStart,1,sectorbuf)) {
496 printf("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
497 return -1;
498 }
499 }
500
501 printf("[INFO] Format successful\n");
502
503 return 0;
504}