1 /* 2 * Copyright 2003-2007, 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_PARTITION_NAME, // pretty_name 431 432 // flags 433 0 434 // | B_DISK_SYSTEM_SUPPORTS_CHECKING 435 // | B_DISK_SYSTEM_SUPPORTS_REPAIRING 436 | B_DISK_SYSTEM_SUPPORTS_RESIZING 437 | B_DISK_SYSTEM_SUPPORTS_MOVING 438 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME 439 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS 440 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING 441 // | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 442 443 | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 444 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 445 // | B_DISK_SYSTEM_SUPPORTS_SETTING_NAME 446 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 447 // | B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS 448 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD 449 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD 450 // | B_DISK_SYSTEM_SUPPORTS_NAME 451 , 452 453 // scanning 454 pm_identify_partition, // identify_partition 455 pm_scan_partition, // scan_partition 456 pm_free_identify_partition_cookie, // free_identify_partition_cookie 457 pm_free_partition_cookie, // free_partition_cookie 458 pm_free_partition_content_cookie, // free_partition_content_cookie 459 460 #ifndef _BOOT_MODE 461 // querying 462 pm_get_supported_operations, // get_supported_operations 463 pm_get_supported_child_operations, // get_supported_child_operations 464 NULL, // supports_initializing_child 465 pm_is_sub_system_for, // is_sub_system_for 466 467 pm_validate_resize, // validate_resize 468 pm_validate_resize_child, // validate_resize_child 469 pm_validate_move, // validate_move 470 pm_validate_move_child, // validate_move_child 471 NULL, // validate_set_name 472 NULL, // validate_set_content_name 473 pm_validate_set_type, // validate_set_type 474 NULL, // validate_set_parameters 475 NULL, // validate_set_content_parameters 476 pm_validate_initialize, // validate_initialize 477 pm_validate_create_child, // validate_create_child 478 pm_get_partitionable_spaces, // get_partitionable_spaces 479 pm_get_next_supported_type, // get_next_supported_type 480 get_type_for_content_type, // get_type_for_content_type 481 482 // shadow partition modification 483 pm_shadow_changed, // shadow_changed 484 485 // writing 486 NULL, // repair 487 pm_resize, // resize 488 pm_resize_child, // resize_child 489 pm_move, // move 490 pm_move_child, // move_child 491 NULL, // set_name 492 NULL, // set_content_name 493 pm_set_type, // set_type 494 NULL, // set_parameters 495 NULL, // set_content_parameters 496 pm_initialize, // initialize 497 pm_create_child, // create_child 498 pm_delete_child, // delete_child 499 #else 500 NULL 501 #endif // _BOOT_MODE 502 }; 503 504 505 #ifdef _BOOT_MODE 506 partition_module_info gIntelExtendedPartitionModule = 507 #else 508 static partition_module_info intel_extended_partition_module = 509 #endif 510 { 511 { 512 INTEL_EXTENDED_PARTITION_MODULE_NAME, 513 0, 514 ep_std_ops 515 }, 516 INTEL_EXTENDED_PARTITION_NAME, // pretty_name 517 518 // flags 519 0 520 // | B_DISK_SYSTEM_SUPPORTS_CHECKING 521 // | B_DISK_SYSTEM_SUPPORTS_REPAIRING 522 | B_DISK_SYSTEM_SUPPORTS_RESIZING 523 | B_DISK_SYSTEM_SUPPORTS_MOVING 524 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME 525 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS 526 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING 527 // | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 528 529 | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 530 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 531 // | B_DISK_SYSTEM_SUPPORTS_SETTING_NAME 532 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 533 // | B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS 534 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD 535 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD 536 // | B_DISK_SYSTEM_SUPPORTS_NAME 537 , 538 539 // scanning 540 ep_identify_partition, // identify_partition 541 ep_scan_partition, // scan_partition 542 ep_free_identify_partition_cookie, // free_identify_partition_cookie 543 ep_free_partition_cookie, // free_partition_cookie 544 ep_free_partition_content_cookie, // free_partition_content_cookie 545 546 #ifndef _BOOT_MODE 547 // querying 548 ep_get_supported_operations, // get_supported_operations 549 ep_get_supported_child_operations, // get_supported_child_operations 550 NULL, // supports_initializing_child 551 ep_is_sub_system_for, // is_sub_system_for 552 553 ep_validate_resize, // validate_resize 554 ep_validate_resize_child, // validate_resize_child 555 ep_validate_move, // validate_move 556 ep_validate_move_child, // validate_move_child 557 NULL, // validate_set_name 558 NULL, // validate_set_content_name 559 ep_validate_set_type, // validate_set_type 560 NULL, // validate_set_parameters 561 NULL, // validate_set_content_parameters 562 ep_validate_initialize, // validate_initialize 563 ep_validate_create_child, // validate_create_child 564 ep_get_partitionable_spaces, // get_partitionable_spaces 565 ep_get_next_supported_type, // get_next_supported_type 566 get_type_for_content_type, // get_type_for_content_type 567 568 // shadow partition modification 569 ep_shadow_changed, // shadow_changed 570 571 // writing 572 NULL, // repair 573 ep_resize, // resize 574 ep_resize_child, // resize_child 575 ep_move, // move 576 ep_move_child, // move_child 577 NULL, // set_name 578 NULL, // set_content_name 579 ep_set_type, // set_type 580 NULL, // set_parameters 581 NULL, // set_content_parameters 582 ep_initialize, // initialize 583 ep_create_child, // create_child 584 ep_delete_child, // delete_child 585 #else // _BOOT_MODE 586 NULL 587 #endif // _BOOT_MODE 588 }; 589 590 591 #ifndef _BOOT_MODE 592 extern "C" partition_module_info *modules[]; 593 _EXPORT partition_module_info *modules[] = 594 { 595 &intel_partition_map_module, 596 &intel_extended_partition_module, 597 NULL 598 }; 599 #endif 600