xref: /haiku/src/add-ons/kernel/partitioning_systems/intel/intel.cpp (revision 9274ca847ba2f4f5755a00d5be82133e1b866c66)
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