Hi,
The OMAP3/4 ROM code seems to have the most picky
implementation of a FAT file system ever seen.
In order to recognize a valid FAT partition, amongst
other things it also checks that the partition size
given in the FAT boot block (BPB) matches the partition
size as given in the MBR
This is quoted from a TI doc that I am sadly not
allowed to disclose:
"BPB_TotSec16 = MBR_Partition_Size
or
BPB_TotSec32 = MBR_Partition_Size"
(see http://en.wikipedia.org/wiki/File_Allocation_Table#Boot_Sector
and offsets 0x13 and 0x20 for BPB_TotSec16 and BPB_TotSec32)
Now, using e.g. mkdosfs to prepare a FAT partition to
boot and read MLO from, the above requirement is not
always met.
Internally, mkdosfs calculates in "blocks" and one
block is BLOCK_SIZE bytes large, which is given as:
/usr/include/linux/fs.h:#define BLOCK_SIZE_BITS 10
/usr/include/linux/fs.h:28:#define BLOCK_SIZE (1<<BLOCK_SIZE_BITS)
BLOCK_SIZE is 1024, but FAT sectors are counted
in 512 multiples.
So, if you have an odd partition size, mkdosfs will
truncate it by 1 and write a wrong value into
BPB_TotSec16 or BPB_TotSec32.
And then OMAP3/4 rom code will not boot .....
example:
# fdisk /dev/sdc
Command (m for help): p
Disk /dev/sdc: 3957 MB, 3957325824 bytes
255 heads, 63 sectors/track, 481 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Disk identifier: 0x00000000
Device Boot Start End Blocks Id System
/dev/sdc1 * 1 8 64228+ 6 FAT16
/dev/sdc2 9 211 1630597+ 83 Linux
Command (m for help): x
Expert command (m for help): p
Disk /dev/sdc: 255 heads, 63 sectors, 481 cylinders
Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID
1 80 1 1 0 254 63 7 63 128457 06
2 00 0 1 8 254 63 210 128520 3261195 83
3 00 0 0 0 0 0 0 0 0 00
4 00 0 0 0 0 0 0 0 0 00
the partition size is exactly 128457 sectors, but mkdosfs
writes 128456 into the FAT BPB.
this little tool checks MBT partition size vs fat BPB size:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main( int argc, char **argv )
{
if ( argc < 2 ) {
printf("check /dev/sdX\n");
return 1;
}
int fd = open( argv[1], O_RDONLY );
lseek( fd, 0 + 446 + 8, SEEK_SET );
int start;
int num_mbr;
read( fd, &start, 4 );
read( fd, &num_mbr, 4 );
int num_bpb = 0;
lseek( fd, start * 512 + 0x13, SEEK_SET );
read( fd, &num_bpb, 2 );
if( num_bpb == 0 ) {
lseek( fd, start * 512 + 0x20, SEEK_SET );
read( fd, &num_bpb, 4 );
}
printf( "start: %d mbr: %d bpb: %d -> %s\n",
start, num_mbr, num_bpb,
num_mbr == num_bpb ? "PASS" : "FAIL!" );
return num_mbr == num_bpb;
}