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, -1); 206 index++; 207 if (!child) { 208 // something went wrong 209 error = B_ERROR; 210 break; 211 } 212 213 child->offset = partition->offset + primary->Offset(); 214 child->size = primary->Size(); 215 child->block_size = partition->block_size; 216 217 // (no name) 218 char type[B_FILE_NAME_LENGTH]; 219 primary->GetTypeString(type); 220 child->type = strdup(type); 221 // parameters 222 char buffer[128]; 223 sprintf(buffer, "type = %u ; active = %d", primary->Type(), 224 primary->Active()); 225 child->parameters = strdup(buffer); 226 child->cookie = primary; 227 // check for allocation problems 228 if (!child->type || !child->parameters) { 229 error = B_NO_MEMORY; 230 break; 231 } 232 } 233 } 234 235 // keep map on success or cleanup on error 236 if (error == B_OK) { 237 atomic_add(&map->ref_count, 1); 238 } else { 239 partition->content_cookie = NULL; 240 for (int32 i = 0; i < partition->child_count; i++) { 241 if (partition_data *child = get_child_partition(partition->id, i)) 242 child->cookie = NULL; 243 } 244 } 245 246 return error; 247 } 248 249 250 // pm_free_identify_partition_cookie 251 static void 252 pm_free_identify_partition_cookie(partition_data */*partition*/, void *cookie) 253 { 254 if (cookie) { 255 PartitionMapCookie *map = (PartitionMapCookie*)cookie; 256 if (atomic_add(&map->ref_count, -1) == 1) 257 delete map; 258 } 259 } 260 261 262 // pm_free_partition_cookie 263 static void 264 pm_free_partition_cookie(partition_data *partition) 265 { 266 // called for the primary partitions: the PrimaryPartition is allocated 267 // by the partition containing the partition map 268 if (partition) 269 partition->cookie = NULL; 270 } 271 272 273 // pm_free_partition_content_cookie 274 static void 275 pm_free_partition_content_cookie(partition_data *partition) 276 { 277 if (partition && partition->content_cookie) { 278 pm_free_identify_partition_cookie(partition, partition->content_cookie); 279 partition->content_cookie = NULL; 280 } 281 } 282 283 284 // #pragma mark - Intel Extended Partition Module 285 286 287 // ep_std_ops 288 static status_t 289 ep_std_ops(int32 op, ...) 290 { 291 TRACE(("intel: ep_std_ops(0x%lx)\n", op)); 292 switch(op) { 293 case B_MODULE_INIT: 294 case B_MODULE_UNINIT: 295 return B_OK; 296 } 297 return B_ERROR; 298 } 299 300 301 // ep_identify_partition 302 static float 303 ep_identify_partition(int fd, partition_data *partition, void **cookie) 304 { 305 // check parameters 306 if (fd < 0 || !partition || !cookie || !partition->cookie) 307 return -1; 308 309 TRACE(("intel: ep_identify_partition(%d, %lld, %lld, %ld)\n", fd, 310 partition->offset, partition->size, 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, %lld, %lld, %ld)\n", fd, 338 partition->offset, partition->size, partition->block_size)); 339 340 partition_data *parent = get_parent_partition(partition->id); 341 if (!parent) 342 return B_ERROR; 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, -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->offset = parent->offset + logical->Offset(); 367 child->size = logical->Size(); 368 child->block_size = partition->block_size; 369 370 // (no name) 371 char type[B_FILE_NAME_LENGTH]; 372 logical->GetTypeString(type); 373 child->type = strdup(type); 374 375 // parameters 376 char buffer[128]; 377 sprintf(buffer, "type = %u ; active = %d", logical->Type(), 378 logical->Active()); 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