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 <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%lx)\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, %ld: %lld, %lld, %ld)\n", fd, 121 partition->id, partition->offset, partition->size, 122 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, %ld: %lld, %lld, %ld)\n", fd, 186 partition->id, partition->offset, partition->size, 187 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%lx)\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, %lld, %lld, %ld)\n", fd, 309 partition->offset, partition->size, partition->block_size)); 310 311 // our parent must be a intel partition map partition and we must have 312 // extended partition type 313 if (!partition->type 314 || strcmp(partition->type, kPartitionTypeIntelExtended)) { 315 return -1; 316 } 317 partition_data* parent = get_parent_partition(partition->id); 318 if (!parent || !parent->content_type 319 || strcmp(parent->content_type, kPartitionTypeIntel)) { 320 return -1; 321 } 322 323 // things seem to be in order 324 return 0.95; 325 } 326 327 328 // ep_scan_partition 329 static status_t 330 ep_scan_partition(int fd, partition_data* partition, void* cookie) 331 { 332 // check parameters 333 if (fd < 0 || !partition || !partition->cookie) 334 return B_ERROR; 335 336 TRACE(("intel: ep_scan_partition(%d, %lld, %lld, %ld)\n", fd, 337 partition->offset, partition->size, partition->block_size)); 338 339 partition_data* parent = get_parent_partition(partition->id); 340 if (!parent) 341 return B_ERROR; 342 343 PrimaryPartition* primary = (PrimaryPartition*)partition->cookie; 344 // fill in the partition_data structure 345 partition->status = B_PARTITION_VALID; 346 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 347 partition->content_size = partition->size; 348 // (no content_name and content_parameters) 349 // (content_type is set by the system) 350 351 partition->content_cookie = primary; 352 // children 353 status_t error = B_OK; 354 int32 index = 0; 355 for (int32 i = 0; i < primary->CountLogicalPartitions(); i++) { 356 LogicalPartition* logical = primary->LogicalPartitionAt(i); 357 partition_data* child = create_child_partition(partition->id, index, 358 parent->offset + logical->Offset(), logical->Size(), -1); 359 index++; 360 if (!child) { 361 // something went wrong 362 TRACE(("intel: ep_scan_partition(): failed to create child " 363 "partition\n")); 364 error = B_ERROR; 365 break; 366 } 367 child->block_size = partition->block_size; 368 369 // (no name) 370 char type[B_FILE_NAME_LENGTH]; 371 logical->GetTypeString(type); 372 child->type = strdup(type); 373 374 // parameters 375 char buffer[128]; 376 sprintf(buffer, "active %s ;\npartition_table_offset %lld ;\n", 377 logical->Active() ? "true" : "false", 378 logical->PartitionTableOffset()); 379 child->parameters = strdup(buffer); 380 child->cookie = logical; 381 // check for allocation problems 382 if (!child->type || !child->parameters) { 383 TRACE(("intel: ep_scan_partition(): failed to allocation type " 384 "or parameters\n")); 385 error = B_NO_MEMORY; 386 break; 387 } 388 } 389 390 // cleanup on error 391 if (error != B_OK) { 392 partition->content_cookie = NULL; 393 for (int32 i = 0; i < partition->child_count; i++) { 394 if (partition_data* child = get_child_partition(partition->id, i)) 395 child->cookie = NULL; 396 } 397 } 398 return error; 399 } 400 401 402 // ep_free_identify_partition_cookie 403 static void 404 ep_free_identify_partition_cookie(partition_data* partition, void* cookie) 405 { 406 // nothing to do 407 } 408 409 410 // ep_free_partition_cookie 411 static void 412 ep_free_partition_cookie(partition_data* partition) 413 { 414 // the logical partition's cookie belongs to the partition map partition 415 if (partition) 416 partition->cookie = NULL; 417 } 418 419 420 // ep_free_partition_content_cookie 421 static void 422 ep_free_partition_content_cookie(partition_data* partition) 423 { 424 // the extended partition's cookie belongs to the partition map partition 425 if (partition) 426 partition->content_cookie = NULL; 427 } 428 429 430 // #pragma mark - modules 431 432 433 #ifdef _BOOT_MODE 434 partition_module_info gIntelPartitionMapModule = 435 #else 436 static partition_module_info intel_partition_map_module = 437 #endif 438 { 439 { 440 INTEL_PARTITION_MODULE_NAME, 441 0, 442 pm_std_ops 443 }, 444 "intel", // short_name 445 INTEL_PARTITION_NAME, // pretty_name 446 447 // flags 448 0 449 // | B_DISK_SYSTEM_SUPPORTS_CHECKING 450 // | B_DISK_SYSTEM_SUPPORTS_REPAIRING 451 | B_DISK_SYSTEM_SUPPORTS_RESIZING 452 | B_DISK_SYSTEM_SUPPORTS_MOVING 453 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME 454 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS 455 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING 456 // | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 457 458 | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 459 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 460 // | B_DISK_SYSTEM_SUPPORTS_SETTING_NAME 461 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 462 // | B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS 463 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD 464 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD 465 // | B_DISK_SYSTEM_SUPPORTS_NAME 466 , 467 468 // scanning 469 pm_identify_partition, // identify_partition 470 pm_scan_partition, // scan_partition 471 pm_free_identify_partition_cookie, // free_identify_partition_cookie 472 pm_free_partition_cookie, // free_partition_cookie 473 pm_free_partition_content_cookie, // free_partition_content_cookie 474 475 #ifndef _BOOT_MODE 476 // querying 477 pm_get_supported_operations, // get_supported_operations 478 pm_get_supported_child_operations, // get_supported_child_operations 479 NULL, // supports_initializing_child 480 pm_is_sub_system_for, // is_sub_system_for 481 482 pm_validate_resize, // validate_resize 483 pm_validate_resize_child, // validate_resize_child 484 pm_validate_move, // validate_move 485 pm_validate_move_child, // validate_move_child 486 NULL, // validate_set_name 487 NULL, // validate_set_content_name 488 pm_validate_set_type, // validate_set_type 489 NULL, // validate_set_parameters 490 NULL, // validate_set_content_parameters 491 pm_validate_initialize, // validate_initialize 492 pm_validate_create_child, // validate_create_child 493 pm_get_partitionable_spaces, // get_partitionable_spaces 494 pm_get_next_supported_type, // get_next_supported_type 495 get_type_for_content_type, // get_type_for_content_type 496 497 // shadow partition modification 498 pm_shadow_changed, // shadow_changed 499 500 // writing 501 NULL, // repair 502 pm_resize, // resize 503 pm_resize_child, // resize_child 504 pm_move, // move 505 pm_move_child, // move_child 506 NULL, // set_name 507 NULL, // set_content_name 508 pm_set_type, // set_type 509 NULL, // set_parameters 510 NULL, // set_content_parameters 511 pm_initialize, // initialize 512 pm_create_child, // create_child 513 pm_delete_child, // delete_child 514 #else 515 NULL 516 #endif // _BOOT_MODE 517 }; 518 519 520 #ifdef _BOOT_MODE 521 partition_module_info gIntelExtendedPartitionModule = 522 #else 523 static partition_module_info intel_extended_partition_module = 524 #endif 525 { 526 { 527 INTEL_EXTENDED_PARTITION_MODULE_NAME, 528 0, 529 ep_std_ops 530 }, 531 "intel_extended", // short_name 532 INTEL_EXTENDED_PARTITION_NAME, // pretty_name 533 534 // flags 535 0 536 // | B_DISK_SYSTEM_SUPPORTS_CHECKING 537 // | B_DISK_SYSTEM_SUPPORTS_REPAIRING 538 | B_DISK_SYSTEM_SUPPORTS_RESIZING 539 | B_DISK_SYSTEM_SUPPORTS_MOVING 540 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME 541 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS 542 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING 543 // | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 544 545 | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 546 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 547 // | B_DISK_SYSTEM_SUPPORTS_SETTING_NAME 548 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 549 // | B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS 550 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD 551 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD 552 // | B_DISK_SYSTEM_SUPPORTS_NAME 553 , 554 555 // scanning 556 ep_identify_partition, // identify_partition 557 ep_scan_partition, // scan_partition 558 ep_free_identify_partition_cookie, // free_identify_partition_cookie 559 ep_free_partition_cookie, // free_partition_cookie 560 ep_free_partition_content_cookie, // free_partition_content_cookie 561 562 #ifndef _BOOT_MODE 563 // querying 564 ep_get_supported_operations, // get_supported_operations 565 ep_get_supported_child_operations, // get_supported_child_operations 566 NULL, // supports_initializing_child 567 ep_is_sub_system_for, // is_sub_system_for 568 569 ep_validate_resize, // validate_resize 570 ep_validate_resize_child, // validate_resize_child 571 ep_validate_move, // validate_move 572 ep_validate_move_child, // validate_move_child 573 NULL, // validate_set_name 574 NULL, // validate_set_content_name 575 ep_validate_set_type, // validate_set_type 576 NULL, // validate_set_parameters 577 NULL, // validate_set_content_parameters 578 ep_validate_initialize, // validate_initialize 579 ep_validate_create_child, // validate_create_child 580 ep_get_partitionable_spaces, // get_partitionable_spaces 581 ep_get_next_supported_type, // get_next_supported_type 582 get_type_for_content_type, // get_type_for_content_type 583 584 // shadow partition modification 585 ep_shadow_changed, // shadow_changed 586 587 // writing 588 NULL, // repair 589 ep_resize, // resize 590 ep_resize_child, // resize_child 591 ep_move, // move 592 ep_move_child, // move_child 593 NULL, // set_name 594 NULL, // set_content_name 595 ep_set_type, // set_type 596 NULL, // set_parameters 597 NULL, // set_content_parameters 598 ep_initialize, // initialize 599 ep_create_child, // create_child 600 ep_delete_child, // delete_child 601 #else // _BOOT_MODE 602 NULL 603 #endif // _BOOT_MODE 604 }; 605 606 607 #ifndef _BOOT_MODE 608 extern "C" partition_module_info* modules[]; 609 _EXPORT partition_module_info* modules[] = 610 { 611 &intel_partition_map_module, 612 &intel_extended_partition_module, 613 NULL 614 }; 615 #endif 616