uboot/disk/part_dos.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2001
   3 * Raymond Lo, lo@routefree.com
   4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   5 *
   6 * SPDX-License-Identifier:     GPL-2.0+
   7 */
   8
   9/*
  10 * Support for harddisk partitions.
  11 *
  12 * To be compatible with LinuxPPC and Apple we use the standard Apple
  13 * SCSI disk partitioning scheme. For more information see:
  14 * http://developer.apple.com/techpubs/mac/Devices/Devices-126.html#MARKER-14-92
  15 */
  16
  17#include <common.h>
  18#include <command.h>
  19#include <ide.h>
  20#include <memalign.h>
  21#include "part_dos.h"
  22
  23#ifdef HAVE_BLOCK_DEVICE
  24
  25#define DOS_PART_DEFAULT_SECTOR 512
  26
  27/* Convert char[4] in little endian format to the host format integer
  28 */
  29static inline unsigned int le32_to_int(unsigned char *le32)
  30{
  31    return ((le32[3] << 24) +
  32            (le32[2] << 16) +
  33            (le32[1] << 8) +
  34             le32[0]
  35           );
  36}
  37
  38static inline int is_extended(int part_type)
  39{
  40    return (part_type == 0x5 ||
  41            part_type == 0xf ||
  42            part_type == 0x85);
  43}
  44
  45static inline int is_bootable(dos_partition_t *p)
  46{
  47        return p->boot_ind == 0x80;
  48}
  49
  50static void print_one_part(dos_partition_t *p, lbaint_t ext_part_sector,
  51                           int part_num, unsigned int disksig)
  52{
  53        lbaint_t lba_start = ext_part_sector + le32_to_int (p->start4);
  54        lbaint_t lba_size  = le32_to_int (p->size4);
  55
  56        printf("%3d\t%-10" LBAFlength "u\t%-10" LBAFlength
  57                "u\t%08x-%02x\t%02x%s%s\n",
  58                part_num, lba_start, lba_size, disksig, part_num, p->sys_ind,
  59                (is_extended(p->sys_ind) ? " Extd" : ""),
  60                (is_bootable(p) ? " Boot" : ""));
  61}
  62
  63static int test_block_type(unsigned char *buffer)
  64{
  65        int slot;
  66        struct dos_partition *p;
  67
  68        if((buffer[DOS_PART_MAGIC_OFFSET + 0] != 0x55) ||
  69            (buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) ) {
  70                return (-1);
  71        } /* no DOS Signature at all */
  72        p = (struct dos_partition *)&buffer[DOS_PART_TBL_OFFSET];
  73        for (slot = 0; slot < 3; slot++) {
  74                if (p->boot_ind != 0 && p->boot_ind != 0x80) {
  75                        if (!slot &&
  76                            (strncmp((char *)&buffer[DOS_PBR_FSTYPE_OFFSET],
  77                                     "FAT", 3) == 0 ||
  78                             strncmp((char *)&buffer[DOS_PBR32_FSTYPE_OFFSET],
  79                                     "FAT32", 5) == 0)) {
  80                                return DOS_PBR; /* is PBR */
  81                        } else {
  82                                return -1;
  83                        }
  84                }
  85        }
  86        return DOS_MBR;     /* Is MBR */
  87}
  88
  89
  90static int part_test_dos(struct blk_desc *dev_desc)
  91{
  92        ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
  93
  94        if (blk_dread(dev_desc, 0, 1, (ulong *)buffer) != 1)
  95                return -1;
  96
  97        if (test_block_type(buffer) != DOS_MBR)
  98                return -1;
  99
 100        return 0;
 101}
 102
 103/*  Print a partition that is relative to its Extended partition table
 104 */
 105static void print_partition_extended(struct blk_desc *dev_desc,
 106                                     lbaint_t ext_part_sector,
 107                                     lbaint_t relative,
 108                                     int part_num, unsigned int disksig)
 109{
 110        ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
 111        dos_partition_t *pt;
 112        int i;
 113
 114        if (blk_dread(dev_desc, ext_part_sector, 1, (ulong *)buffer) != 1) {
 115                printf ("** Can't read partition table on %d:" LBAFU " **\n",
 116                        dev_desc->devnum, ext_part_sector);
 117                return;
 118        }
 119        i=test_block_type(buffer);
 120        if (i != DOS_MBR) {
 121                printf ("bad MBR sector signature 0x%02x%02x\n",
 122                        buffer[DOS_PART_MAGIC_OFFSET],
 123                        buffer[DOS_PART_MAGIC_OFFSET + 1]);
 124                return;
 125        }
 126
 127        if (!ext_part_sector)
 128                disksig = le32_to_int(&buffer[DOS_PART_DISKSIG_OFFSET]);
 129
 130        /* Print all primary/logical partitions */
 131        pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET);
 132        for (i = 0; i < 4; i++, pt++) {
 133                /*
 134                 * fdisk does not show the extended partitions that
 135                 * are not in the MBR
 136                 */
 137
 138                if ((pt->sys_ind != 0) &&
 139                    (ext_part_sector == 0 || !is_extended (pt->sys_ind)) ) {
 140                        print_one_part(pt, ext_part_sector, part_num, disksig);
 141                }
 142
 143                /* Reverse engr the fdisk part# assignment rule! */
 144                if ((ext_part_sector == 0) ||
 145                    (pt->sys_ind != 0 && !is_extended (pt->sys_ind)) ) {
 146                        part_num++;
 147                }
 148        }
 149
 150        /* Follows the extended partitions */
 151        pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET);
 152        for (i = 0; i < 4; i++, pt++) {
 153                if (is_extended (pt->sys_ind)) {
 154                        lbaint_t lba_start
 155                                = le32_to_int (pt->start4) + relative;
 156
 157                        print_partition_extended(dev_desc, lba_start,
 158                                ext_part_sector == 0  ? lba_start : relative,
 159                                part_num, disksig);
 160                }
 161        }
 162
 163        return;
 164}
 165
 166
 167/*  Print a partition that is relative to its Extended partition table
 168 */
 169static int part_get_info_extended(struct blk_desc *dev_desc,
 170                                  lbaint_t ext_part_sector, lbaint_t relative,
 171                                  int part_num, int which_part,
 172                                  disk_partition_t *info, unsigned int disksig)
 173{
 174        ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);
 175        dos_partition_t *pt;
 176        int i;
 177        int dos_type;
 178
 179        if (blk_dread(dev_desc, ext_part_sector, 1, (ulong *)buffer) != 1) {
 180                printf ("** Can't read partition table on %d:" LBAFU " **\n",
 181                        dev_desc->devnum, ext_part_sector);
 182                return -1;
 183        }
 184        if (buffer[DOS_PART_MAGIC_OFFSET] != 0x55 ||
 185                buffer[DOS_PART_MAGIC_OFFSET + 1] != 0xaa) {
 186                printf ("bad MBR sector signature 0x%02x%02x\n",
 187                        buffer[DOS_PART_MAGIC_OFFSET],
 188                        buffer[DOS_PART_MAGIC_OFFSET + 1]);
 189                return -1;
 190        }
 191
 192#ifdef CONFIG_PARTITION_UUIDS
 193        if (!ext_part_sector)
 194                disksig = le32_to_int(&buffer[DOS_PART_DISKSIG_OFFSET]);
 195#endif
 196
 197        /* Print all primary/logical partitions */
 198        pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET);
 199        for (i = 0; i < 4; i++, pt++) {
 200                /*
 201                 * fdisk does not show the extended partitions that
 202                 * are not in the MBR
 203                 */
 204                if (((pt->boot_ind & ~0x80) == 0) &&
 205                    (pt->sys_ind != 0) &&
 206                    (part_num == which_part) &&
 207                    (is_extended(pt->sys_ind) == 0)) {
 208                        info->blksz = DOS_PART_DEFAULT_SECTOR;
 209                        info->start = (lbaint_t)(ext_part_sector +
 210                                        le32_to_int(pt->start4));
 211                        info->size  = (lbaint_t)le32_to_int(pt->size4);
 212                        switch(dev_desc->if_type) {
 213                                case IF_TYPE_IDE:
 214                                case IF_TYPE_SATA:
 215                                case IF_TYPE_ATAPI:
 216                                        sprintf((char *)info->name, "hd%c%d",
 217                                                'a' + dev_desc->devnum,
 218                                                part_num);
 219                                        break;
 220                                case IF_TYPE_SCSI:
 221                                        sprintf((char *)info->name, "sd%c%d",
 222                                                'a' + dev_desc->devnum,
 223                                                part_num);
 224                                        break;
 225                                case IF_TYPE_USB:
 226                                        sprintf((char *)info->name, "usbd%c%d",
 227                                                'a' + dev_desc->devnum,
 228                                                part_num);
 229                                        break;
 230                                case IF_TYPE_DOC:
 231                                        sprintf((char *)info->name, "docd%c%d",
 232                                                'a' + dev_desc->devnum,
 233                                                part_num);
 234                                        break;
 235                                default:
 236                                        sprintf((char *)info->name, "xx%c%d",
 237                                                'a' + dev_desc->devnum,
 238                                                part_num);
 239                                        break;
 240                        }
 241                        /* sprintf(info->type, "%d, pt->sys_ind); */
 242                        strcpy((char *)info->type, "U-Boot");
 243                        info->bootable = is_bootable(pt);
 244#ifdef CONFIG_PARTITION_UUIDS
 245                        sprintf(info->uuid, "%08x-%02x", disksig, part_num);
 246#endif
 247                        return 0;
 248                }
 249
 250                /* Reverse engr the fdisk part# assignment rule! */
 251                if ((ext_part_sector == 0) ||
 252                    (pt->sys_ind != 0 && !is_extended (pt->sys_ind)) ) {
 253                        part_num++;
 254                }
 255        }
 256
 257        /* Follows the extended partitions */
 258        pt = (dos_partition_t *) (buffer + DOS_PART_TBL_OFFSET);
 259        for (i = 0; i < 4; i++, pt++) {
 260                if (is_extended (pt->sys_ind)) {
 261                        lbaint_t lba_start
 262                                = le32_to_int (pt->start4) + relative;
 263
 264                        return part_get_info_extended(dev_desc, lba_start,
 265                                 ext_part_sector == 0 ? lba_start : relative,
 266                                 part_num, which_part, info, disksig);
 267                }
 268        }
 269
 270        /* Check for DOS PBR if no partition is found */
 271        dos_type = test_block_type(buffer);
 272
 273        if (dos_type == DOS_PBR) {
 274                info->start = 0;
 275                info->size = dev_desc->lba;
 276                info->blksz = DOS_PART_DEFAULT_SECTOR;
 277                info->bootable = 0;
 278                strcpy((char *)info->type, "U-Boot");
 279#ifdef CONFIG_PARTITION_UUIDS
 280                info->uuid[0] = 0;
 281#endif
 282                return 0;
 283        }
 284
 285        return -1;
 286}
 287
 288void part_print_dos(struct blk_desc *dev_desc)
 289{
 290        printf("Part\tStart Sector\tNum Sectors\tUUID\t\tType\n");
 291        print_partition_extended(dev_desc, 0, 0, 1, 0);
 292}
 293
 294int part_get_info_dos(struct blk_desc *dev_desc, int part,
 295                      disk_partition_t *info)
 296{
 297        return part_get_info_extended(dev_desc, 0, 0, 1, part, info, 0);
 298}
 299
 300U_BOOT_PART_TYPE(dos) = {
 301        .name           = "DOS",
 302        .part_type      = PART_TYPE_DOS,
 303        .get_info       = part_get_info_ptr(part_get_info_dos),
 304        .print          = part_print_ptr(part_print_dos),
 305        .test           = part_test_dos,
 306};
 307
 308#endif
 309