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