1 /* sun.c - Read SUN style partition tables.  */
   2 /*
   3  *  GRUB  --  GRand Unified Bootloader
   4  *  Copyright (C) 2002,2005,2006,2007  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_MAGIC 0xDABE
  32 #define GRUB_PARTMAP_SUN_MAX_PARTS 8
  33 #define GRUB_PARTMAP_SUN_WHOLE_DISK_ID 0x05
  34 
  35 struct grub_sun_partition_info
  36 {
  37   grub_uint8_t spare1;
  38   grub_uint8_t id;
  39   grub_uint8_t spare2;
  40   grub_uint8_t flags;
  41 } __attribute__ ((packed));
  42 
  43 struct grub_sun_partition_descriptor
  44 {
  45   grub_uint32_t start_cylinder;
  46   grub_uint32_t num_sectors;
  47 } __attribute__ ((packed));
  48 
  49 struct grub_sun_block
  50 {
  51   grub_uint8_t  info[128];      /* Informative text string.  */
  52   grub_uint8_t  spare0[14];
  53   struct grub_sun_partition_info infos[8];
  54   grub_uint8_t  spare1[246];    /* Boot information etc.  */
  55   grub_uint16_t  rspeed;        /* Disk rotational speed.  */
  56   grub_uint16_t  pcylcount;     /* Physical cylinder count.  */
  57   grub_uint16_t  sparecyl;      /* extra sects per cylinder.  */
  58   grub_uint8_t  spare2[4];      /* More magic...  */
  59   grub_uint16_t  ilfact;        /* Interleave factor.  */
  60   grub_uint16_t  ncyl;          /* Data cylinder count.  */
  61   grub_uint16_t  nacyl;         /* Alt. cylinder count.  */
  62   grub_uint16_t  ntrks;         /* Tracks per cylinder.  */
  63   grub_uint16_t  nsect;         /* Sectors per track.  */
  64   grub_uint8_t  spare3[4];      /* Even more magic...  */
  65   struct grub_sun_partition_descriptor partitions[8];
  66   grub_uint16_t  magic;         /* Magic number.  */
  67   grub_uint16_t  csum;          /* Label xor'd checksum.  */
  68 } __attribute__ ((packed));
  69 
  70 static struct grub_partition_map grub_sun_partition_map;
  71 
  72 /* Verify checksum (true=ok).  */
  73 static int
  74 grub_sun_is_valid (grub_uint16_t *label)
  75 {
  76   grub_uint16_t *pos;
  77   grub_uint16_t sum = 0;
  78 
  79   for (pos = label;
  80        pos < (label + sizeof (struct grub_sun_block) / 2);
  81        pos++)
  82     sum ^= *pos;
  83 
  84   return ! sum;
  85 }
  86 
  87 static grub_err_t
  88 sun_partition_map_iterate (grub_disk_t disk,
  89                            int (*hook) (grub_disk_t disk,
  90                                         const grub_partition_t partition))
  91 {
  92   struct grub_partition p;
  93   union
  94   {
  95     struct grub_sun_block sunb;
  96     grub_uint16_t raw[0];
  97   } block;
  98   int partnum;
  99   grub_err_t err;
 100 
 101   p.partmap = &grub_sun_partition_map;
 102   err = grub_disk_read (disk, 0, 0, sizeof (struct grub_sun_block),
 103                         &block);
 104   if (err)
 105     return err;
 106 
 107   if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.sunb.magic))
 108     return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a sun partition table");
 109 
 110   if (! grub_sun_is_valid (block.raw))
 111       return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid checksum");
 112   
 113   /* Maybe another error value would be better, because partition
 114      table _is_ recognized but invalid.  */
 115   for (partnum = 0; partnum < GRUB_PARTMAP_SUN_MAX_PARTS; partnum++)
 116     {
 117       struct grub_sun_partition_descriptor *desc;
 118 
 119       if (block.sunb.infos[partnum].id == 0
 120           || block.sunb.infos[partnum].id == GRUB_PARTMAP_SUN_WHOLE_DISK_ID)
 121         continue;
 122 
 123       desc = &block.sunb.partitions[partnum];
 124       p.start = ((grub_uint64_t) grub_be_to_cpu32 (desc->start_cylinder)
 125                   * grub_be_to_cpu16 (block.sunb.ntrks)
 126                   * grub_be_to_cpu16 (block.sunb.nsect));
 127       p.len = grub_be_to_cpu32 (desc->num_sectors);
 128       p.number = p.index = partnum;
 129       if (p.len)
 130         {
 131           if (hook (disk, &p))
 132             partnum = GRUB_PARTMAP_SUN_MAX_PARTS;
 133         }
 134     }
 135 
 136   return grub_errno;
 137 }
 138 
 139 /* Partition map type.  */
 140 static struct grub_partition_map grub_sun_partition_map =
 141   {
 142     .name = "sun",
 143     .iterate = sun_partition_map_iterate,
 144   };
 145 
 146 GRUB_MOD_INIT(part_sun)
 147 {
 148   grub_partition_map_register (&grub_sun_partition_map);
 149 }
 150 
 151 GRUB_MOD_FINI(part_sun)
 152 {
 153   grub_partition_map_unregister (&grub_sun_partition_map);
 154 }
 155