Support "eject" on OS X.
[maemo-rb.git] / bootloader / fat32format.c
blob540ee89b548739cd7cfd0a58507f68fd37953c0e
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: fat32format.c 30351 2011-08-25 19:58:47Z thomasjfox $
11 * FAT32 formatting functions. Based on:
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.
21 * Modified June 2007 by Dave Chapman for use in ipodpatcher
22 * Modified September 2011 by Frank Gevaerts for use in sansa eraser
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.
30 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
31 * KIND, either express or implied.
33 ****************************************************************************/
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"
53 #define SECTOR_SIZE 512
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.
59 Note that htole16/htole32 exist on some platforms, so for
60 simplicity we use different names.
64 static uint16_t rb_htole16(uint16_t x)
66 uint16_t test = 0x1234;
67 unsigned char* p = (unsigned char*)&test;
69 if (p[0]==0x12) {
70 /* Big-endian */
71 return swap16(x);
72 } else {
73 return x;
77 static uint32_t rb_htole32(uint32_t x)
79 uint32_t test = 0x12345678;
80 unsigned char* p = (unsigned char*)&test;
82 if (p[0]==0x12) {
83 /* Big-endian */
84 return swap32(x);
85 } else {
86 return x;
91 /* A large aligned buffer for disk I/O */
92 unsigned char sectorbuf[128*SECTOR_SIZE];
94 /* TODO: Pass these as parameters to the various create_ functions */
96 /* can be zero for default or 1,2,4,8,16,32 or 64 */
97 static int sectors_per_cluster = 0;
99 /* Recommended values */
100 static uint32_t ReservedSectCount = 32;
101 static uint32_t NumFATs = 2;
102 static uint32_t BackupBootSect = 6;
103 static uint32_t VolumeId=0; /* calculated before format */
105 /* Calculated later */
106 static uint32_t FatSize=0;
107 static uint32_t BytesPerSect=0;
108 static uint32_t SectorsPerCluster=0;
109 static uint32_t TotalSectors=0;
110 static uint32_t SystemAreaSize=0;
111 static uint32_t UserAreaSize=0;
112 static uint8_t VolId[12] = "NO NAME ";
115 struct FAT_BOOTSECTOR32
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;
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));
149 struct 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));
160 /* Write "count" zero sectors, starting at sector "sector" */
161 static int zero_sectors(uint32_t sector, int count)
163 int n;
165 memset(sectorbuf, 0, 128 * SECTOR_SIZE);
167 /* Write 128 sectors at a time */
168 while (count) {
169 if (count >= 128)
170 n = 128;
171 else
172 n = count;
174 if (storage_write_sectors(sector,n,sectorbuf) < 0) {
175 printf("[ERR] Write failed in zero_sectors\n");
176 return -1;
178 sector += n;
179 count -= n;
182 return 0;
187 28.2 CALCULATING THE VOLUME SERIAL NUMBER
189 For example, say a disk was formatted on 26 Dec 95 at 9:55 PM and 41.94
190 seconds. DOS takes the date and time just before it writes it to the
191 disk.
193 Low 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
199 High order word is calculated:
200 Hours & Minutes 21:55 1537h
201 Year 1995 07cbh
202 -----
203 1d02h
205 static uint32_t get_volume_id ( void )
207 /* TODO */
208 #if 0
209 SYSTEMTIME s;
210 uint32_t d;
211 uint16_t lo,hi,tmp;
213 GetLocalTime( &s );
215 lo = s.wDay + ( s.wMonth << 8 );
216 tmp = (s.wMilliseconds/10) + (s.wSecond << 8 );
217 lo += tmp;
219 hi = s.wMinute + ( s.wHour << 8 );
220 hi += s.wYear;
222 d = lo + (hi << 16);
223 return(d);
224 #endif
225 return(0);
229 This is the Microsoft calculation from FATGEN
231 uint32_t RootDirSectors = 0;
232 uint32_t TmpVal1, TmpVal2, FATSz;
234 TmpVal1 = DskSize - ( ReservedSecCnt + RootDirSectors);
235 TmpVal2 = (256 * SecPerClus) + NumFATs;
236 TmpVal2 = TmpVal2 / 2;
237 FATSz = (TmpVal1 + (TmpVal2 - 1)) / TmpVal2;
239 return( FatSz );
243 static uint32_t get_fat_size_sectors(uint32_t DskSize, uint32_t ReservedSecCnt,
244 uint32_t SecPerClus, uint32_t NumFATs,
245 uint32_t BytesPerSect)
247 uint32_t Numerator, Denominator;
248 uint32_t FatElementSize = 4;
249 uint32_t FatSz;
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
256 Numerator = FatElementSize * ( DskSize - ReservedSecCnt );
257 Denominator = ( SecPerClus * BytesPerSect ) + ( FatElementSize * NumFATs );
258 FatSz = Numerator / Denominator;
260 /* round up */
261 FatSz += 1;
263 return((uint32_t)FatSz);
266 static uint8_t get_spc(uint32_t ClusterSizeKB, uint32_t BytesPerSect)
268 uint32_t spc = ( ClusterSizeKB * 1024 ) / BytesPerSect;
269 return( (uint8_t) spc );
272 static uint8_t get_sectors_per_cluster(uint32_t DiskSizeSectors,
273 uint32_t BytesPerSect)
275 uint8_t ret = 0x01; /* 1 sector per cluster */
276 int32_t DiskSizeMB = DiskSizeSectors / ( 1024*1024 / SECTOR_SIZE);
278 /* 512 MB to 8,191 MB 4 KB */
279 if ( DiskSizeMB > 512 )
280 ret = get_spc( 4, BytesPerSect ); /* ret = 0x8; */
282 /* 8,192 MB to 16,383 MB 8 KB */
283 if ( DiskSizeMB > 8192 )
284 ret = get_spc( 8, BytesPerSect ); /* ret = 0x10; */
286 /* 16,384 MB to 32,767 MB 16 KB */
287 if ( DiskSizeMB > 16384 )
288 ret = get_spc( 16, BytesPerSect ); /* ret = 0x20; */
290 /* Larger than 32,768 MB 32 KB */
291 if ( DiskSizeMB > 32768 )
292 ret = get_spc( 32, BytesPerSect ); /* ret = 0x40; */
294 return( ret );
298 static void create_boot_sector(unsigned char* buf)
300 struct FAT_BOOTSECTOR32* pFAT32BootSect = (struct FAT_BOOTSECTOR32*)buf;
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 );
332 buf[510] = 0x55;
333 buf[511] = 0xaa;
336 static void create_fsinfo(unsigned char* buf)
338 struct FAT_FSINFO* pFAT32FsInfo = (struct FAT_FSINFO*)buf;
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);
348 /* clusters 0-1 reserved, we used cluster 2 for the root dir */
349 pFAT32FsInfo->dNxt_Free = rb_htole32(3);
352 static void create_firstfatsector(unsigned char* buf)
354 uint32_t* p = (uint32_t*)buf; /* We know the buffer is aligned */
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 */
362 int format_partition(int start, int size)
364 uint32_t i;
365 uint32_t qTotalSectors=0;
366 uint32_t FatNeeded;
368 VolumeId = get_volume_id( );
370 /* Only support hard disks at the moment */
371 if ( SECTOR_SIZE != 512 )
373 printf("[ERR] Only disks with 512 bytes per sector are supported.\n");
374 return -1;
376 BytesPerSect = SECTOR_SIZE;
378 /* Checks on Disk Size */
379 qTotalSectors = size;
381 /* low end limit - 65536 sectors */
382 if ( qTotalSectors < 65536 )
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 */
388 printf("[ERR] This drive is too small for FAT32 - there must be at least 64K clusters\n" );
389 return -1;
392 if ( qTotalSectors >= 0xffffffff )
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. */
403 printf("[ERR] This drive is too big for FAT32 - max 2TB supported\n");
406 if ( sectors_per_cluster ) {
407 SectorsPerCluster = sectors_per_cluster;
408 } else {
409 SectorsPerCluster = get_sectors_per_cluster(size,
410 BytesPerSect );
413 TotalSectors = (uint32_t) qTotalSectors;
415 FatSize = get_fat_size_sectors(TotalSectors, ReservedSectCount,
416 SectorsPerCluster, NumFATs, BytesPerSect );
418 UserAreaSize = TotalSectors - ReservedSectCount - (NumFATs*FatSize);
420 /* First zero out ReservedSect + FatSize * NumFats + SectorsPerCluster */
421 SystemAreaSize = (ReservedSectCount+(NumFATs*FatSize) + SectorsPerCluster);
423 /* Work out the Cluster count */
424 FatNeeded = UserAreaSize/SectorsPerCluster;
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;
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. */
437 FatNeeded *=4;
438 FatNeeded += (BytesPerSect-1);
439 FatNeeded /= BytesPerSect;
441 if ( FatNeeded > FatSize ) {
442 printf("[ERR] Drive too big to format\n");
443 return -1;
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
460 FATn ReservedSectCount to ReservedSectCount + FatSize
461 RootDir - allocated to cluster2
465 printf("[INFO] Formatting partition:...");
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 );
470 zero_sectors(start, SystemAreaSize);
472 printf("[INFO] Initialising reserved sectors and FATs...\n" );
474 /* Create the boot sector structure */
475 create_boot_sector(sectorbuf);
476 create_fsinfo(sectorbuf + 512);
478 if (storage_write_sectors(start,2,sectorbuf)) {
479 printf("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
480 return -1;
483 if (storage_write_sectors(start + BackupBootSect,2,sectorbuf)) {
484 printf("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
485 return -1;
488 /* Create the first FAT sector */
489 create_firstfatsector(sectorbuf);
491 /* Write the first fat sector in the right places */
492 for ( i=0; i<NumFATs; i++ ) {
493 int SectorStart = ReservedSectCount + (i * FatSize );
495 if (storage_write_sectors(start + SectorStart,1,sectorbuf)) {
496 printf("[ERR] Write failed (first copy of bootsect/fsinfo)\n");
497 return -1;
501 printf("[INFO] Format successful\n");
503 return 0;