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