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