1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** FileX Component */
16 /** */
17 /** Application Utility */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22 #define FX_SOURCE_CODE
23
24
25 /* Include necessary system files. */
26
27 #include "fx_api.h"
28 #include "fx_utility.h"
29
30
31 /* Define internal data structures. */
32
33 typedef struct FX_MEDIA_PARTITION_STRUCT
34 {
35 ULONG fx_media_part_start;
36 ULONG fx_media_part_size;
37 } FX_MEDIA_PARTITION;
38
39 /* Define internal partition constants. */
40
41 #ifndef FX_MAX_PARTITION_COUNT
42 #define FX_MAX_PARTITION_COUNT 16
43 #endif /* FX_MAX_PARTITION_COUNT */
44
45 #define FX_PARTITION_TABLE_OFFSET 446
46 #define FX_PARTITION_ENTRY_SIZE 16
47 #define FX_PARTITION_TYPE_OFFSET 4
48 #define FX_PARTITION_LBA_OFFSET 8
49 #define FX_PARTITION_SECTORS_OFFSET 12
50
51 #define FX_PARTITION_TYPE_FREE 0x00
52 #define FX_PARTITION_TYPE_EXTENDED 0x05
53 #define FX_PARTITION_TYPE_EXTENDED_LBA 0x0F
54
55
56 /* Define function prototypes for the partition table parsing application
57 utility. */
58
59 UINT _fx_partition_offset_calculate(void *partition_sector, UINT partition,
60 ULONG *partition_start, ULONG *partition_size);
61 UINT _fx_utility_partition_get(FX_MEDIA_PARTITION *partition_table,
62 UINT *count, ULONG sector, UCHAR *sector_buffer);
63 UINT _fx_partition_offset_calculate_extended(FX_MEDIA *media_ptr, void *partition_sector, UINT partition,
64 ULONG *partition_start, ULONG *partition_size);
65
66 /**************************************************************************/
67 /* */
68 /* FUNCTION RELEASE */
69 /* */
70 /* _fx_partition_offset_calculate PORTABLE C */
71 /* 6.1.6 */
72 /* AUTHOR */
73 /* */
74 /* William E. Lamie, Microsoft Corporation */
75 /* */
76 /* DESCRIPTION */
77 /* */
78 /* This function calculates the sector offset to the specified */
79 /* partition. The buffer containing the partition table is also */
80 /* supplied to this function. If the buffer supplied is a boot */
81 /* record (which could be the case in non-partition systems), this */
82 /* function returns an offset of zero, the total sectors, and a */
83 /* successful status indicating that the buffer supplied is the boot */
84 /* record. Otherwise, if a partition is found, this function returns */
85 /* the sector offset to its boot record along with a successful */
86 /* status. If the specified partition is not found or the buffer is */
87 /* not a partition table or boot record, this function returns an */
88 /* error. */
89 /* */
90 /* Note: Empty partitions have a FX_SUCCESS return code, however their */
91 /* starting sector is FX_NULL and the size returned is 0. */
92 /* */
93 /* INPUT */
94 /* */
95 /* partition_sector Pointer to buffer containing */
96 /* either the partition table */
97 /* or the boot sector */
98 /* partition Desired partition */
99 /* partition_start Return partition start */
100 /* partition_size Return partition size */
101 /* */
102 /* OUTPUT */
103 /* */
104 /* return status */
105 /* */
106 /* CALLS */
107 /* */
108 /* _fx_utility_partition_get Actual partition parsing */
109 /* routine */
110 /* */
111 /* CALLED BY */
112 /* */
113 /* Application Driver */
114 /* */
115 /* RELEASE HISTORY */
116 /* */
117 /* DATE NAME DESCRIPTION */
118 /* */
119 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
120 /* 09-30-2020 William E. Lamie Modified comment(s), */
121 /* resulting in version 6.1 */
122 /* 04-02-2021 William E. Lamie Modified comment(s), */
123 /* ignored signature check for */
124 /* no partition situation, */
125 /* resulting in version 6.1.6 */
126 /* */
127 /**************************************************************************/
_fx_partition_offset_calculate(void * partition_sector,UINT partition,ULONG * partition_start,ULONG * partition_size)128 UINT _fx_partition_offset_calculate(void *partition_sector, UINT partition,
129 ULONG *partition_start, ULONG *partition_size)
130 {
131
132 FX_MEDIA_PARTITION partition_table[4];
133 UINT count;
134 ULONG64 total_sectors;
135 UCHAR *partition_sector_ptr;
136
137
138 /* Setup working pointer and initialize count. */
139 partition_sector_ptr = partition_sector;
140 count = 0;
141
142 /* Check for a real boot sector instead of a partition table. */
143 if ((partition_sector_ptr[0] == 0xe9) || ((partition_sector_ptr[0] == 0xeb) && (partition_sector_ptr[2] == 0x90)))
144 {
145
146 /* Yes, a real boot sector could be present. */
147
148 /* See if there are good values for sectors per FAT. */
149 if (partition_sector_ptr[0x16] || partition_sector_ptr[0x17] || partition_sector_ptr[0x24] || partition_sector_ptr[0x25] || partition_sector_ptr[0x26] || partition_sector_ptr[0x27])
150 {
151
152 /* There are values for sectors per FAT. */
153
154 /* Determine if there is a total sector count. */
155 total_sectors = 0;
156
157 if (partition_sector_ptr[0x13] || partition_sector_ptr[0x14])
158 {
159
160 /* Calculate the total sectors, FAT12/16. */
161 total_sectors = (((ULONG) partition_sector_ptr[0x14]) << 8) | ((ULONG) partition_sector_ptr[0x13]);
162 }
163 else if (partition_sector_ptr[0x20] || partition_sector_ptr[0x21] || partition_sector_ptr[0x22] || partition_sector_ptr[0x23])
164 {
165
166 /* Calculate the total sectors, FAT32. */
167 total_sectors = (((ULONG) partition_sector_ptr[0x23]) << 24) |
168 (((ULONG) partition_sector_ptr[0x22]) << 16) |
169 (((ULONG) partition_sector_ptr[0x21]) << 8) |
170 ((ULONG) partition_sector_ptr[0x20]);
171 }
172
173 /* Determine if there is a total sector count. */
174 if (total_sectors)
175 {
176
177 if (partition_start != FX_NULL)
178 {
179 /* Return an offset of 0, size of boot record, and a successful status. */
180 *partition_start = 0;
181 }
182
183 /* Determine if the total sectors is required. */
184 if (partition_size != FX_NULL)
185 {
186
187 /* Return the total sectors. */
188 *partition_size = (ULONG)(total_sectors & 0xFFFFFFFF);
189 }
190
191 /* Return success! */
192 return(FX_SUCCESS);
193 }
194 }
195 }
196
197 /* Check signature to make sure the buffer is valid. */
198 if ((partition_sector_ptr[510] != 0x55) || (partition_sector_ptr[511] != 0xAA))
199 {
200
201 /* Invalid, return an error. */
202 return(FX_NOT_FOUND);
203 }
204
205 /* Not bootable, look for specific partition. */
206 _fx_utility_partition_get(partition_table, &count, 0, partition_sector_ptr);
207
208 /* Determine if return value is valid. */
209 if (partition >= count)
210 {
211
212 /* No, return an error. */
213 return(FX_NOT_FOUND);
214 }
215
216 /* Return the partition starting sector, if non-NULL. */
217 if (partition_start != FX_NULL)
218 {
219 *partition_start = partition_table[partition].fx_media_part_start;
220 }
221
222 /* Return the partition size, if non-NULL. */
223 if (partition_size != FX_NULL)
224 {
225 *partition_size = partition_table[partition].fx_media_part_size;
226 }
227
228 /* Return successful completion. */
229 return(FX_SUCCESS);
230 }
231
232
233 /**************************************************************************/
234 /* */
235 /* FUNCTION RELEASE */
236 /* */
237 /* _fx_utility_partition_get PORTABLE C */
238 /* 6.1.6 */
239 /* AUTHOR */
240 /* */
241 /* William E. Lamie, Microsoft Corporation */
242 /* */
243 /* DESCRIPTION */
244 /* */
245 /* This function parses the partition sector and completes the */
246 /* supplied partition entry structure. */
247 /* */
248 /* INPUT */
249 /* */
250 /* partition_table Pointer to partition table */
251 /* count Number of partitions found */
252 /* sector Base sector */
253 /* sector_buffer Buffer containing partition */
254 /* table */
255 /* */
256 /* OUTPUT */
257 /* */
258 /* return status */
259 /* */
260 /* CALLS */
261 /* */
262 /* None */
263 /* */
264 /* CALLED BY */
265 /* */
266 /* _fx_partition_offset_calculate Calculate partition offset */
267 /* */
268 /* RELEASE HISTORY */
269 /* */
270 /* DATE NAME DESCRIPTION */
271 /* */
272 /* 05-19-2020 William E. Lamie Initial Version 6.0 */
273 /* 09-30-2020 William E. Lamie Modified comment(s), */
274 /* resulting in version 6.1 */
275 /* 04-02-2021 William E. Lamie Modified comment(s), */
276 /* resulting in version 6.1.6 */
277 /* */
278 /**************************************************************************/
_fx_utility_partition_get(FX_MEDIA_PARTITION * partition_table,UINT * count,ULONG sector,UCHAR * sector_buffer)279 UINT _fx_utility_partition_get(FX_MEDIA_PARTITION *partition_table,
280 UINT *count, ULONG sector, UCHAR *sector_buffer)
281 {
282
283 UINT i;
284 ULONG base_sector, value;
285
286 /* This parameter has not been supported yet. */
287 FX_PARAMETER_NOT_USED(sector);
288
289 /* Initialize base sector. */
290 base_sector = 0;
291
292 for(i = 446; i <= 494; i+=16)
293 {
294 if (sector_buffer[i + 4] == 0) /* no partition entry here */
295 {
296
297 partition_table[*count].fx_media_part_start = 0;
298 partition_table[*count].fx_media_part_size = 0;
299 }
300 else
301 {
302
303 value = (ULONG) sector_buffer[i + 8]; /* little endian start value */
304 value = (((ULONG) sector_buffer[i + 9]) << 8) | value;
305 value = (((ULONG) sector_buffer[i + 10]) << 16) | value;
306 value = (((ULONG) sector_buffer[i + 11]) << 24) | value;
307 partition_table[*count].fx_media_part_start = value + base_sector;
308
309 value = (ULONG) sector_buffer[i + 12]; /* little endian size value */
310 value = (((ULONG) sector_buffer[i + 13]) << 8) | value;
311 value = (((ULONG) sector_buffer[i + 14]) << 16) | value;
312 value = (((ULONG) sector_buffer[i + 15]) << 24) | value;
313 partition_table[*count].fx_media_part_size = value;
314 }
315
316 (*count)++;
317 }
318
319 /* Return success. */
320 return(FX_SUCCESS);
321 }
322
323 /**************************************************************************/
324 /* */
325 /* FUNCTION RELEASE */
326 /* */
327 /* _fx_partition_offset_calculate_extended PORTABLE C */
328 /* 6.2.0 */
329 /* AUTHOR */
330 /* */
331 /* Xiuwen Cai, Microsoft Corporation */
332 /* */
333 /* DESCRIPTION */
334 /* */
335 /* This function calculates the sector offset to the specified */
336 /* partition. The buffer containing the partition table is also */
337 /* supplied to this function. If the buffer supplied is a boot */
338 /* record (which could be the case in non-partition systems), this */
339 /* function returns an offset of zero, the total sectors, and a */
340 /* successful status indicating that the buffer supplied is the boot */
341 /* record. Otherwise, if a partition is found, this function returns */
342 /* the sector offset to its boot record along with a successful */
343 /* status. If the specified partition is not found or the buffer is */
344 /* not a partition table or boot record, this function returns an */
345 /* error. */
346 /* */
347 /* Note: Empty partitions have a FX_NOT_FOUND return code. */
348 /* Use partition index 0 to 3 for primary partition and index 4 to */
349 /* FX_MAX_PARTITION_COUNT for extended partition. */
350 /* */
351 /* INPUT */
352 /* */
353 /* media_ptr Media control block pointer */
354 /* partition_sector Pointer to buffer containing */
355 /* either the partition table */
356 /* or the boot sector */
357 /* partition Desired partition */
358 /* partition_start Return partition start */
359 /* partition_size Return partition size */
360 /* */
361 /* OUTPUT */
362 /* */
363 /* return status */
364 /* */
365 /* CALLS */
366 /* */
367 /* _fx_utility_16_unsigned_read Read a USHORT from memory */
368 /* _fx_utility_32_unsigned_read Read a ULONG from memory */
369 /* _fx_utility_64_unsigned_read Read a ULONG64 from memory */
370 /* Media driver */
371 /* */
372 /* CALLED BY */
373 /* */
374 /* Application Driver */
375 /* */
376 /* RELEASE HISTORY */
377 /* */
378 /* DATE NAME DESCRIPTION */
379 /* */
380 /* 10-31-2022 Xiuwen Cai Initial Version 6.2.0 */
381 /* */
382 /**************************************************************************/
_fx_partition_offset_calculate_extended(FX_MEDIA * media_ptr,void * partition_sector,UINT partition,ULONG * partition_start,ULONG * partition_size)383 UINT _fx_partition_offset_calculate_extended(FX_MEDIA *media_ptr, void *partition_sector, UINT partition,
384 ULONG *partition_start, ULONG *partition_size)
385 {
386
387 ULONG64 total_sectors;
388 UCHAR *partition_sector_ptr;
389 UCHAR partition_type;
390 UINT i;
391 ULONG base_sector;
392 ULONG base_sector_extended;
393
394
395 /* Setup working pointer. */
396 partition_sector_ptr = partition_sector;
397
398 /* Check for a real boot sector instead of a partition table. */
399 if ((partition_sector_ptr[0] == 0xe9) || ((partition_sector_ptr[0] == 0xeb) && (partition_sector_ptr[2] == 0x90)))
400 {
401
402 /* Yes, a real boot sector could be present. */
403
404 /* See if there are good values for sectors per FAT. */
405 if (partition_sector_ptr[0x16] || partition_sector_ptr[0x17] || partition_sector_ptr[0x24] || partition_sector_ptr[0x25] || partition_sector_ptr[0x26] || partition_sector_ptr[0x27])
406 {
407
408 /* There are values for sectors per FAT. */
409
410 /* Get the total sectors, FAT12/16. */
411 total_sectors = _fx_utility_16_unsigned_read(&partition_sector_ptr[FX_SECTORS]);
412
413 if (total_sectors == 0)
414 {
415
416 /* Get the total sectors, FAT32. */
417 total_sectors = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_HUGE_SECTORS]);
418 }
419
420 /* Determine if there is a total sector count. */
421 if (total_sectors)
422 {
423
424 if (partition_start != FX_NULL)
425 {
426 /* Return an offset of 0, size of boot record, and a successful status. */
427 *partition_start = 0;
428 }
429
430 /* Determine if the total sectors is required. */
431 if (partition_size != FX_NULL)
432 {
433
434 /* Return the total sectors. */
435 *partition_size = (ULONG)(total_sectors & 0xFFFFFFFF);
436 }
437
438 /* Return success! */
439 return(FX_SUCCESS);
440 }
441 }
442 }
443
444 /* Check signature to make sure the buffer is valid. */
445 if ((partition_sector_ptr[510] != FX_SIG_BYTE_1) || (partition_sector_ptr[511] != FX_SIG_BYTE_2))
446 {
447
448 /* Invalid, return an error. */
449 return(FX_NOT_FOUND);
450 }
451
452 /* Not bootable, look for specific partition. */
453
454 /* Check if primary partitions are addressed. */
455 if (partition < 4)
456 {
457
458 /* Get partition type. */
459 partition_type = partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + partition * FX_PARTITION_ENTRY_SIZE + FX_PARTITION_TYPE_OFFSET];
460
461 /* Check if there is a vaild partition. */
462 if (partition_type != FX_PARTITION_TYPE_FREE)
463 {
464
465 /* Return the partition starting sector, if non-NULL. */
466 if (partition_start != FX_NULL)
467 {
468 *partition_start = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + partition * FX_PARTITION_ENTRY_SIZE + FX_PARTITION_LBA_OFFSET]);
469 }
470
471 /* Return the partition size, if non-NULL. */
472 if (partition_size != FX_NULL)
473 {
474 *partition_size = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + partition * FX_PARTITION_ENTRY_SIZE + FX_PARTITION_SECTORS_OFFSET]);
475 }
476
477 /* Return success! */
478 return(FX_SUCCESS);
479 }
480 else
481 {
482
483 /* Not partition here. */
484 return(FX_NOT_FOUND);
485 }
486 }
487
488 /* Check for invalid parameter. */
489 if (partition > FX_MAX_PARTITION_COUNT)
490 {
491
492 /* Return error. */
493 return(FX_NOT_FOUND);
494 }
495
496 base_sector = 0;
497
498 /* Loop to find the extended partition table. */
499 for(i = FX_PARTITION_TABLE_OFFSET; i <= FX_PARTITION_TABLE_OFFSET + 3 * FX_PARTITION_ENTRY_SIZE; i += FX_PARTITION_ENTRY_SIZE)
500 {
501
502 /* Get partition type. */
503 partition_type = partition_sector_ptr[i + FX_PARTITION_TYPE_OFFSET];
504 if (partition_type == FX_PARTITION_TYPE_EXTENDED || partition_type == FX_PARTITION_TYPE_EXTENDED_LBA)
505 {
506 base_sector = _fx_utility_32_unsigned_read(&partition_sector_ptr[i + FX_PARTITION_LBA_OFFSET]);
507 break;
508 }
509 }
510
511 if (base_sector == 0)
512 {
513
514 /* No extended partition. */
515 return(FX_NOT_FOUND);
516 }
517
518 base_sector_extended = base_sector;
519
520 for (i = 4; i <= partition; i++)
521 {
522
523 /* Read the partition sector from the device. Build the read sector
524 command. */
525 media_ptr -> fx_media_driver_request = FX_DRIVER_READ;
526 media_ptr -> fx_media_driver_status = FX_IO_ERROR;
527 media_ptr -> fx_media_driver_buffer = partition_sector_ptr;
528 media_ptr -> fx_media_driver_logical_sector = base_sector;
529 media_ptr -> fx_media_driver_sectors = 1;
530 media_ptr -> fx_media_driver_sector_type = FX_UNKNOWN_SECTOR;
531 media_ptr -> fx_media_hidden_sectors = 0;
532
533 /* Invoke the driver to read the sector. */
534 (media_ptr -> fx_media_driver_entry) (media_ptr);
535
536 /* Determine if the sector was read correctly. */
537 if (media_ptr -> fx_media_driver_status != FX_SUCCESS)
538 {
539
540 /* Return error. */
541 return(FX_IO_ERROR);
542 }
543
544 /* Check signature to make sure the sector is valid. */
545 if ((partition_sector_ptr[510] != FX_SIG_BYTE_1) || (partition_sector_ptr[511] != FX_SIG_BYTE_2))
546 {
547
548 /* Invalid, return an error. */
549 return(FX_NOT_FOUND);
550 }
551
552 /* Determine if this is the desired partition. */
553 if (i == partition)
554 {
555
556 /* Get partition type. */
557 partition_type = partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_TYPE_OFFSET];
558 if (partition_type != FX_PARTITION_TYPE_FREE)
559 {
560
561 /* Return the partition starting sector, if non-NULL. */
562 if (partition_start != FX_NULL)
563 {
564 *partition_start = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_LBA_OFFSET]) + base_sector;
565 }
566
567 /* Return the partition size, if non-NULL. */
568 if (partition_size != FX_NULL)
569 {
570 *partition_size = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_SECTORS_OFFSET]);
571 }
572
573 /* Return success! */
574 return(FX_SUCCESS);
575 }
576 else
577 {
578 /* Not partition here. */
579 return(FX_NOT_FOUND);
580 }
581 }
582 else
583 {
584
585 /* Get partition type. */
586 partition_type = partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_ENTRY_SIZE + FX_PARTITION_TYPE_OFFSET];
587 if (partition_type == FX_PARTITION_TYPE_EXTENDED || partition_type == FX_PARTITION_TYPE_EXTENDED_LBA)
588 {
589
590 /* Update sector number for next partition table. */
591 base_sector = _fx_utility_32_unsigned_read(&partition_sector_ptr[FX_PARTITION_TABLE_OFFSET + FX_PARTITION_ENTRY_SIZE + FX_PARTITION_LBA_OFFSET]) + base_sector_extended;
592 }
593 else
594 {
595 /* No valid partition, get out of the loop. */
596 break;
597 }
598 }
599
600 }
601
602 /* Return error. */
603 return(FX_NOT_FOUND);
604 }