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