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