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