1 /* 2 * Copyright 2003-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold, bonefish@cs.tu-berlin.de 7 * Tomas Kucera, kucerat@centrum.cz 8 */ 9 10 /*! 11 \file intel.cpp 12 \brief partitioning system module for "intel" style partitions. 13 */ 14 15 // TODO: The implementation is very strict right now. It rejects a partition 16 // completely, if it finds an error in its partition tables. We should see, 17 // what error can be handled gracefully, e.g. by ignoring the partition 18 // descriptor or the whole partition table sector. 19 20 #include <errno.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include <new> 26 27 #include <KernelExport.h> 28 29 #include <AutoDeleter.h> 30 #include <disk_device_manager/ddm_modules.h> 31 32 #include "intel.h" 33 #include "PartitionLocker.h" 34 #include "PartitionMap.h" 35 #include "PartitionMapParser.h" 36 37 #ifndef _BOOT_MODE 38 # include <DiskDeviceTypes.h> 39 # include "write_support.h" 40 # define TRACE(x) dprintf x 41 #else 42 # include <boot/partitions.h> 43 # include <util/kernel_cpp.h> 44 # define TRACE(x) ; 45 #endif 46 47 48 // module names 49 #define INTEL_PARTITION_MODULE_NAME "partitioning_systems/intel/map/v1" 50 #define INTEL_EXTENDED_PARTITION_MODULE_NAME \ 51 "partitioning_systems/intel/extended/v1" 52 53 54 using std::nothrow; 55 56 // TODO: This doesn't belong here! 57 // no atomic_add() in the boot loader 58 #ifdef _BOOT_MODE 59 60 inline int32 61 atomic_add(int32* a, int32 num) 62 { 63 int32 oldA = *a; 64 *a += num; 65 return oldA; 66 } 67 68 #endif 69 70 71 #ifndef _BOOT_MODE 72 73 // get_type_for_content_type (for both pm_* and ep_*) 74 static status_t 75 get_type_for_content_type(const char* contentType, char* type) 76 { 77 TRACE(("intel: get_type_for_content_type(%s)\n", 78 contentType)); 79 80 if (!contentType || !type) 81 return B_BAD_VALUE; 82 83 PartitionType ptype; 84 ptype.SetContentType(contentType); 85 if (!ptype.IsValid()) 86 return B_NAME_NOT_FOUND; 87 88 ptype.GetTypeString(type); 89 return B_OK; 90 } 91 92 #endif 93 94 95 // #pragma mark - Intel Partition Map Module 96 97 98 // pm_std_ops 99 static status_t 100 pm_std_ops(int32 op, ...) 101 { 102 TRACE(("intel: pm_std_ops(0x%" B_PRIx32 ")\n", op)); 103 switch(op) { 104 case B_MODULE_INIT: 105 case B_MODULE_UNINIT: 106 return B_OK; 107 } 108 return B_ERROR; 109 } 110 111 112 // pm_identify_partition 113 static float 114 pm_identify_partition(int fd, partition_data* partition, void** cookie) 115 { 116 // check parameters 117 if (fd < 0 || !partition || !cookie) 118 return -1; 119 120 TRACE(("intel: pm_identify_partition(%d, %" B_PRId32 ": %" B_PRId64 ", " 121 "%" B_PRId64 ", %" B_PRId32 ")\n", fd, partition->id, partition->offset, 122 partition->size, partition->block_size)); 123 // reject extended partitions 124 if (partition->type 125 && !strcmp(partition->type, kPartitionTypeIntelExtended)) { 126 return -1; 127 } 128 129 // allocate a PartitionMap 130 PartitionMapCookie* map = new(nothrow) PartitionMapCookie; 131 if (!map) 132 return -1; 133 134 // read the partition structure 135 PartitionMapParser parser(fd, 0, partition->size, partition->block_size); 136 status_t error = parser.Parse(NULL, map); 137 if (error != B_OK) { 138 // cleanup, if not detected 139 delete map; 140 return -1; 141 } 142 143 *cookie = map; 144 145 // Depending on whether we actually have recognized child partitions and 146 // whether we are installed directly on a device (the by far most common 147 // setup), we determine the priority. 148 bool hasChildren = (map->CountNonEmptyPartitions() > 0); 149 bool hasParent = (get_parent_partition(partition->id) != NULL); 150 151 if (!hasParent) { 152 if (hasChildren) { 153 // This value overrides BFS. 154 return 0.81; 155 } 156 157 // No children -- might be a freshly initialized disk. But it could 158 // also be an image file. So we give BFS a chance to override us. 159 return 0.5; 160 } 161 162 // NOTE: It seems supporting nested partition maps makes more trouble than it 163 // has useful applications ATM. So it is disabled for the time being. 164 #if 0 165 // We have a parent. That's a very unlikely setup. 166 if (hasChildren) 167 return 0.4; 168 169 // No children. Extremely unlikely, that this is desired. But if no one 170 // else claims the partition, we take it anyway. 171 return 0.1; 172 #endif 173 return -1; 174 } 175 176 177 // pm_scan_partition 178 static status_t 179 pm_scan_partition(int fd, partition_data* partition, void* cookie) 180 { 181 // check parameters 182 if (fd < 0 || !partition || !cookie) 183 return B_ERROR; 184 185 TRACE(("intel: pm_scan_partition(%d, %" B_PRId32 ": %" B_PRId64 ", " 186 "%" B_PRId64 ", %" B_PRId32 ")\n", fd, partition->id, partition->offset, 187 partition->size, partition->block_size)); 188 189 PartitionMapCookie* map = (PartitionMapCookie*)cookie; 190 // fill in the partition_data structure 191 partition->status = B_PARTITION_VALID; 192 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 193 partition->content_size = partition->size; 194 // (no content_name and content_parameters) 195 // (content_type is set by the system) 196 197 partition->content_cookie = map; 198 // children 199 status_t error = B_OK; 200 int32 index = 0; 201 for (int32 i = 0; i < 4; i++) { 202 PrimaryPartition* primary = map->PrimaryPartitionAt(i); 203 if (!primary->IsEmpty()) { 204 partition_data* child = create_child_partition(partition->id, 205 index, partition->offset + primary->Offset(), primary->Size(), 206 -1); 207 index++; 208 if (!child) { 209 // something went wrong 210 error = B_ERROR; 211 break; 212 } 213 214 child->block_size = partition->block_size; 215 216 // (no name) 217 char type[B_FILE_NAME_LENGTH]; 218 primary->GetTypeString(type); 219 child->type = strdup(type); 220 // parameters 221 char buffer[128]; 222 sprintf(buffer, "type = %u ; active = %d", primary->Type(), 223 primary->Active()); 224 child->parameters = strdup(buffer); 225 child->cookie = primary; 226 // check for allocation problems 227 if (!child->type || !child->parameters) { 228 error = B_NO_MEMORY; 229 break; 230 } 231 } 232 } 233 234 // keep map on success or cleanup on error 235 if (error == B_OK) { 236 atomic_add(&map->ref_count, 1); 237 } else { 238 partition->content_cookie = NULL; 239 for (int32 i = 0; i < partition->child_count; i++) { 240 if (partition_data* child = get_child_partition(partition->id, i)) 241 child->cookie = NULL; 242 } 243 } 244 245 return error; 246 } 247 248 249 // pm_free_identify_partition_cookie 250 static void 251 pm_free_identify_partition_cookie(partition_data*/* partition*/, void* cookie) 252 { 253 if (cookie) { 254 PartitionMapCookie* map = (PartitionMapCookie*)cookie; 255 if (atomic_add(&map->ref_count, -1) == 1) 256 delete map; 257 } 258 } 259 260 261 // pm_free_partition_cookie 262 static void 263 pm_free_partition_cookie(partition_data* partition) 264 { 265 // called for the primary partitions: the PrimaryPartition is allocated 266 // by the partition containing the partition map 267 if (partition) 268 partition->cookie = NULL; 269 } 270 271 272 // pm_free_partition_content_cookie 273 static void 274 pm_free_partition_content_cookie(partition_data* partition) 275 { 276 if (partition && partition->content_cookie) { 277 pm_free_identify_partition_cookie(partition, partition->content_cookie); 278 partition->content_cookie = NULL; 279 } 280 } 281 282 283 // #pragma mark - Intel Extended Partition Module 284 285 286 // ep_std_ops 287 static status_t 288 ep_std_ops(int32 op, ...) 289 { 290 TRACE(("intel: ep_std_ops(0x%" B_PRIx32 ")\n", op)); 291 switch(op) { 292 case B_MODULE_INIT: 293 case B_MODULE_UNINIT: 294 return B_OK; 295 } 296 return B_ERROR; 297 } 298 299 300 // ep_identify_partition 301 static float 302 ep_identify_partition(int fd, partition_data* partition, void** cookie) 303 { 304 // check parameters 305 if (fd < 0 || !partition || !cookie || !partition->cookie) 306 return -1; 307 308 TRACE(("intel: ep_identify_partition(%d, %" B_PRId64 ", %" B_PRId64 ", " 309 "%" B_PRId32 ")\n", fd, partition->offset, partition->size, 310 partition->block_size)); 311 312 // our parent must be a intel partition map partition and we must have 313 // extended partition type 314 if (!partition->type 315 || strcmp(partition->type, kPartitionTypeIntelExtended)) { 316 return -1; 317 } 318 partition_data* parent = get_parent_partition(partition->id); 319 if (!parent || !parent->content_type 320 || strcmp(parent->content_type, kPartitionTypeIntel)) { 321 return -1; 322 } 323 324 // things seem to be in order 325 return 0.95; 326 } 327 328 329 // ep_scan_partition 330 static status_t 331 ep_scan_partition(int fd, partition_data* partition, void* cookie) 332 { 333 // check parameters 334 if (fd < 0 || !partition || !partition->cookie) 335 return B_ERROR; 336 337 TRACE(("intel: ep_scan_partition(%d, %" B_PRId64 ", %" B_PRId64 ", " 338 "%" B_PRId32 ")\n", fd, partition->offset, partition->size, 339 partition->block_size)); 340 341 partition_data* parent = get_parent_partition(partition->id); 342 if (!parent) 343 return B_ERROR; 344 345 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 346 // fill in the partition_data structure 347 partition->status = B_PARTITION_VALID; 348 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 349 partition->content_size = partition->size; 350 // (no content_name and content_parameters) 351 // (content_type is set by the system) 352 353 partition->content_cookie = primary; 354 // children 355 status_t error = B_OK; 356 int32 index = 0; 357 for (int32 i = 0; i < primary->CountLogicalPartitions(); i++) { 358 LogicalPartition* logical = primary->LogicalPartitionAt(i); 359 partition_data* child = create_child_partition(partition->id, index, 360 parent->offset + logical->Offset(), logical->Size(), -1); 361 index++; 362 if (!child) { 363 // something went wrong 364 TRACE(("intel: ep_scan_partition(): failed to create child " 365 "partition\n")); 366 error = B_ERROR; 367 break; 368 } 369 child->block_size = partition->block_size; 370 371 // (no name) 372 char type[B_FILE_NAME_LENGTH]; 373 logical->GetTypeString(type); 374 child->type = strdup(type); 375 376 // parameters 377 char buffer[128]; 378 sprintf(buffer, "active %s ;\npartition_table_offset %" B_PRId64 " ;\n", 379 logical->Active() ? "true" : "false", 380 logical->PartitionTableOffset()); 381 child->parameters = strdup(buffer); 382 child->cookie = logical; 383 // check for allocation problems 384 if (!child->type || !child->parameters) { 385 TRACE(("intel: ep_scan_partition(): failed to allocation type " 386 "or parameters\n")); 387 error = B_NO_MEMORY; 388 break; 389 } 390 } 391 392 // cleanup on error 393 if (error != B_OK) { 394 partition->content_cookie = NULL; 395 for (int32 i = 0; i < partition->child_count; i++) { 396 if (partition_data* child = get_child_partition(partition->id, i)) 397 child->cookie = NULL; 398 } 399 } 400 return error; 401 } 402 403 404 // ep_free_identify_partition_cookie 405 static void 406 ep_free_identify_partition_cookie(partition_data* partition, void* cookie) 407 { 408 // nothing to do 409 } 410 411 412 // ep_free_partition_cookie 413 static void 414 ep_free_partition_cookie(partition_data* partition) 415 { 416 // the logical partition's cookie belongs to the partition map partition 417 if (partition) 418 partition->cookie = NULL; 419 } 420 421 422 // ep_free_partition_content_cookie 423 static void 424 ep_free_partition_content_cookie(partition_data* partition) 425 { 426 // the extended partition's cookie belongs to the partition map partition 427 if (partition) 428 partition->content_cookie = NULL; 429 } 430 431 432 // #pragma mark - modules 433 434 435 #ifdef _BOOT_MODE 436 partition_module_info gIntelPartitionMapModule = 437 #else 438 static partition_module_info intel_partition_map_module = 439 #endif 440 { 441 { 442 INTEL_PARTITION_MODULE_NAME, 443 0, 444 pm_std_ops 445 }, 446 "intel", // short_name 447 INTEL_PARTITION_NAME, // pretty_name 448 449 // flags 450 0 451 // | B_DISK_SYSTEM_SUPPORTS_CHECKING 452 // | B_DISK_SYSTEM_SUPPORTS_REPAIRING 453 | B_DISK_SYSTEM_SUPPORTS_RESIZING 454 | B_DISK_SYSTEM_SUPPORTS_MOVING 455 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME 456 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS 457 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING 458 // | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 459 460 | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 461 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 462 // | B_DISK_SYSTEM_SUPPORTS_SETTING_NAME 463 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 464 // | B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS 465 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD 466 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD 467 // | B_DISK_SYSTEM_SUPPORTS_NAME 468 , 469 470 // scanning 471 pm_identify_partition, // identify_partition 472 pm_scan_partition, // scan_partition 473 pm_free_identify_partition_cookie, // free_identify_partition_cookie 474 pm_free_partition_cookie, // free_partition_cookie 475 pm_free_partition_content_cookie, // free_partition_content_cookie 476 477 #ifndef _BOOT_MODE 478 // querying 479 pm_get_supported_operations, // get_supported_operations 480 pm_get_supported_child_operations, // get_supported_child_operations 481 NULL, // supports_initializing_child 482 pm_is_sub_system_for, // is_sub_system_for 483 484 pm_validate_resize, // validate_resize 485 pm_validate_resize_child, // validate_resize_child 486 pm_validate_move, // validate_move 487 pm_validate_move_child, // validate_move_child 488 NULL, // validate_set_name 489 NULL, // validate_set_content_name 490 pm_validate_set_type, // validate_set_type 491 NULL, // validate_set_parameters 492 NULL, // validate_set_content_parameters 493 pm_validate_initialize, // validate_initialize 494 pm_validate_create_child, // validate_create_child 495 pm_get_partitionable_spaces, // get_partitionable_spaces 496 pm_get_next_supported_type, // get_next_supported_type 497 get_type_for_content_type, // get_type_for_content_type 498 499 // shadow partition modification 500 pm_shadow_changed, // shadow_changed 501 502 // writing 503 NULL, // repair 504 pm_resize, // resize 505 pm_resize_child, // resize_child 506 pm_move, // move 507 pm_move_child, // move_child 508 NULL, // set_name 509 NULL, // set_content_name 510 pm_set_type, // set_type 511 NULL, // set_parameters 512 NULL, // set_content_parameters 513 pm_initialize, // initialize 514 pm_uninitialize, // uninitialize 515 pm_create_child, // create_child 516 pm_delete_child, // delete_child 517 #else 518 NULL 519 #endif // _BOOT_MODE 520 }; 521 522 523 #ifdef _BOOT_MODE 524 partition_module_info gIntelExtendedPartitionModule = 525 #else 526 static partition_module_info intel_extended_partition_module = 527 #endif 528 { 529 { 530 INTEL_EXTENDED_PARTITION_MODULE_NAME, 531 0, 532 ep_std_ops 533 }, 534 "intel_extended", // short_name 535 INTEL_EXTENDED_PARTITION_NAME, // pretty_name 536 537 // flags 538 0 539 // | B_DISK_SYSTEM_SUPPORTS_CHECKING 540 // | B_DISK_SYSTEM_SUPPORTS_REPAIRING 541 | B_DISK_SYSTEM_SUPPORTS_RESIZING 542 | B_DISK_SYSTEM_SUPPORTS_MOVING 543 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME 544 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS 545 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING 546 // | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 547 548 | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 549 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 550 // | B_DISK_SYSTEM_SUPPORTS_SETTING_NAME 551 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 552 // | B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS 553 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD 554 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD 555 // | B_DISK_SYSTEM_SUPPORTS_NAME 556 , 557 558 // scanning 559 ep_identify_partition, // identify_partition 560 ep_scan_partition, // scan_partition 561 ep_free_identify_partition_cookie, // free_identify_partition_cookie 562 ep_free_partition_cookie, // free_partition_cookie 563 ep_free_partition_content_cookie, // free_partition_content_cookie 564 565 #ifndef _BOOT_MODE 566 // querying 567 ep_get_supported_operations, // get_supported_operations 568 ep_get_supported_child_operations, // get_supported_child_operations 569 NULL, // supports_initializing_child 570 ep_is_sub_system_for, // is_sub_system_for 571 572 ep_validate_resize, // validate_resize 573 ep_validate_resize_child, // validate_resize_child 574 ep_validate_move, // validate_move 575 ep_validate_move_child, // validate_move_child 576 NULL, // validate_set_name 577 NULL, // validate_set_content_name 578 ep_validate_set_type, // validate_set_type 579 NULL, // validate_set_parameters 580 NULL, // validate_set_content_parameters 581 ep_validate_initialize, // validate_initialize 582 ep_validate_create_child, // validate_create_child 583 ep_get_partitionable_spaces, // get_partitionable_spaces 584 ep_get_next_supported_type, // get_next_supported_type 585 get_type_for_content_type, // get_type_for_content_type 586 587 // shadow partition modification 588 ep_shadow_changed, // shadow_changed 589 590 // writing 591 NULL, // repair 592 ep_resize, // resize 593 ep_resize_child, // resize_child 594 ep_move, // move 595 ep_move_child, // move_child 596 NULL, // set_name 597 NULL, // set_content_name 598 ep_set_type, // set_type 599 NULL, // set_parameters 600 NULL, // set_content_parameters 601 ep_initialize, // initialize 602 NULL, // uninitialize 603 ep_create_child, // create_child 604 ep_delete_child, // delete_child 605 #else // _BOOT_MODE 606 NULL 607 #endif // _BOOT_MODE 608 }; 609 610 611 #ifndef _BOOT_MODE 612 extern "C" partition_module_info* modules[]; 613 _EXPORT partition_module_info* modules[] = 614 { 615 &intel_partition_map_module, 616 &intel_extended_partition_module, 617 NULL 618 }; 619 #endif 620