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 // We have a parent. That's a very unlikely setup. 163 if (hasChildren) 164 return 0.4; 165 166 // No children. Extremely unlikely, that this is desired. But if no one 167 // else claims the partition, we take it anyway. 168 return 0.1; 169 } 170 171 // pm_scan_partition 172 static status_t 173 pm_scan_partition(int fd, partition_data *partition, void *cookie) 174 { 175 // check parameters 176 if (fd < 0 || !partition || !cookie) 177 return B_ERROR; 178 179 TRACE(("intel: pm_scan_partition(%d, %ld: %lld, %lld, %ld)\n", fd, 180 partition->id, partition->offset, partition->size, 181 partition->block_size)); 182 183 PartitionMapCookie *map = (PartitionMapCookie*)cookie; 184 // fill in the partition_data structure 185 partition->status = B_PARTITION_VALID; 186 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 187 partition->content_size = partition->size; 188 // (no content_name and content_parameters) 189 // (content_type is set by the system) 190 partition->block_size = SECTOR_SIZE; 191 192 partition->content_cookie = map; 193 // children 194 status_t error = B_OK; 195 int32 index = 0; 196 for (int32 i = 0; i < 4; i++) { 197 PrimaryPartition *primary = map->PrimaryPartitionAt(i); 198 if (!primary->IsEmpty()) { 199 partition_data *child = create_child_partition(partition->id, 200 index, -1); 201 index++; 202 if (!child) { 203 // something went wrong 204 error = B_ERROR; 205 break; 206 } 207 208 child->offset = partition->offset + primary->Offset(); 209 child->size = primary->Size(); 210 child->block_size = SECTOR_SIZE; 211 // (no name) 212 char type[B_FILE_NAME_LENGTH]; 213 primary->GetTypeString(type); 214 child->type = strdup(type); 215 // parameters 216 char buffer[128]; 217 sprintf(buffer, "type = %u ; active = %d", primary->Type(), 218 primary->Active()); 219 child->parameters = strdup(buffer); 220 child->cookie = primary; 221 // check for allocation problems 222 if (!child->type || !child->parameters) { 223 error = B_NO_MEMORY; 224 break; 225 } 226 } 227 } 228 229 // keep map on success or cleanup on error 230 if (error == B_OK) { 231 atomic_add(&map->ref_count, 1); 232 } else { 233 partition->content_cookie = NULL; 234 for (int32 i = 0; i < partition->child_count; i++) { 235 if (partition_data *child = get_child_partition(partition->id, i)) 236 child->cookie = NULL; 237 } 238 } 239 240 return error; 241 } 242 243 // pm_free_identify_partition_cookie 244 static void 245 pm_free_identify_partition_cookie(partition_data */*partition*/, void *cookie) 246 { 247 if (cookie) { 248 PartitionMapCookie *map = (PartitionMapCookie*)cookie; 249 if (atomic_add(&map->ref_count, -1) == 1) 250 delete map; 251 } 252 } 253 254 // pm_free_partition_cookie 255 static void 256 pm_free_partition_cookie(partition_data *partition) 257 { 258 // called for the primary partitions: the PrimaryPartition is allocated 259 // by the partition containing the partition map 260 if (partition) 261 partition->cookie = NULL; 262 } 263 264 // pm_free_partition_content_cookie 265 static void 266 pm_free_partition_content_cookie(partition_data *partition) 267 { 268 if (partition && partition->content_cookie) { 269 pm_free_identify_partition_cookie(partition, partition->content_cookie); 270 partition->content_cookie = NULL; 271 } 272 } 273 274 // #pragma mark - Intel Extended Partition Module 275 276 277 // ep_std_ops 278 static status_t 279 ep_std_ops(int32 op, ...) 280 { 281 TRACE(("intel: ep_std_ops(0x%lx)\n", op)); 282 switch(op) { 283 case B_MODULE_INIT: 284 case B_MODULE_UNINIT: 285 return B_OK; 286 } 287 return B_ERROR; 288 } 289 290 // ep_identify_partition 291 static float 292 ep_identify_partition(int fd, partition_data *partition, void **cookie) 293 { 294 // check parameters 295 if (fd < 0 || !partition || !cookie || !partition->cookie) 296 return -1; 297 298 TRACE(("intel: ep_identify_partition(%d, %lld, %lld, %ld)\n", fd, 299 partition->offset, partition->size, partition->block_size)); 300 301 // our parent must be a intel partition map partition and we must have 302 // extended partition type 303 if (!partition->type 304 || strcmp(partition->type, kPartitionTypeIntelExtended)) { 305 return -1; 306 } 307 partition_data *parent = get_parent_partition(partition->id); 308 if (!parent || !parent->content_type 309 || strcmp(parent->content_type, kPartitionTypeIntel)) { 310 return -1; 311 } 312 313 // things seem to be in order 314 return 0.95; 315 } 316 317 // ep_scan_partition 318 static status_t 319 ep_scan_partition(int fd, partition_data *partition, void *cookie) 320 { 321 // check parameters 322 if (fd < 0 || !partition || !partition->cookie) 323 return B_ERROR; 324 325 TRACE(("intel: ep_scan_partition(%d, %lld, %lld, %ld)\n", fd, 326 partition->offset, partition->size, partition->block_size)); 327 328 partition_data *parent = get_parent_partition(partition->id); 329 if (!parent) 330 return B_ERROR; 331 PrimaryPartition *primary = (PrimaryPartition*)partition->cookie; 332 // fill in the partition_data structure 333 partition->status = B_PARTITION_VALID; 334 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM; 335 partition->content_size = partition->size; 336 // (no content_name and content_parameters) 337 // (content_type is set by the system) 338 partition->block_size = SECTOR_SIZE; 339 340 partition->content_cookie = primary; 341 // children 342 status_t error = B_OK; 343 int32 index = 0; 344 for (int32 i = 0; i < primary->CountLogicalPartitions(); i++) { 345 LogicalPartition *logical = primary->LogicalPartitionAt(i); 346 partition_data *child = create_child_partition(partition->id, 347 index, -1); 348 index++; 349 if (!child) { 350 // something went wrong 351 TRACE(("intel: ep_scan_partition(): failed to create child " 352 "partition\n")); 353 error = B_ERROR; 354 break; 355 } 356 child->offset = parent->offset + logical->Offset(); 357 child->size = logical->Size(); 358 child->block_size = SECTOR_SIZE; 359 // (no name) 360 char type[B_FILE_NAME_LENGTH]; 361 logical->GetTypeString(type); 362 child->type = strdup(type); 363 364 // parameters 365 char buffer[128]; 366 sprintf(buffer, "type = %u ; active = %d", logical->Type(), 367 logical->Active()); 368 child->parameters = strdup(buffer); 369 child->cookie = logical; 370 // check for allocation problems 371 if (!child->type || !child->parameters) { 372 TRACE(("intel: ep_scan_partition(): failed to allocation type " 373 "or parameters\n")); 374 error = B_NO_MEMORY; 375 break; 376 } 377 } 378 // cleanup on error 379 if (error != B_OK) { 380 partition->content_cookie = NULL; 381 for (int32 i = 0; i < partition->child_count; i++) { 382 if (partition_data *child = get_child_partition(partition->id, i)) 383 child->cookie = NULL; 384 } 385 } 386 return error; 387 } 388 389 // ep_free_identify_partition_cookie 390 static void 391 ep_free_identify_partition_cookie(partition_data *partition, void *cookie) 392 { 393 // nothing to do 394 } 395 396 // ep_free_partition_cookie 397 static void 398 ep_free_partition_cookie(partition_data *partition) 399 { 400 // the logical partition's cookie belongs to the partition map partition 401 if (partition) 402 partition->cookie = NULL; 403 } 404 405 // ep_free_partition_content_cookie 406 static void 407 ep_free_partition_content_cookie(partition_data *partition) 408 { 409 // the extended partition's cookie belongs to the partition map partition 410 if (partition) 411 partition->content_cookie = NULL; 412 } 413 414 415 // #pragma mark - modules 416 417 418 #ifdef _BOOT_MODE 419 partition_module_info gIntelPartitionMapModule = 420 #else 421 static partition_module_info intel_partition_map_module = 422 #endif 423 { 424 { 425 INTEL_PARTITION_MODULE_NAME, 426 0, 427 pm_std_ops 428 }, 429 "intel", // short_name 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", // short_name 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