1 /* This file is part of the program psim. 2 3 Copyright (C) 1994-1997, Andrew Cagney <cagney@highland.com.au> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, see <http://www.gnu.org/licenses/>. 17 18 */ 19 20 21 #ifndef _PK_DISKLABEL_C_ 22 #define _PK_DISKLABEL_C_ 23 24 #ifndef STATIC_INLINE_PK_DISKLABEL 25 #define STATIC_INLINE_PK_DISKLABEL STATIC_INLINE 26 #endif 27 28 #include "device_table.h" 29 30 #include "pk.h" 31 32 #include <stdlib.h> 33 34 /* PACKAGE 35 36 disk-label - all knowing disk I/O package 37 38 DESCRIPTION 39 40 The disk-label package provides a generic interface to disk 41 devices. It uses the arguments specified when an instance is being 42 created to determine if the raw disk, a partition, or a file within 43 a partition should be opened. 44 45 An instance create call to disk-label could result, for instance, 46 in the opening of a DOS file system contained within a dos 47 partition contained within a physical disk. 48 49 */ 50 51 /* taken from bfd/ppcboot.c by Michael Meissner */ 52 53 /* PPCbug location structure */ 54 typedef struct ppcboot_location { 55 uint8_t ind; 56 uint8_t head; 57 uint8_t sector; 58 uint8_t cylinder; 59 } ppcboot_location_t; 60 61 /* PPCbug partition table layout */ 62 typedef struct ppcboot_partition { 63 ppcboot_location_t partition_begin; /* partition begin */ 64 ppcboot_location_t partition_end; /* partition end */ 65 uint8_t sector_begin[4]; /* 32-bit start RBA (zero-based), little endian */ 66 uint8_t sector_length[4]; /* 32-bit RBA count (one-based), little endian */ 67 } ppcboot_partition_t; 68 69 #if 0 70 /* PPCbug boot layout. */ 71 typedef struct ppcboot_hdr { 72 uint8_t pc_compatibility[446]; /* x86 instruction field */ 73 ppcboot_partition_t partition[4]; /* partition information */ 74 uint8_t signature[2]; /* 0x55 and 0xaa */ 75 uint8_t entry_offset[4]; /* entry point offset, little endian */ 76 uint8_t length[4]; /* load image length, little endian */ 77 uint8_t flags; /* flag field */ 78 uint8_t os_id; /* OS_ID */ 79 char partition_name[32]; /* partition name */ 80 uint8_t reserved1[470]; /* reserved */ 81 } ppcboot_hdr_t; 82 #endif 83 84 85 typedef struct _disklabel { 86 device_instance *parent; 87 device_instance *raw_disk; 88 unsigned_word pos; 89 unsigned_word sector_begin; 90 unsigned_word sector_length; 91 } disklabel; 92 93 94 static unsigned_word 95 sector2uw(uint8_t s[4]) 96 { 97 return ((s[3] << 24) 98 + (s[2] << 16) 99 + (s[1] << 8) 100 + (s[0] << 0)); 101 } 102 103 104 static void 105 disklabel_delete(device_instance *instance) 106 { 107 disklabel *label = device_instance_data(instance); 108 device_instance_delete(label->raw_disk); 109 free(label); 110 } 111 112 113 static int 114 disklabel_read(device_instance *instance, 115 void *buf, 116 unsigned_word len) 117 { 118 disklabel *label = device_instance_data(instance); 119 int nr_read; 120 if (label->pos + len > label->sector_length) 121 len = label->sector_length - label->pos; 122 if (device_instance_seek(label->raw_disk, 0, 123 label->sector_begin + label->pos) < 0) 124 return -1; 125 nr_read = device_instance_read(label->raw_disk, buf, len); 126 if (nr_read > 0) 127 label->pos += nr_read; 128 return nr_read; 129 } 130 131 static int 132 disklabel_write(device_instance *instance, 133 const void *buf, 134 unsigned_word len) 135 { 136 disklabel *label = device_instance_data(instance); 137 int nr_written; 138 if (label->pos + len > label->sector_length) 139 len = label->sector_length - label->pos; 140 if (device_instance_seek(label->raw_disk, 0, 141 label->sector_begin + label->pos) < 0) 142 return -1; 143 nr_written = device_instance_write(label->raw_disk, buf, len); 144 if (nr_written > 0) 145 label->pos += nr_written; 146 return nr_written; 147 } 148 149 static int 150 disklabel_seek(device_instance *instance, 151 unsigned_word pos_hi, 152 unsigned_word pos_lo) 153 { 154 disklabel *label = device_instance_data(instance); 155 if (pos_lo >= label->sector_length || pos_hi != 0) 156 return -1; 157 label->pos = pos_lo; 158 return 0; 159 } 160 161 162 static const device_instance_callbacks package_disklabel_callbacks = { 163 disklabel_delete, 164 disklabel_read, 165 disklabel_write, 166 disklabel_seek, 167 }; 168 169 /* Reconize different types of boot block */ 170 171 static int 172 block0_is_bpb(const uint8_t block[]) 173 { 174 const char ebdic_ibma[] = { 0xc9, 0xc2, 0xd4, 0xc1 }; 175 /* ref PowerPC Microprocessor CHRP bindings 1.2b - page 47 */ 176 /* can't start with IBMA */ 177 if (memcmp(block, ebdic_ibma, sizeof(ebdic_ibma)) == 0) 178 return 0; 179 /* must have LE 0xAA55 signature at offset 510 */ 180 if (block[511] != 0xAA && block[510] != 0x55) 181 return 0; 182 /* valid 16 bit LE bytes per sector - 256, 512, 1024 */ 183 if (block[11] != 0 184 || (block[12] != 1 && block[12] != 2 && block[12] != 4)) 185 return 0; 186 /* nr fats is 1 or 2 */ 187 if (block[16] != 1 && block[16] != 2) 188 return 0; 189 return 1; 190 } 191 192 193 /* Verify that the device contains an ISO-9660 File system */ 194 195 static int 196 is_iso9660(device_instance *raw_disk) 197 { 198 /* ref PowerPC Microprocessor CHRP bindings 1.2b - page 47 */ 199 uint8_t block[512]; 200 if (device_instance_seek(raw_disk, 0, 512 * 64) < 0) 201 return 0; 202 if (device_instance_read(raw_disk, block, sizeof(block)) != sizeof(block)) 203 return 0; 204 if (block[0] == 0x01 205 && block[1] == 'C' 206 && block[2] == 'D' 207 && block[3] == '0' 208 && block[4] == '0' 209 && block[5] == '1') 210 return 1; 211 return 0; 212 } 213 214 215 /* Verify that the disk block contains a valid DOS partition table. 216 While we're at it have a look around for active partitions etc. 217 218 Return 0: invalid 219 Return 1..4: valid, value returned is the first active partition 220 Return -1: no active partition */ 221 222 static int 223 block0_is_fdisk(const uint8_t block[]) 224 { 225 const int partition_type_fields[] = { 0, 0x1c2, 0x1d2, 0x1e2, 0x1f2 }; 226 const int partition_active_fields[] = { 0, 0x1be, 0x1ce, 0x1de, 0xee }; 227 int partition; 228 int active = -1; 229 /* ref PowerPC Microprocessor CHRP bindings 1.2b - page 47 */ 230 /* must have LE 0xAA55 signature at offset 510 */ 231 if (block[511/*0x1ff*/] != 0xAA && block[510/*0x1fe*/] != 0x55) 232 return 0; 233 /* must contain valid partition types */ 234 for (partition = 1; partition <= 4 && active != 0; partition++) { 235 int partition_type = block[partition_type_fields[partition]]; 236 int is_active = block[partition_active_fields[partition]] == 0x80; 237 const char *type; 238 switch (partition_type) { 239 case 0x00: 240 type = "UNUSED"; 241 break; 242 case 0x01: 243 type = "FAT 12 File system"; 244 break; 245 case 0x04: 246 type = "FAT 16 File system"; 247 break; 248 case 0x05: 249 case 0x06: 250 type = "rejected - extended/chained partition not supported"; 251 active = 0; 252 break; 253 case 0x41: 254 type = "Single program image"; 255 break; 256 case 0x82: 257 type = "Solaris?"; 258 break; 259 case 0x96: 260 type = "ISO 9660 File system"; 261 break; 262 default: 263 type = "rejected - unknown type"; 264 active = 0; 265 break; 266 } 267 PTRACE(disklabel, ("partition %d of type 0x%02x - %s%s\n", 268 partition, 269 partition_type, 270 type, 271 is_active && active != 0 ? " (active)" : "")); 272 if (partition_type != 0 && is_active && active < 0) 273 active = partition; 274 } 275 return active; 276 } 277 278 279 /* Verify that block0 corresponds to a MAC disk */ 280 281 static int 282 block0_is_mac_disk(const uint8_t block[]) 283 { 284 /* ref PowerPC Microprocessor CHRP bindings 1.2b - page 47 */ 285 /* signature - BEx4552 at offset 0 */ 286 if (block[0] != 0x45 || block[1] != 0x52) 287 return 0; 288 return 1; 289 } 290 291 292 /* Open a logical disk/file */ 293 294 device_instance * 295 pk_disklabel_create_instance(device_instance *raw_disk, 296 const char *args) 297 { 298 int partition; 299 char *filename; 300 301 /* parse the arguments */ 302 if (args == NULL) { 303 partition = 0; 304 filename = NULL; 305 } 306 else { 307 partition = strtoul((char*)args, &filename, 0); 308 if (filename == args) 309 partition = -1; /* not specified */ 310 if (*filename == ',') 311 filename++; 312 if (*filename == '\0') 313 filename = NULL; /* easier */ 314 } 315 316 if (partition == 0) { 317 /* select the raw disk */ 318 return raw_disk; 319 } 320 else { 321 uint8_t boot_block[512]; 322 /* get the boot block for examination */ 323 if (device_instance_seek(raw_disk, 0, 0) < 0) 324 device_error(device_instance_device(raw_disk), 325 "Problem seeking on raw disk"); 326 if (device_instance_read(raw_disk, &boot_block, sizeof(boot_block)) 327 != sizeof(boot_block)) 328 device_error(device_instance_device(raw_disk), "Problem reading boot block"); 329 330 if (partition < 0) { 331 /* select the active partition */ 332 if (block0_is_bpb(boot_block)) { 333 device_error(device_instance_device(raw_disk), "Unimplemented active BPB"); 334 } 335 else if (block0_is_fdisk(boot_block)) { 336 int active = block0_is_fdisk(boot_block); 337 device_error(device_instance_device(raw_disk), "Unimplemented active FDISK (%d)", 338 active); 339 } 340 else if (is_iso9660(raw_disk)) { 341 device_error(device_instance_device(raw_disk), "Unimplemented active ISO9660"); 342 } 343 else if (block0_is_mac_disk(boot_block)) { 344 device_error(device_instance_device(raw_disk), "Unimplemented active MAC DISK"); 345 } 346 else { 347 device_error(device_instance_device(raw_disk), "Unreconized bootblock"); 348 } 349 } 350 else { 351 /* select the specified disk partition */ 352 if (block0_is_bpb(boot_block)) { 353 device_error(device_instance_device(raw_disk), "Unimplemented BPB"); 354 } 355 else if (block0_is_fdisk(boot_block)) { 356 /* return an instance */ 357 ppcboot_partition_t *partition_table = (ppcboot_partition_t*) &boot_block[446]; 358 ppcboot_partition_t *partition_entry; 359 disklabel *label; 360 if (partition > 4) 361 device_error(device_instance_device(raw_disk), 362 "Only FDISK partitions 1..4 supported"); 363 partition_entry = &partition_table[partition - 1]; 364 label = ZALLOC(disklabel); 365 label->raw_disk = raw_disk; 366 label->pos = 0; 367 label->sector_begin = 512 * sector2uw(partition_entry->sector_begin); 368 label->sector_length = 512 * sector2uw(partition_entry->sector_length); 369 PTRACE(disklabel, ("partition %ld, sector-begin %ld, length %ld\n", 370 (long)partition, 371 (long)label->sector_begin, 372 (long)label->sector_length)); 373 if (filename != NULL) 374 device_error(device_instance_device(raw_disk), 375 "FDISK file names not yet supported"); 376 return device_create_instance_from(NULL, raw_disk, 377 label, 378 NULL, args, 379 &package_disklabel_callbacks); 380 } 381 else if (block0_is_mac_disk(boot_block)) { 382 device_error(device_instance_device(raw_disk), "Unimplemented MAC DISK"); 383 } 384 else { 385 device_error(device_instance_device(raw_disk), 386 "Unreconized bootblock"); 387 } 388 } 389 } 390 391 return NULL; 392 } 393 394 395 #endif /* _PK_DISKLABEL_C_ */ 396 397