/* dump-boot-blocks.c Copyright 2011 DJ Delorie This file is distributed under the terms of the GNU General Public License, either version 2 or, at your choice, some lter version. The purpose of this program is to scan an SD card and check for various things that are known to prevent an OMAP processor from booting off it. Just pass the block device name on the command line (you'll probably have to be root to do that). */ #include #include #include #include #include #include #include #ifndef O_BINARY #define O_BINARY 0 #endif typedef uint8_t byte; static int fd; struct { int type; int active; uint32_t lba; uint32_t num_sectors; } partitions[4]; struct { int part_type; char *developer; char *description; } part_types[] = { { 0x00 , "IBM ", "Empty partition" }, { 0x01 , "Microsoft ", "FAT 12" }, { 0x02 , "Microsoft & SCO ", "XENIX root" }, { 0x03 , "Microsoft & SCO ", "XENIX usr" }, { 0x04 , "Microsoft ", "FAT 16 with a size < 32 MiB" }, { 0x05 , "IBM ", "Extended partition" }, { 0x06 , "Compaq ", "FAT 16 with size ≥32 MiB" }, { 0x07 , "Microsoft ", "HPFS or NTFS" }, { 0x08 , "IBM ", "AIX" }, { 0x09 , "IBM ", "AIX bootable" }, { 0x0A , "Microsoft & IBM ", "OS/2 Boot Manager" }, { 0x0B , "Microsoft ", "Windows 95 FAT 32" }, { 0x0C , "Microsoft ", "Windows 95 FAT 32 with LBA" }, { 0x0E , "Microsoft ", "Windows 95 FAT 16 with LBA" }, { 0x0F , "Microsoft ", "Extended partition with LBA" }, { 0x10 , "AIM alliance & Taligent ", "OPUS" }, { 0x11 , "Microsoft ", "Hidden FAT 12" }, { 0x12 , "Compaq ", "Compaq diagnostics partition" }, { 0x14 , "Microsoft ", "Hidden FAT 16" }, { 0x17 , "Microsoft ", "Hidden HPFS or hidden NTFS" }, { 0x1B , "Microsoft ", "Hidden FAT 32" }, { 0x1C , "Microsoft ", "Hidden FAT 32 with LBA" }, { 0x1D , "Microsoft ", "Hidden FAT 16 with LBA" }, { 0x78 , "Geurt Vos ", "XOSL bootloader filesystem" }, { 0x82 , "GNU/Linux ", "Linux swap space" }, { 0x83 , "GNU/Linux ", "Any native Linux file system" }, { 0x85 , "GNU/Linux ", "Linux extended" }, { 0x86 , "Microsoft ", "Legacy FT FAT 16" }, { 0x87 , "Microsoft ", "Legacy FT NTFS" }, { 0x88 , "GNU/Linux ", "Linux plaintext" }, { 0x89 , "GNU/Linux ", "Linux LVM" }, { 0x8B , "Microsoft ", "Legacy FT FAT 32" }, { 0x8C , "Microsoft ", "Legacy FT FAT 32 with LBA" }, { 0x8E , " ?? ", "Linux LVM" }, { 0xA5 , " ?? ", "BSD slice" }, { 0xDA , " ?? ", "Raw data (no File System)" }, { 0xDF , "TeraByte Unlimited ", "BootIt" }, { 0xEB , "Be, Inc. ", "BFS (BeOS or Haiku)" }, { 0xEF , "Intel ", "EFI" }, { 0xFB , "VMware ", "VMware VMFS" }, { 0xFC , "VMware ", "VMware VMKCORE" }, { 0xFD , "GNU/Linux ", "Linux RAID auto" } }; #define NPARTS (sizeof(part_types)/sizeof(part_types[0])) uint8_t mbr[512]; uint8_t dosbb[512]; void decode_chs (uint8_t *chs, int *c, int *h, int *s) { *h = chs[0]; *s = chs[1] & 0x3f; *c = (((int)chs[1] & 0xc0) << 2) | chs[2]; } uint32_t get4 (uint8_t *e) { return (uint32_t)e[0] | ((uint32_t)e[1] << 8) | ((uint32_t)e[2] << 16) | ((uint32_t)e[3] << 24); } uint32_t get2 (uint8_t *e) { return (uint32_t)e[0] | ((uint32_t)e[1] << 8); } void mbr_partition (int pnum, uint8_t *entry) { int active; int sc, sh, ss; int partition_type; int ec, eh, es; uint32_t start_lba; uint32_t num_sectors; int i; char *pname = "unknown"; active = entry[0]; decode_chs (entry+1, &sc, &sh, &ss); partition_type = entry[4]; decode_chs (entry+5, &ec, &eh, &es); start_lba = get4 (entry+8); num_sectors = get4 (entry+12); for (i=0; i 0) { /* printf("root cluster %d\n", root_cluster); */ get_cluster_block_32 (root_cluster, buf); for (i=0; i 0) { /* printf("MLO cluster: %d\n", mlo_cluster); */ next_cluster = get_next_cluster (mlo_cluster); if (next_cluster <= 0) break; if (next_cluster != mlo_cluster + 1) { printf("MLO data is not contiguous; it's recommended that MLO be the first file\n"); printf("copied to the disk after you format it (mkfs)\n"); return; } mlo_cluster = next_cluster; } } /*----------------------------------------------------------------------*/ int main(int argc, char **argv) { int i; int type_ok[4]; if (argc < 2) { fprintf (stderr, "usage: %s (or whatever)\n", argv[0]); exit (1); } fd = open (argv[1], O_RDONLY | O_BINARY); if (fd < 0) { fprintf (stderr, "Cannot open %s for reading\n", argv[1]); perror("The error was:"); exit (1); } lseek (fd, 0L, SEEK_SET); read (fd, mbr, 512); /* * 0 1 1 - 5 254 63 04 63 96327 = FAT 16 with a size < 32 MiB */ printf("\033[32m"); printf(" C H S C H S\n"); printf("B? ---------- ---------- Type start-lba num-sectors\n"); printf("\033[0m"); for (i=0; i<4; i++) mbr_partition (i, mbr + 446 + i * 16); for (i=0; i<4; i++) { type_ok[i] = 0; switch (partitions[i].type) { case 0x01: case 0x11: scan_fat12 (i); break; case 0x04: case 0x06: case 0x0e: case 0x14: case 0x1e: type_ok[i] = 16; scan_fat16 (i); break; case 0x0b: case 0x0c: case 0x1b: case 0x1c: type_ok[i] = 32; scan_fat32 (i); break; } } if (! type_ok [0]) { printf ("The partition type of the first partition is not FAT16 or FAT32.\n"); } else { if (partitions[0].num_sectors & 1) { printf ("The boot (first) partition has an odd number of sectors. You likely specified\n"); printf ("an even number of cylinders, try using an odd number as the first track\n"); printf ("is not used in the first partition.\n"); } if (!partitions[0].active) { printf ("The first partition is not marked bootable (active).\n"); } if (partitions[0].lba != 63) { printf ("The first partition does not start on sector 63. While the boot code normally\n"); printf ("ignores the C/H/S information, it does seem to assume 63 sectors per track.\n"); printf ("If you have trouble convincing your fdisk to start on sector 63, try enabling\n"); printf ("DOS compatibility mode.\n"); } check_mlo_first (type_ok[0]); } close (fd); exit (0); }