1 /* 2 * Copyright 2003-2008, 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); 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 // pm_scan_partition 177 static status_t 178 pm_scan_partition(int fd, partition_data *partition, void *cookie) 179 { 180 // check parameters 181 if (fd < 0 || !partition || !cookie) 182 return B_ERROR; 183 184 TRACE(("intel: pm_scan_partition(%d, %ld: %lld, %lld, %ld)\n", fd, 185 partition->id, partition->offset, partition->size, 186 partition->block_size)); 187 188 PartitionMapCookie *map = (PartitionMapCookie*)cookie; 189 // fill in the partition_data structure 190 partition->status = B_PARTITION_VALID; 191 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 192 partition->content_size = partition->size; 193 // (no content_name and content_parameters) 194 // (content_type is set by the system) 195 partition->block_size = SECTOR_SIZE; 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 = SECTOR_SIZE; 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 // pm_free_identify_partition_cookie 249 static void 250 pm_free_identify_partition_cookie(partition_data */*partition*/, void *cookie) 251 { 252 if (cookie) { 253 PartitionMapCookie *map = (PartitionMapCookie*)cookie; 254 if (atomic_add(&map->ref_count, -1) == 1) 255 delete map; 256 } 257 } 258 259 // pm_free_partition_cookie 260 static void 261 pm_free_partition_cookie(partition_data *partition) 262 { 263 // called for the primary partitions: the PrimaryPartition is allocated 264 // by the partition containing the partition map 265 if (partition) 266 partition->cookie = NULL; 267 } 268 269 // pm_free_partition_content_cookie 270 static void 271 pm_free_partition_content_cookie(partition_data *partition) 272 { 273 if (partition && partition->content_cookie) { 274 pm_free_identify_partition_cookie(partition, partition->content_cookie); 275 partition->content_cookie = NULL; 276 } 277 } 278 279 // #pragma mark - Intel Extended Partition Module 280 281 282 // ep_std_ops 283 static status_t 284 ep_std_ops(int32 op, ...) 285 { 286 TRACE(("intel: ep_std_ops(0x%lx)\n", op)); 287 switch(op) { 288 case B_MODULE_INIT: 289 case B_MODULE_UNINIT: 290 return B_OK; 291 } 292 return B_ERROR; 293 } 294 295 // ep_identify_partition 296 static float 297 ep_identify_partition(int fd, partition_data *partition, void **cookie) 298 { 299 // check parameters 300 if (fd < 0 || !partition || !cookie || !partition->cookie) 301 return -1; 302 303 TRACE(("intel: ep_identify_partition(%d, %lld, %lld, %ld)\n", fd, 304 partition->offset, partition->size, partition->block_size)); 305 306 // our parent must be a intel partition map partition and we must have 307 // extended partition type 308 if (!partition->type 309 || strcmp(partition->type, kPartitionTypeIntelExtended)) { 310 return -1; 311 } 312 partition_data *parent = get_parent_partition(partition->id); 313 if (!parent || !parent->content_type 314 || strcmp(parent->content_type, kPartitionTypeIntel)) { 315 return -1; 316 } 317 318 // things seem to be in order 319 return 0.95; 320 } 321 322 // ep_scan_partition 323 static status_t 324 ep_scan_partition(int fd, partition_data *partition, void *cookie) 325 { 326 // check parameters 327 if (fd < 0 || !partition || !partition->cookie) 328 return B_ERROR; 329 330 TRACE(("intel: ep_scan_partition(%d, %lld, %lld, %ld)\n", fd, 331 partition->offset, partition->size, partition->block_size)); 332 333 partition_data *parent = get_parent_partition(partition->id); 334 if (!parent) 335 return B_ERROR; 336 PrimaryPartition *primary = (PrimaryPartition*)partition->cookie; 337 // fill in the partition_data structure 338 partition->status = B_PARTITION_VALID; 339 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 340 partition->content_size = partition->size; 341 // (no content_name and content_parameters) 342 // (content_type is set by the system) 343 partition->block_size = SECTOR_SIZE; 344 345 partition->content_cookie = primary; 346 // children 347 status_t error = B_OK; 348 int32 index = 0; 349 for (int32 i = 0; i < primary->CountLogicalPartitions(); i++) { 350 LogicalPartition *logical = primary->LogicalPartitionAt(i); 351 partition_data *child = create_child_partition(partition->id, 352 index, -1); 353 index++; 354 if (!child) { 355 // something went wrong 356 TRACE(("intel: ep_scan_partition(): failed to create child " 357 "partition\n")); 358 error = B_ERROR; 359 break; 360 } 361 child->offset = parent->offset + logical->Offset(); 362 child->size = logical->Size(); 363 child->block_size = SECTOR_SIZE; 364 // (no name) 365 char type[B_FILE_NAME_LENGTH]; 366 logical->GetTypeString(type); 367 child->type = strdup(type); 368 369 // parameters 370 char buffer[128]; 371 sprintf(buffer, "type = %u ; active = %d", logical->Type(), 372 logical->Active()); 373 child->parameters = strdup(buffer); 374 child->cookie = logical; 375 // check for allocation problems 376 if (!child->type || !child->parameters) { 377 TRACE(("intel: ep_scan_partition(): failed to allocation type " 378 "or parameters\n")); 379 error = B_NO_MEMORY; 380 break; 381 } 382 } 383 // cleanup on error 384 if (error != B_OK) { 385 partition->content_cookie = NULL; 386 for (int32 i = 0; i < partition->child_count; i++) { 387 if (partition_data *child = get_child_partition(partition->id, i)) 388 child->cookie = NULL; 389 } 390 } 391 return error; 392 } 393 394 // ep_free_identify_partition_cookie 395 static void 396 ep_free_identify_partition_cookie(partition_data *partition, void *cookie) 397 { 398 // nothing to do 399 } 400 401 // ep_free_partition_cookie 402 static void 403 ep_free_partition_cookie(partition_data *partition) 404 { 405 // the logical partition's cookie belongs to the partition map partition 406 if (partition) 407 partition->cookie = NULL; 408 } 409 410 // ep_free_partition_content_cookie 411 static void 412 ep_free_partition_content_cookie(partition_data *partition) 413 { 414 // the extended partition's cookie belongs to the partition map partition 415 if (partition) 416 partition->content_cookie = NULL; 417 } 418 419 420 // #pragma mark - modules 421 422 423 #ifdef _BOOT_MODE 424 partition_module_info gIntelPartitionMapModule = 425 #else 426 static partition_module_info intel_partition_map_module = 427 #endif 428 { 429 { 430 INTEL_PARTITION_MODULE_NAME, 431 0, 432 pm_std_ops 433 }, 434 "intel", // short_name 435 INTEL_PARTITION_NAME, // pretty_name 436 437 // flags 438 0 439 // | B_DISK_SYSTEM_SUPPORTS_CHECKING 440 // | B_DISK_SYSTEM_SUPPORTS_REPAIRING 441 | B_DISK_SYSTEM_SUPPORTS_RESIZING 442 | B_DISK_SYSTEM_SUPPORTS_MOVING 443 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME 444 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS 445 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING 446 // | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 447 448 | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 449 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 450 // | B_DISK_SYSTEM_SUPPORTS_SETTING_NAME 451 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 452 // | B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS 453 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD 454 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD 455 // | B_DISK_SYSTEM_SUPPORTS_NAME 456 , 457 458 // scanning 459 pm_identify_partition, // identify_partition 460 pm_scan_partition, // scan_partition 461 pm_free_identify_partition_cookie, // free_identify_partition_cookie 462 pm_free_partition_cookie, // free_partition_cookie 463 pm_free_partition_content_cookie, // free_partition_content_cookie 464 465 #ifndef _BOOT_MODE 466 // querying 467 pm_get_supported_operations, // get_supported_operations 468 pm_get_supported_child_operations, // get_supported_child_operations 469 NULL, // supports_initializing_child 470 pm_is_sub_system_for, // is_sub_system_for 471 472 pm_validate_resize, // validate_resize 473 pm_validate_resize_child, // validate_resize_child 474 pm_validate_move, // validate_move 475 pm_validate_move_child, // validate_move_child 476 NULL, // validate_set_name 477 NULL, // validate_set_content_name 478 pm_validate_set_type, // validate_set_type 479 NULL, // validate_set_parameters 480 NULL, // validate_set_content_parameters 481 pm_validate_initialize, // validate_initialize 482 pm_validate_create_child, // validate_create_child 483 pm_get_partitionable_spaces, // get_partitionable_spaces 484 pm_get_next_supported_type, // get_next_supported_type 485 get_type_for_content_type, // get_type_for_content_type 486 487 // shadow partition modification 488 pm_shadow_changed, // shadow_changed 489 490 // writing 491 NULL, // repair 492 pm_resize, // resize 493 pm_resize_child, // resize_child 494 pm_move, // move 495 pm_move_child, // move_child 496 NULL, // set_name 497 NULL, // set_content_name 498 pm_set_type, // set_type 499 NULL, // set_parameters 500 NULL, // set_content_parameters 501 pm_initialize, // initialize 502 pm_create_child, // create_child 503 pm_delete_child, // delete_child 504 #else 505 NULL 506 #endif // _BOOT_MODE 507 }; 508 509 510 #ifdef _BOOT_MODE 511 partition_module_info gIntelExtendedPartitionModule = 512 #else 513 static partition_module_info intel_extended_partition_module = 514 #endif 515 { 516 { 517 INTEL_EXTENDED_PARTITION_MODULE_NAME, 518 0, 519 ep_std_ops 520 }, 521 "intel_extended", // short_name 522 INTEL_EXTENDED_PARTITION_NAME, // pretty_name 523 524 // flags 525 0 526 // | B_DISK_SYSTEM_SUPPORTS_CHECKING 527 // | B_DISK_SYSTEM_SUPPORTS_REPAIRING 528 | B_DISK_SYSTEM_SUPPORTS_RESIZING 529 | B_DISK_SYSTEM_SUPPORTS_MOVING 530 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME 531 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS 532 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING 533 // | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 534 535 | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 536 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 537 // | B_DISK_SYSTEM_SUPPORTS_SETTING_NAME 538 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 539 // | B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS 540 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD 541 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD 542 // | B_DISK_SYSTEM_SUPPORTS_NAME 543 , 544 545 // scanning 546 ep_identify_partition, // identify_partition 547 ep_scan_partition, // scan_partition 548 ep_free_identify_partition_cookie, // free_identify_partition_cookie 549 ep_free_partition_cookie, // free_partition_cookie 550 ep_free_partition_content_cookie, // free_partition_content_cookie 551 552 #ifndef _BOOT_MODE 553 // querying 554 ep_get_supported_operations, // get_supported_operations 555 ep_get_supported_child_operations, // get_supported_child_operations 556 NULL, // supports_initializing_child 557 ep_is_sub_system_for, // is_sub_system_for 558 559 ep_validate_resize, // validate_resize 560 ep_validate_resize_child, // validate_resize_child 561 ep_validate_move, // validate_move 562 ep_validate_move_child, // validate_move_child 563 NULL, // validate_set_name 564 NULL, // validate_set_content_name 565 ep_validate_set_type, // validate_set_type 566 NULL, // validate_set_parameters 567 NULL, // validate_set_content_parameters 568 ep_validate_initialize, // validate_initialize 569 ep_validate_create_child, // validate_create_child 570 ep_get_partitionable_spaces, // get_partitionable_spaces 571 ep_get_next_supported_type, // get_next_supported_type 572 get_type_for_content_type, // get_type_for_content_type 573 574 // shadow partition modification 575 ep_shadow_changed, // shadow_changed 576 577 // writing 578 NULL, // repair 579 ep_resize, // resize 580 ep_resize_child, // resize_child 581 ep_move, // move 582 ep_move_child, // move_child 583 NULL, // set_name 584 NULL, // set_content_name 585 ep_set_type, // set_type 586 NULL, // set_parameters 587 NULL, // set_content_parameters 588 ep_initialize, // initialize 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