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