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 map->ref_count = 1; 135 136 // read the partition structure 137 PartitionMapParser parser(fd, 0, partition->size); 138 status_t error = parser.Parse(NULL, map); 139 if (error != B_OK) { 140 // cleanup, if not detected 141 delete map; 142 return -1; 143 } 144 145 *cookie = map; 146 147 // Depending on whether we actually have recognized child partitions and 148 // whether we are installed directly on a device (the by far most common 149 // setup), we determine the priority. 150 bool hasChildren = (map->CountNonEmptyPartitions() > 0); 151 bool hasParent = (get_parent_partition(partition->id) != NULL); 152 153 if (!hasParent) { 154 if (hasChildren) { 155 // This value overrides BFS. 156 return 0.81; 157 } 158 159 // No children -- might be a freshly initialized disk. But it could 160 // also be an image file. So we give BFS a chance to override us. 161 return 0.5; 162 } 163 164 // We have a parent. That's a very unlikely setup. 165 if (hasChildren) 166 return 0.4; 167 168 // No children. Extremely unlikely, that this is a desired. But if no one 169 // else claims the partition, we take it anyway. 170 return 0.1; 171 } 172 173 // pm_scan_partition 174 static status_t 175 pm_scan_partition(int fd, partition_data *partition, void *cookie) 176 { 177 // check parameters 178 if (fd < 0 || !partition || !cookie) 179 return B_ERROR; 180 181 TRACE(("intel: pm_scan_partition(%d, %ld: %lld, %lld, %ld)\n", fd, 182 partition->id, partition->offset, partition->size, 183 partition->block_size)); 184 185 PartitionMapCookie *map = (PartitionMapCookie*)cookie; 186 // fill in the partition_data structure 187 partition->status = B_PARTITION_VALID; 188 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 189 partition->content_size = partition->size; 190 // (no content_name and content_parameters) 191 // (content_type is set by the system) 192 partition->block_size = SECTOR_SIZE; 193 194 partition->content_cookie = map; 195 // children 196 status_t error = B_OK; 197 int32 index = 0; 198 for (int32 i = 0; i < 4; i++) { 199 PrimaryPartition *primary = map->PrimaryPartitionAt(i); 200 if (!primary->IsEmpty()) { 201 partition_data *child = create_child_partition(partition->id, 202 index, -1); 203 index++; 204 if (!child) { 205 // something went wrong 206 error = B_ERROR; 207 break; 208 } 209 210 child->offset = partition->offset + primary->Offset(); 211 child->size = primary->Size(); 212 child->block_size = SECTOR_SIZE; 213 // (no name) 214 char type[B_FILE_NAME_LENGTH]; 215 primary->GetTypeString(type); 216 child->type = strdup(type); 217 // parameters 218 char buffer[128]; 219 sprintf(buffer, "type = %u ; active = %d", primary->Type(), 220 primary->Active()); 221 child->parameters = strdup(buffer); 222 child->cookie = primary; 223 // check for allocation problems 224 if (!child->type || !child->parameters) { 225 error = B_NO_MEMORY; 226 break; 227 } 228 } 229 } 230 231 // keep map on success or cleanup on error 232 if (error == B_OK) { 233 atomic_add(&map->ref_count, 1); 234 } else { 235 partition->content_cookie = NULL; 236 for (int32 i = 0; i < partition->child_count; i++) { 237 if (partition_data *child = get_child_partition(partition->id, i)) 238 child->cookie = NULL; 239 } 240 } 241 242 return error; 243 } 244 245 // pm_free_identify_partition_cookie 246 static void 247 pm_free_identify_partition_cookie(partition_data */*partition*/, void *cookie) 248 { 249 if (cookie) { 250 PartitionMapCookie *map = (PartitionMapCookie*)cookie; 251 if (atomic_add(&map->ref_count, -1) == 1) 252 delete map; 253 } 254 } 255 256 // pm_free_partition_cookie 257 static void 258 pm_free_partition_cookie(partition_data *partition) 259 { 260 // called for the primary partitions: the PrimaryPartition is allocated 261 // by the partition containing the partition map 262 if (partition) 263 partition->cookie = NULL; 264 } 265 266 // pm_free_partition_content_cookie 267 static void 268 pm_free_partition_content_cookie(partition_data *partition) 269 { 270 if (partition && partition->content_cookie) { 271 pm_free_identify_partition_cookie(partition, partition->content_cookie); 272 partition->content_cookie = NULL; 273 } 274 } 275 276 // #pragma mark - Intel Extended Partition Module 277 278 279 // ep_std_ops 280 static status_t 281 ep_std_ops(int32 op, ...) 282 { 283 TRACE(("intel: ep_std_ops(0x%lx)\n", op)); 284 switch(op) { 285 case B_MODULE_INIT: 286 case B_MODULE_UNINIT: 287 return B_OK; 288 } 289 return B_ERROR; 290 } 291 292 // ep_identify_partition 293 static float 294 ep_identify_partition(int fd, partition_data *partition, void **cookie) 295 { 296 // check parameters 297 if (fd < 0 || !partition || !cookie || !partition->cookie) 298 return -1; 299 300 TRACE(("intel: ep_identify_partition(%d, %lld, %lld, %ld)\n", fd, 301 partition->offset, partition->size, partition->block_size)); 302 303 // our parent must be a intel partition map partition and we must have 304 // extended partition type 305 if (!partition->type 306 || strcmp(partition->type, kPartitionTypeIntelExtended)) { 307 return -1; 308 } 309 partition_data *parent = get_parent_partition(partition->id); 310 if (!parent || !parent->content_type 311 || strcmp(parent->content_type, kPartitionTypeIntel)) { 312 return -1; 313 } 314 315 // things seem to be in order 316 return 0.95; 317 } 318 319 // ep_scan_partition 320 static status_t 321 ep_scan_partition(int fd, partition_data *partition, void *cookie) 322 { 323 // check parameters 324 if (fd < 0 || !partition || !partition->cookie) 325 return B_ERROR; 326 327 TRACE(("intel: ep_scan_partition(%d, %lld, %lld, %ld)\n", fd, 328 partition->offset, partition->size, partition->block_size)); 329 330 partition_data *parent = get_parent_partition(partition->id); 331 if (!parent) 332 return B_ERROR; 333 PrimaryPartition *primary = (PrimaryPartition*)partition->cookie; 334 // fill in the partition_data structure 335 partition->status = B_PARTITION_VALID; 336 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 337 partition->content_size = partition->size; 338 // (no content_name and content_parameters) 339 // (content_type is set by the system) 340 partition->block_size = SECTOR_SIZE; 341 342 partition->content_cookie = primary; 343 // children 344 status_t error = B_OK; 345 int32 index = 0; 346 for (int32 i = 0; i < primary->CountLogicalPartitions(); i++) { 347 LogicalPartition *logical = primary->LogicalPartitionAt(i); 348 partition_data *child = create_child_partition(partition->id, 349 index, -1); 350 index++; 351 if (!child) { 352 // something went wrong 353 TRACE(("intel: ep_scan_partition(): failed to create child " 354 "partition\n")); 355 error = B_ERROR; 356 break; 357 } 358 child->offset = parent->offset + logical->Offset(); 359 child->size = logical->Size(); 360 child->block_size = SECTOR_SIZE; 361 // (no name) 362 char type[B_FILE_NAME_LENGTH]; 363 logical->GetTypeString(type); 364 child->type = strdup(type); 365 366 // parameters 367 char buffer[128]; 368 sprintf(buffer, "type = %u ; active = %d", logical->Type(), 369 logical->Active()); 370 child->parameters = strdup(buffer); 371 child->cookie = logical; 372 // check for allocation problems 373 if (!child->type || !child->parameters) { 374 TRACE(("intel: ep_scan_partition(): failed to allocation type " 375 "or parameters\n")); 376 error = B_NO_MEMORY; 377 break; 378 } 379 } 380 // cleanup on error 381 if (error != B_OK) { 382 partition->content_cookie = NULL; 383 for (int32 i = 0; i < partition->child_count; i++) { 384 if (partition_data *child = get_child_partition(partition->id, i)) 385 child->cookie = NULL; 386 } 387 } 388 return error; 389 } 390 391 // ep_free_identify_partition_cookie 392 static void 393 ep_free_identify_partition_cookie(partition_data *partition, void *cookie) 394 { 395 // nothing to do 396 } 397 398 // ep_free_partition_cookie 399 static void 400 ep_free_partition_cookie(partition_data *partition) 401 { 402 // the logical partition's cookie belongs to the partition map partition 403 if (partition) 404 partition->cookie = NULL; 405 } 406 407 // ep_free_partition_content_cookie 408 static void 409 ep_free_partition_content_cookie(partition_data *partition) 410 { 411 // the extended partition's cookie belongs to the partition map partition 412 if (partition) 413 partition->content_cookie = NULL; 414 } 415 416 417 // #pragma mark - modules 418 419 420 #ifdef _BOOT_MODE 421 partition_module_info gIntelPartitionMapModule = 422 #else 423 static partition_module_info intel_partition_map_module = 424 #endif 425 { 426 { 427 INTEL_PARTITION_MODULE_NAME, 428 0, 429 pm_std_ops 430 }, 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_PARTITION_NAME, // pretty_name 518 519 // flags 520 0 521 // | B_DISK_SYSTEM_SUPPORTS_CHECKING 522 // | B_DISK_SYSTEM_SUPPORTS_REPAIRING 523 | B_DISK_SYSTEM_SUPPORTS_RESIZING 524 | B_DISK_SYSTEM_SUPPORTS_MOVING 525 // | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_NAME 526 | B_DISK_SYSTEM_SUPPORTS_SETTING_CONTENT_PARAMETERS 527 | B_DISK_SYSTEM_SUPPORTS_INITIALIZING 528 // | B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME 529 530 | B_DISK_SYSTEM_SUPPORTS_RESIZING_CHILD 531 | B_DISK_SYSTEM_SUPPORTS_MOVING_CHILD 532 // | B_DISK_SYSTEM_SUPPORTS_SETTING_NAME 533 | B_DISK_SYSTEM_SUPPORTS_SETTING_TYPE 534 // | B_DISK_SYSTEM_SUPPORTS_SETTING_PARAMETERS 535 | B_DISK_SYSTEM_SUPPORTS_CREATING_CHILD 536 | B_DISK_SYSTEM_SUPPORTS_DELETING_CHILD 537 // | B_DISK_SYSTEM_SUPPORTS_NAME 538 , 539 540 // scanning 541 ep_identify_partition, // identify_partition 542 ep_scan_partition, // scan_partition 543 ep_free_identify_partition_cookie, // free_identify_partition_cookie 544 ep_free_partition_cookie, // free_partition_cookie 545 ep_free_partition_content_cookie, // free_partition_content_cookie 546 547 #ifndef _BOOT_MODE 548 // querying 549 ep_get_supported_operations, // get_supported_operations 550 ep_get_supported_child_operations, // get_supported_child_operations 551 NULL, // supports_initializing_child 552 ep_is_sub_system_for, // is_sub_system_for 553 554 ep_validate_resize, // validate_resize 555 ep_validate_resize_child, // validate_resize_child 556 ep_validate_move, // validate_move 557 ep_validate_move_child, // validate_move_child 558 NULL, // validate_set_name 559 NULL, // validate_set_content_name 560 ep_validate_set_type, // validate_set_type 561 NULL, // validate_set_parameters 562 NULL, // validate_set_content_parameters 563 ep_validate_initialize, // validate_initialize 564 ep_validate_create_child, // validate_create_child 565 ep_get_partitionable_spaces, // get_partitionable_spaces 566 ep_get_next_supported_type, // get_next_supported_type 567 get_type_for_content_type, // get_type_for_content_type 568 569 // shadow partition modification 570 ep_shadow_changed, // shadow_changed 571 572 // writing 573 NULL, // repair 574 ep_resize, // resize 575 ep_resize_child, // resize_child 576 ep_move, // move 577 ep_move_child, // move_child 578 NULL, // set_name 579 NULL, // set_content_name 580 ep_set_type, // set_type 581 NULL, // set_parameters 582 NULL, // set_content_parameters 583 ep_initialize, // initialize 584 ep_create_child, // create_child 585 ep_delete_child, // delete_child 586 #else // _BOOT_MODE 587 NULL 588 #endif // _BOOT_MODE 589 }; 590 591 592 #ifndef _BOOT_MODE 593 extern "C" partition_module_info *modules[]; 594 _EXPORT partition_module_info *modules[] = 595 { 596 &intel_partition_map_module, 597 &intel_extended_partition_module, 598 NULL 599 }; 600 #endif 601