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