2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
6 #include <exec/memory.h>
7 #include <exec/types.h>
8 #include <libraries/partition.h>
9 #include <proto/exec.h>
10 #include <proto/partition.h>
11 #include <proto/utility.h>
13 #include "partition_types.h"
14 #include "partition_support.h"
15 #include "partitionmbr.h"
20 struct PCPartitionTable
*entry
;
24 struct FATBootSector
{
27 UWORD bpb_bytes_per_sect
;
28 UBYTE bpb_sect_per_clust
;
29 UWORD bpb_rsvd_sect_count
;
31 UWORD bpb_root_entries_count
;
32 UWORD bpb_total_sectors_16
;
34 UWORD bpb_fat_size_16
;
35 UWORD bpb_sect_per_track
;
37 ULONG bpb_hidden_sect
;
38 ULONG bpb_total_sectors_32
;
47 UBYTE bs_filsystype
[8];
48 } __attribute__ ((__packed__
)) fat16
;
51 ULONG bpb_fat_size_32
;
54 ULONG bpb_root_cluster
;
56 UWORD bpb_back_bootsec
;
57 UBYTE bpb_reserved
[12];
63 UBYTE bs_filsystype
[8];
64 } __attribute__ ((__packed__
)) fat32
;
67 UBYTE bpb_signature
[2];
68 } __attribute__ ((__packed__
));
75 struct FATBootSector bs
;
80 LONG
MBRCheckPartitionTable(struct Library
*PartitionBase
, struct PartitionHandle
*root
, void *buffer
)
82 struct rootblock
*blk
= buffer
;
85 if (readBlock(PartitionBase
, root
, 0, blk
) == 0)
87 /* Check it doesn't look like a FAT boot sector */
88 ULONG sectorsize
, clustersectors
;
90 /* Valid sector size: 512, 1024, 2048, 4096 */
91 sectorsize
= AROS_LE2WORD(blk
->u
.bs
.bpb_bytes_per_sect
);
92 if (sectorsize
!= 512 && sectorsize
!= 1024 && sectorsize
!= 2048 && sectorsize
!= 4096)
95 /* Valid bpb_sect_per_clust: 1, 2, 4, 8, 16, 32, 64, 128 */
96 clustersectors
= blk
->u
.bs
.bpb_sect_per_clust
;
97 if ((clustersectors
& (clustersectors
- 1)) != 0 || clustersectors
== 0 || clustersectors
> 128)
100 /* Valid cluster size: 512, 1024, 2048, 4096, 8192, 16k, 32k, 64k */
101 if (clustersectors
* sectorsize
> 64 * 1024)
104 if (blk
->u
.bs
.bpb_media
< 0xF0)
109 struct PCPartitionTable
*pcpt
= blk
->u
.mbr
.pcpt
;
111 /* Check status bytes of all partition slots and block signature */
112 if ((AROS_LE2WORD(blk
->u
.mbr
.magic
) != MBR_MAGIC
) ||
113 (!MBR_STATUS_VALID(pcpt
[0].status
)) || (!MBR_STATUS_VALID(pcpt
[1].status
)) ||
114 (!MBR_STATUS_VALID(pcpt
[2].status
)) || (!MBR_STATUS_VALID(pcpt
[3].status
)))
124 static LONG
PartitionMBRCheckPartitionTable(struct Library
*PartitionBase
, struct PartitionHandle
*root
)
129 /* MBR can be placed only in the root of the disk */
133 blk
= AllocMem(root
->de
.de_SizeBlock
<< 2, MEMF_ANY
);
137 res
= MBRCheckPartitionTable(PartitionBase
, root
, blk
);
139 FreeMem(blk
, root
->de
.de_SizeBlock
<< 2);
143 static struct PartitionHandle
*PartitionMBRNewHandle(struct Library
*PartitionBase
, struct PartitionHandle
*root
, UBYTE position
, struct PCPartitionTable
*entry
)
145 struct PartitionHandle
*ph
;
147 if (entry
->first_sector
!= 0)
149 ph
= AllocMem(sizeof(struct PartitionHandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
152 struct MBRData
*data
;
154 data
= AllocMem(sizeof(struct MBRData
), MEMF_PUBLIC
);
158 data
->position
= position
;
161 /* initialize DosEnvec and DriveGeometry */
162 initPartitionHandle(root
, ph
, AROS_LE2LONG(data
->entry
->first_sector
), AROS_LE2LONG(data
->entry
->count_sector
));
164 /* Map type ID to a DOSType */
165 setDosType(&ph
->de
, MBR_FindDosType(data
->entry
->type
));
167 /* Set position as priority */
168 ph
->ln
.ln_Pri
= MBR_MAX_PARTITIONS
- 1 - position
;
171 FreeMem(ph
, sizeof(struct PartitionHandle
));
177 static LONG
PartitionMBROpenPartitionTable(struct Library
*PartitionBase
, struct PartitionHandle
*root
)
179 struct PartitionHandle
*ph
;
183 mbr
= AllocMem(root
->de
.de_SizeBlock
<<2, MEMF_PUBLIC
);
186 if (readBlock(PartitionBase
, root
, 0, mbr
) == 0)
188 root
->table
->data
= mbr
;
191 ph
= PartitionMBRNewHandle(PartitionBase
, root
, i
, &mbr
->pcpt
[i
]);
193 Enqueue(&root
->table
->list
, &ph
->ln
);
197 FreeMem(mbr
, root
->de
.de_SizeBlock
<<2);
202 static void PartitionMBRFreeHandle
204 struct Library
*PartitionBase
,
205 struct PartitionHandle
*ph
208 ClosePartitionTable(ph
);
209 FreeMem(ph
->data
, sizeof(struct MBRData
));
210 FreeMem(ph
, sizeof(struct PartitionHandle
));
213 static void PartitionMBRClosePartitionTable
215 struct Library
*PartitionBase
,
216 struct PartitionHandle
*root
219 struct PartitionHandle
*ph
;
221 while ((ph
= (struct PartitionHandle
*)RemTail(&root
->table
->list
)))
222 PartitionMBRFreeHandle(PartitionBase
, ph
);
223 FreeMem(root
->table
->data
, root
->de
.de_SizeBlock
<<2);
226 static LONG PartitionMBRWritePartitionTable
228 struct Library
*PartitionBase
,
229 struct PartitionHandle
*root
232 /* FIXME: readBlock(0) and synchronize data */
234 /* root->data = mbr is up to date */
235 if (writeBlock(PartitionBase
, root
, 0, root
->table
->data
))
240 static LONG PartitionMBRCreatePartitionTable
242 struct Library
*PartitionBase
,
243 struct PartitionHandle
*ph
248 mbr
= AllocMem(ph
->de
.de_SizeBlock
<<2, MEMF_PUBLIC
);
251 if (readBlock(PartitionBase
, ph
, 0, mbr
) == 0)
253 ph
->table
->data
= mbr
;
255 memset(mbr
->pcpt
, 0, sizeof(mbr
->pcpt
));
256 mbr
->magic
= AROS_WORD2LE(0xAA55);
258 NEWLIST(&ph
->table
->list
);
261 FreeMem(mbr
, ph
->de
.de_SizeBlock
<<2);
266 void PartitionMBRSetGeometry
268 struct PartitionHandle
*root
,
269 struct PCPartitionTable
*entry
,
272 ULONG relative_sector
278 /* Store LBA start block and block count */
280 entry
->first_sector
= AROS_LONG2LE(sector
- relative_sector
);
281 entry
->count_sector
= AROS_LONG2LE(count
);
283 /* Store CHS-address of start block. The upper two bits of the cylinder
284 number are stored in the upper two bits of the sector field */
286 track
= sector
/root
->de
.de_BlocksPerTrack
;
287 cyl
= track
/root
->de
.de_Surfaces
;
290 entry
->start_head
= track
% root
->de
.de_Surfaces
;
291 entry
->start_sector
=
292 ((sector
% root
->de
.de_BlocksPerTrack
) + 1)
293 | ((cyl
& 0x300) >> 2);
294 entry
->start_cylinder
= (cyl
& 0xFF);
298 entry
->start_head
= 0xFE;
299 entry
->start_sector
= 0xFF;
300 entry
->start_cylinder
= 0xFF;
303 /* Store CHS-address of last block */
306 track
= sector
/root
->de
.de_BlocksPerTrack
;
307 cyl
= track
/root
->de
.de_Surfaces
;
310 entry
->end_head
= track
% root
->de
.de_Surfaces
;
311 entry
->end_sector
= ((sector
% root
->de
.de_BlocksPerTrack
) + 1)
312 | ((cyl
& 0x300)>>2);
313 entry
->end_cylinder
= (cyl
& 0xFF);
317 entry
->end_head
= 0xFE;
318 entry
->end_sector
= 0xFF;
319 entry
->end_cylinder
= 0xFF;
323 static void PartitionMBRSetDosEnvec
325 struct PartitionHandle
*root
,
326 struct PCPartitionTable
*entry
,
332 sector
= de
->de_LowCyl
* de
->de_Surfaces
* de
->de_BlocksPerTrack
;
333 count
= (de
->de_HighCyl
- de
->de_LowCyl
+ 1) *
335 de
->de_BlocksPerTrack
;
336 PartitionMBRSetGeometry(root
, entry
, sector
, count
, 0);
339 static struct PartitionHandle
*PartitionMBRAddPartition(struct Library
*PartitionBase
, struct PartitionHandle
*root
, const struct TagItem
*taglist
)
343 tag
= FindTagItem(PT_DOSENVEC
, taglist
);
347 struct PCPartitionTable
*entry
;
348 struct PartitionHandle
*ph
;
349 struct DosEnvec
*de
= (struct DosEnvec
*)tag
->ti_Data
;
352 tag
= FindTagItem(PT_POSITION
, taglist
);
357 // Find an unused slot
358 for (i
= 0; i
< MBR_MAX_PARTITIONS
&& pos
== -1; i
++)
360 entry
= &((struct MBR
*)root
->table
->data
)->pcpt
[i
];
361 if (entry
->type
== 0)
368 entry
= &((struct MBR
*)root
->table
->data
)->pcpt
[pos
];
369 tag
= FindTagItem(PT_ACTIVE
, taglist
);
371 entry
->status
= tag
->ti_Data
? 0x80 : 0;
374 tag
= FindTagItem(PT_TYPE
, taglist
);
377 struct PartitionType
*ptype
= (struct PartitionType
*)tag
->ti_Data
;
379 entry
->type
= ptype
->id
[0];
383 PartitionMBRSetDosEnvec(root
, entry
, de
);
384 ph
= PartitionMBRNewHandle(PartitionBase
, root
, pos
, entry
);
386 Enqueue(&root
->table
->list
, &ph
->ln
);
388 memset(entry
, 0, sizeof(struct PCPartitionTable
));
396 static void PartitionMBRDeletePartition(struct Library
*PartitionBase
, struct PartitionHandle
*ph
)
398 struct MBRData
*data
= (struct MBRData
*)ph
->data
;
400 memset(data
->entry
, 0, sizeof(struct PCPartitionTable
));
403 PartitionMBRFreeHandle(PartitionBase
, ph
);
406 static LONG
PartitionMBRGetPartitionTableAttr(struct Library
*PartitionBase
,
407 struct PartitionHandle
*root
, const struct TagItem
*tag
)
412 *((LONG
*)tag
->ti_Data
) = root
->de
.de_BlocksPerTrack
; /* One track */
415 case PTT_MAX_PARTITIONS
:
416 *((LONG
*)tag
->ti_Data
) = MBR_MAX_PARTITIONS
;
423 static LONG
PartitionMBRGetPartitionAttr(struct Library
*PartitionBase
,
424 struct PartitionHandle
*ph
, const struct TagItem
*tag
)
426 struct MBRData
*data
= (struct MBRData
*)ph
->data
;
431 PTYPE(tag
->ti_Data
)->id
[0] = (LONG
)data
->entry
->type
;
432 PTYPE(tag
->ti_Data
)->id_len
= 1;
436 *((LONG
*)tag
->ti_Data
) = (LONG
)data
->position
;
440 *((LONG
*)tag
->ti_Data
) = data
->entry
->status
& 0x80 ? 1 : 0;
444 *((UQUAD
*)tag
->ti_Data
) = AROS_LE2LONG(data
->entry
->first_sector
);
448 *((UQUAD
*)tag
->ti_Data
) = AROS_LE2LONG(data
->entry
->first_sector
) + AROS_LE2LONG(data
->entry
->count_sector
) - 1;
452 /* Everything else gets default values */
456 static LONG
PartitionMBRSetPartitionAttrs(struct Library
*PartitionBase
, struct PartitionHandle
*ph
, const struct TagItem
*taglist
)
458 struct MBRData
*data
= (struct MBRData
*)ph
->data
;
461 while ((tag
= NextTagItem((struct TagItem
**)&taglist
)))
466 CopyMem((struct DosEnvec
*)tag
->ti_Data
, &ph
->de
, sizeof(struct DosEnvec
));
467 PartitionMBRSetDosEnvec(ph
->root
, data
->entry
, (struct DosEnvec
*)tag
->ti_Data
);
471 data
->entry
->type
= PTYPE(tag
->ti_Data
)->id
[0];
472 /* Update DOSType according to a new type ID */
473 setDosType(&ph
->de
, MBR_FindDosType(data
->entry
->type
));
477 if (tag
->ti_Data
!= data
->position
)
479 struct PartitionHandle
*node
;
480 struct PCPartitionTable
*entry
;
482 node
= (struct PartitionHandle
*)ph
->root
->table
->list
.lh_Head
;
483 while (node
->ln
.ln_Succ
)
485 if (tag
->ti_Data
== ((struct MBRData
*)node
->data
)->position
)
487 node
= (struct PartitionHandle
*)node
->ln
.ln_Succ
;
489 data
->position
= tag
->ti_Data
;
490 entry
= &((struct MBR
*)ph
->root
->table
->data
)->pcpt
[data
->position
];
491 CopyMem(data
->entry
, entry
, sizeof(struct PCPartitionTable
));
492 memset(data
->entry
, 0, sizeof(struct PCPartitionTable
));
494 ph
->ln
.ln_Pri
= MBR_MAX_PARTITIONS
-1-data
->position
;
496 Enqueue(&ph
->root
->table
->list
, &ph
->ln
);
504 data
->entry
->status
|= 0x80;
506 data
->entry
->status
&= ~0x80;
513 static const struct PartitionAttribute PartitionMBRPartitionTableAttrs
[]=
515 {PTT_TYPE
, PLAM_READ
},
516 {PTT_RESERVED
, PLAM_READ
},
517 {PTT_MAX_PARTITIONS
, PLAM_READ
},
521 static const struct PartitionAttribute PartitionMBRPartitionAttrs
[]=
523 {PT_GEOMETRY
, PLAM_READ
},
524 {PT_TYPE
, PLAM_READ
| PLAM_WRITE
},
525 {PT_POSITION
, PLAM_READ
| PLAM_WRITE
},
526 {PT_ACTIVE
, PLAM_READ
| PLAM_WRITE
},
527 {PT_STARTBLOCK
, PLAM_READ
},
528 {PT_ENDBLOCK
, PLAM_READ
},
532 ULONG
PartitionMBRDestroyPartitionTable(struct Library
*PartitionBase
,
533 struct PartitionHandle
*root
)
535 struct MBR
*mbr
= root
->table
->data
;
537 memset(mbr
->pcpt
, 0, sizeof(mbr
->pcpt
));
538 /* deleting the magic value will invalidate the
539 * partition table so it cannot be opened again
542 if (writeBlock(PartitionBase
, root
, 0, root
->table
->data
))
547 const struct PTFunctionTable PartitionMBR
=
551 PartitionMBRCheckPartitionTable
,
552 PartitionMBROpenPartitionTable
,
553 PartitionMBRClosePartitionTable
,
554 PartitionMBRWritePartitionTable
,
555 PartitionMBRCreatePartitionTable
,
556 PartitionMBRAddPartition
,
557 PartitionMBRDeletePartition
,
558 PartitionMBRGetPartitionTableAttr
,
560 PartitionMBRGetPartitionAttr
,
561 PartitionMBRSetPartitionAttrs
,
562 PartitionMBRPartitionTableAttrs
,
563 PartitionMBRPartitionAttrs
,
564 PartitionMBRDestroyPartitionTable
,