1 /* sunpc.c - Read SUN PC style partition tables.  */
   2 /*
   3  *  GRUB  --  GRand Unified Bootloader
   4  *  Copyright (C) 2002,2005,2006,2007,2009  Free Software Foundation, Inc.
   5  *
   6  *  GRUB is free software: you can redistribute it and/or modify
   7  *  it under the terms of the GNU General Public License as published by
   8  *  the Free Software Foundation, either version 3 of the License, or
   9  *  (at your option) any later version.
  10  *
  11  *  GRUB is distributed in the hope that it will be useful,
  12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14  *  GNU General Public License for more details.
  15  *
  16  *  You should have received a copy of the GNU General Public License
  17  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
  18  */
  19 
  20 #include <grub/partition.h>
  21 #include <grub/disk.h>
  22 #include <grub/mm.h>
  23 #include <grub/misc.h>
  24 #include <grub/dl.h>
  25 #include <grub/symbol.h>
  26 #include <grub/types.h>
  27 #include <grub/err.h>
  28 
  29 GRUB_MOD_LICENSE ("GPLv3+");
  30 
  31 #define GRUB_PARTMAP_SUN_PC_MAGIC 0xDABE
  32 #define GRUB_PARTMAP_SUN_PC_MAX_PARTS 16
  33 #define GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID 0x05
  34 
  35 struct grub_sun_pc_partition_descriptor
  36 {
  37   grub_uint16_t id;
  38   grub_uint16_t unused;
  39   grub_uint32_t start_sector;
  40   grub_uint32_t num_sectors;
  41 } __attribute__ ((packed));
  42 
  43 struct grub_sun_pc_block
  44 {
  45   grub_uint8_t unused[72];
  46   struct grub_sun_pc_partition_descriptor partitions[GRUB_PARTMAP_SUN_PC_MAX_PARTS];
  47   grub_uint8_t unused2[244];
  48   grub_uint16_t  magic;         /* Magic number.  */
  49   grub_uint16_t  csum;          /* Label xor'd checksum.  */
  50 } __attribute__ ((packed));
  51 
  52 static struct grub_partition_map grub_sun_pc_partition_map;
  53 
  54 /* Verify checksum (true=ok).  */
  55 static int
  56 grub_sun_is_valid (grub_uint16_t *label)
  57 {
  58   grub_uint16_t *pos;
  59   grub_uint16_t sum = 0;
  60 
  61   for (pos = label;
  62        pos < (label + sizeof (struct grub_sun_pc_block) / 2);
  63        pos++)
  64     sum ^= *pos;
  65 
  66   return ! sum;
  67 }
  68 
  69 static grub_err_t
  70 sun_pc_partition_map_iterate (grub_disk_t disk,
  71                               int (*hook) (grub_disk_t disk,
  72                                            const grub_partition_t partition))
  73 {
  74   grub_partition_t p;
  75   union
  76   {
  77     struct grub_sun_pc_block sunb;
  78     grub_uint16_t raw[0];
  79   } block;
  80   int partnum;
  81   grub_err_t err;
  82 
  83   p = (grub_partition_t) grub_zalloc (sizeof (struct grub_partition));
  84   if (! p)
  85     return grub_errno;
  86 
  87   p->partmap = &grub_sun_pc_partition_map;
  88   err = grub_disk_read (disk, 1, 0, sizeof (struct grub_sun_pc_block), &block);
  89   if (err)
  90     {
  91       grub_free (p);
  92       return err;
  93     }
  94   
  95   if (GRUB_PARTMAP_SUN_PC_MAGIC != grub_le_to_cpu16 (block.sunb.magic))
  96     {
  97       grub_free (p);
  98       return grub_error (GRUB_ERR_BAD_PART_TABLE, 
  99                          "not a sun_pc partition table");
 100     }
 101 
 102   if (! grub_sun_is_valid (block.raw))
 103     {
 104       grub_free (p);
 105       return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum");
 106     }
 107 
 108   /* Maybe another error value would be better, because partition
 109      table _is_ recognized but invalid.  */
 110   for (partnum = 0; partnum < GRUB_PARTMAP_SUN_PC_MAX_PARTS; partnum++)
 111     {
 112       struct grub_sun_pc_partition_descriptor *desc;
 113 
 114       if (block.sunb.partitions[partnum].id == 0
 115           || block.sunb.partitions[partnum].id
 116           == GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID)
 117         continue;
 118 
 119       desc = &block.sunb.partitions[partnum];
 120       p->start = grub_le_to_cpu32 (desc->start_sector);
 121       p->len = grub_le_to_cpu32 (desc->num_sectors);
 122       p->number = partnum;
 123       if (p->len)
 124         {
 125           if (hook (disk, p))
 126             partnum = GRUB_PARTMAP_SUN_PC_MAX_PARTS;
 127         }
 128     }
 129 
 130   grub_free (p);
 131 
 132   return grub_errno;
 133 }
 134 
 135 /* Partition map type.  */
 136 static struct grub_partition_map grub_sun_pc_partition_map =
 137   {
 138     .name = "sunpc",
 139     .iterate = sun_pc_partition_map_iterate,
 140   };
 141 
 142 GRUB_MOD_INIT(part_sunpc)
 143 {
 144   grub_partition_map_register (&grub_sun_pc_partition_map);
 145 }
 146 
 147 GRUB_MOD_FINI(part_sunpc)
 148 {
 149   grub_partition_map_unregister (&grub_sun_pc_partition_map);
 150 }
 151