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