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