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