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 sun; 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.sun.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.sun.infos[partnum].id == 0 120 || block.sun.infos[partnum].id == GRUB_PARTMAP_SUN_WHOLE_DISK_ID) 121 continue; 122 123 desc = &block.sun.partitions[partnum]; 124 p.start = ((grub_uint64_t) grub_be_to_cpu32 (desc->start_cylinder) 125 * grub_be_to_cpu16 (block.sun.ntrks) 126 * grub_be_to_cpu16 (block.sun.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