2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
7 #include <exec/memory.h>
8 #include <exec/types.h>
9 #include <libraries/partition.h>
10 #include <proto/exec.h>
11 #include <proto/partition.h>
12 #include <proto/utility.h>
14 #include "partition_types.h"
15 #include "partition_support.h"
16 #include "partitionmbr.h"
21 struct PCPartitionTable
*entry
;
25 struct FATBootSector
{
28 UWORD bpb_bytes_per_sect
;
29 UBYTE bpb_sect_per_clust
;
30 UWORD bpb_rsvd_sect_count
;
32 UWORD bpb_root_entries_count
;
33 UWORD bpb_total_sectors_16
;
35 UWORD bpb_fat_size_16
;
36 UWORD bpb_sect_per_track
;
38 ULONG bpb_hidden_sect
;
39 ULONG bpb_total_sectors_32
;
48 UBYTE bs_filsystype
[8];
49 } __attribute__ ((__packed__
)) fat16
;
52 ULONG bpb_fat_size_32
;
55 ULONG bpb_root_cluster
;
57 UWORD bpb_back_bootsec
;
58 UBYTE bpb_reserved
[12];
64 UBYTE bs_filsystype
[8];
65 } __attribute__ ((__packed__
)) fat32
;
68 UBYTE bpb_signature
[2];
69 } __attribute__ ((__packed__
));
76 struct FATBootSector bs
;
81 LONG
MBRCheckPartitionTable(struct Library
*PartitionBase
, struct PartitionHandle
*root
, void *buffer
)
83 struct rootblock
*blk
= buffer
;
86 if (readBlock(PartitionBase
, root
, 0, blk
) == 0)
88 /* Check it doesn't look like a FAT boot sector */
89 ULONG sectorsize
, clustersectors
;
91 /* Valid sector size: 512, 1024, 2048, 4096 */
92 sectorsize
= AROS_LE2WORD(blk
->u
.bs
.bpb_bytes_per_sect
);
93 if (sectorsize
!= 512 && sectorsize
!= 1024 && sectorsize
!= 2048 && sectorsize
!= 4096)
96 /* Valid bpb_sect_per_clust: 1, 2, 4, 8, 16, 32, 64, 128 */
97 clustersectors
= blk
->u
.bs
.bpb_sect_per_clust
;
98 if ((clustersectors
& (clustersectors
- 1)) != 0 || clustersectors
== 0 || clustersectors
> 128)
101 /* Valid cluster size: 512, 1024, 2048, 4096, 8192, 16k, 32k, 64k */
102 if (clustersectors
* sectorsize
> 64 * 1024)
105 if (blk
->u
.bs
.bpb_media
< 0xF0)
110 struct PCPartitionTable
*pcpt
= blk
->u
.mbr
.pcpt
;
112 /* Check status bytes of all partition slots and block signature */
113 if ((AROS_LE2WORD(blk
->u
.mbr
.magic
) != MBR_MAGIC
) ||
114 (!MBR_STATUS_VALID(pcpt
[0].status
)) || (!MBR_STATUS_VALID(pcpt
[1].status
)) ||
115 (!MBR_STATUS_VALID(pcpt
[2].status
)) || (!MBR_STATUS_VALID(pcpt
[3].status
)))
125 static LONG
PartitionMBRCheckPartitionTable(struct Library
*PartitionBase
, struct PartitionHandle
*root
)
130 /* MBR can be placed only in the root of the disk */
134 blk
= AllocMem(root
->de
.de_SizeBlock
<< 2, MEMF_ANY
);
138 res
= MBRCheckPartitionTable(PartitionBase
, root
, blk
);
140 FreeMem(blk
, root
->de
.de_SizeBlock
<< 2);
144 static struct PartitionHandle
*PartitionMBRNewHandle(struct Library
*PartitionBase
, struct PartitionHandle
*root
, UBYTE position
, struct PCPartitionTable
*entry
)
146 struct PartitionHandle
*ph
;
148 if (entry
->first_sector
!= 0)
150 ph
= AllocMem(sizeof(struct PartitionHandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
153 struct MBRData
*data
;
155 data
= AllocMem(sizeof(struct MBRData
), MEMF_PUBLIC
);
159 data
->position
= position
;
162 /* initialize DosEnvec and DriveGeometry */
163 initPartitionHandle(root
, ph
, AROS_LE2LONG(data
->entry
->first_sector
), AROS_LE2LONG(data
->entry
->count_sector
));
165 /* Map type ID to a DOSType */
166 setDosType(&ph
->de
, MBR_FindDosType(data
->entry
->type
));
168 /* Set position as priority */
169 ph
->ln
.ln_Pri
= MBR_MAX_PARTITIONS
- 1 - position
;
172 FreeMem(ph
, sizeof(struct PartitionHandle
));
178 static LONG
PartitionMBROpenPartitionTable(struct Library
*PartitionBase
, struct PartitionHandle
*root
)
180 struct PartitionHandle
*ph
;
184 mbr
= AllocMem(root
->de
.de_SizeBlock
<<2, MEMF_PUBLIC
);
187 if (readBlock(PartitionBase
, root
, 0, mbr
) == 0)
189 root
->table
->data
= mbr
;
192 ph
= PartitionMBRNewHandle(PartitionBase
, root
, i
, &mbr
->pcpt
[i
]);
194 Enqueue(&root
->table
->list
, &ph
->ln
);
198 FreeMem(mbr
, root
->de
.de_SizeBlock
<<2);
203 static void PartitionMBRFreeHandle
205 struct Library
*PartitionBase
,
206 struct PartitionHandle
*ph
209 ClosePartitionTable(ph
);
210 FreeMem(ph
->data
, sizeof(struct MBRData
));
211 FreeMem(ph
, sizeof(struct PartitionHandle
));
214 static void PartitionMBRClosePartitionTable
216 struct Library
*PartitionBase
,
217 struct PartitionHandle
*root
220 struct PartitionHandle
*ph
;
222 while ((ph
= (struct PartitionHandle
*)RemTail(&root
->table
->list
)))
223 PartitionMBRFreeHandle(PartitionBase
, ph
);
224 FreeMem(root
->table
->data
, root
->de
.de_SizeBlock
<<2);
227 static LONG PartitionMBRWritePartitionTable
229 struct Library
*PartitionBase
,
230 struct PartitionHandle
*root
233 /* FIXME: readBlock(0) and synchronize data */
235 /* root->data = mbr is up to date */
236 if (writeBlock(PartitionBase
, root
, 0, root
->table
->data
))
241 static LONG PartitionMBRCreatePartitionTable
243 struct Library
*PartitionBase
,
244 struct PartitionHandle
*ph
249 mbr
= AllocMem(ph
->de
.de_SizeBlock
<<2, MEMF_PUBLIC
);
252 if (readBlock(PartitionBase
, ph
, 0, mbr
) == 0)
254 ph
->table
->data
= mbr
;
256 memset(mbr
->pcpt
, 0, sizeof(mbr
->pcpt
));
257 mbr
->magic
= AROS_WORD2LE(0xAA55);
259 NEWLIST(&ph
->table
->list
);
262 FreeMem(mbr
, ph
->de
.de_SizeBlock
<<2);
267 void PartitionMBRSetGeometry
269 struct PartitionHandle
*root
,
270 struct PCPartitionTable
*entry
,
273 ULONG relative_sector
279 /* Store LBA start block and block count */
281 entry
->first_sector
= AROS_LONG2LE(sector
- relative_sector
);
282 entry
->count_sector
= AROS_LONG2LE(count
);
284 /* Store CHS-address of start block. The upper two bits of the cylinder
285 number are stored in the upper two bits of the sector field */
287 track
= sector
/root
->de
.de_BlocksPerTrack
;
288 cyl
= track
/root
->de
.de_Surfaces
;
291 entry
->start_head
= track
% root
->de
.de_Surfaces
;
292 entry
->start_sector
=
293 ((sector
% root
->de
.de_BlocksPerTrack
) + 1)
294 | ((cyl
& 0x300) >> 2);
295 entry
->start_cylinder
= (cyl
& 0xFF);
299 entry
->start_head
= 0xFE;
300 entry
->start_sector
= 0xFF;
301 entry
->start_cylinder
= 0xFF;
304 /* Store CHS-address of last block */
307 track
= sector
/root
->de
.de_BlocksPerTrack
;
308 cyl
= track
/root
->de
.de_Surfaces
;
311 entry
->end_head
= track
% root
->de
.de_Surfaces
;
312 entry
->end_sector
= ((sector
% root
->de
.de_BlocksPerTrack
) + 1)
313 | ((cyl
& 0x300)>>2);
314 entry
->end_cylinder
= (cyl
& 0xFF);
318 entry
->end_head
= 0xFE;
319 entry
->end_sector
= 0xFF;
320 entry
->end_cylinder
= 0xFF;
324 static void PartitionMBRSetDosEnvec
326 struct PartitionHandle
*root
,
327 struct PCPartitionTable
*entry
,
333 sector
= de
->de_LowCyl
* de
->de_Surfaces
* de
->de_BlocksPerTrack
;
334 count
= (de
->de_HighCyl
- de
->de_LowCyl
+ 1) *
336 de
->de_BlocksPerTrack
;
337 PartitionMBRSetGeometry(root
, entry
, sector
, count
, 0);
340 static struct PartitionHandle
*PartitionMBRAddPartition(struct Library
*PartitionBase
, struct PartitionHandle
*root
, struct TagItem
*taglist
)
344 tag
= FindTagItem(PT_DOSENVEC
, taglist
);
348 struct PCPartitionTable
*entry
;
349 struct PartitionHandle
*ph
;
350 struct DosEnvec
*de
= (struct DosEnvec
*)tag
->ti_Data
;
353 tag
= FindTagItem(PT_POSITION
, taglist
);
358 // Find an unused slot
359 for (i
= 0; i
< MBR_MAX_PARTITIONS
&& pos
== -1; i
++)
361 entry
= &((struct MBR
*)root
->table
->data
)->pcpt
[i
];
362 if (entry
->type
== 0)
369 entry
= &((struct MBR
*)root
->table
->data
)->pcpt
[pos
];
370 tag
= FindTagItem(PT_ACTIVE
, taglist
);
372 entry
->status
= tag
->ti_Data
? 0x80 : 0;
375 tag
= FindTagItem(PT_TYPE
, taglist
);
378 struct PartitionType
*ptype
= (struct PartitionType
*)tag
->ti_Data
;
380 entry
->type
= ptype
->id
[0];
384 PartitionMBRSetDosEnvec(root
, entry
, de
);
385 ph
= PartitionMBRNewHandle(PartitionBase
, root
, pos
, entry
);
387 Enqueue(&root
->table
->list
, &ph
->ln
);
389 memset(entry
, 0, sizeof(struct PCPartitionTable
));
397 static void PartitionMBRDeletePartition(struct Library
*PartitionBase
, struct PartitionHandle
*ph
)
399 struct MBRData
*data
= (struct MBRData
*)ph
->data
;
401 memset(data
->entry
, 0, sizeof(struct PCPartitionTable
));
404 PartitionMBRFreeHandle(PartitionBase
, ph
);
407 static LONG
PartitionMBRGetPartitionTableAttr(struct Library
*PartitionBase
, struct PartitionHandle
*root
, 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
, struct PartitionHandle
*ph
, struct TagItem
*tag
)
425 struct MBRData
*data
= (struct MBRData
*)ph
->data
;
430 PTYPE(tag
->ti_Data
)->id
[0] = (LONG
)data
->entry
->type
;
431 PTYPE(tag
->ti_Data
)->id_len
= 1;
435 *((LONG
*)tag
->ti_Data
) = (LONG
)data
->position
;
439 *((LONG
*)tag
->ti_Data
) = data
->entry
->status
& 0x80 ? 1 : 0;
443 *((ULONG
*)tag
->ti_Data
) = AROS_LE2LONG(data
->entry
->first_sector
);
447 *((ULONG
*)tag
->ti_Data
) = AROS_LE2LONG(data
->entry
->first_sector
) + AROS_LE2LONG(data
->entry
->count_sector
) - 1;
451 /* Everything else gets default values */
455 static LONG
PartitionMBRSetPartitionAttrs(struct Library
*PartitionBase
, struct PartitionHandle
*ph
, const struct TagItem
*taglist
)
457 struct MBRData
*data
= (struct MBRData
*)ph
->data
;
460 while ((tag
= NextTagItem((struct TagItem
**)&taglist
)))
465 CopyMem((struct DosEnvec
*)tag
->ti_Data
, &ph
->de
, sizeof(struct DosEnvec
));
466 PartitionMBRSetDosEnvec(ph
->root
, data
->entry
, (struct DosEnvec
*)tag
->ti_Data
);
470 data
->entry
->type
= PTYPE(tag
->ti_Data
)->id
[0];
471 /* Update DOSType according to a new type ID */
472 setDosType(&ph
->de
, MBR_FindDosType(data
->entry
->type
));
476 if (tag
->ti_Data
!= data
->position
)
478 struct PartitionHandle
*node
;
479 struct PCPartitionTable
*entry
;
481 node
= (struct PartitionHandle
*)ph
->root
->table
->list
.lh_Head
;
482 while (node
->ln
.ln_Succ
)
484 if (tag
->ti_Data
== ((struct MBRData
*)node
->data
)->position
)
486 node
= (struct PartitionHandle
*)node
->ln
.ln_Succ
;
488 data
->position
= tag
->ti_Data
;
489 entry
= &((struct MBR
*)ph
->root
->table
->data
)->pcpt
[data
->position
];
490 CopyMem(data
->entry
, entry
, sizeof(struct PCPartitionTable
));
491 memset(data
->entry
, 0, sizeof(struct PCPartitionTable
));
493 ph
->ln
.ln_Pri
= MBR_MAX_PARTITIONS
-1-data
->position
;
495 Enqueue(&ph
->root
->table
->list
, &ph
->ln
);
503 data
->entry
->status
|= 0x80;
505 data
->entry
->status
&= ~0x80;
512 static const struct PartitionAttribute PartitionMBRPartitionTableAttrs
[]=
514 {PTT_TYPE
, PLAM_READ
},
515 {PTT_RESERVED
, PLAM_READ
},
516 {PTT_MAX_PARTITIONS
, PLAM_READ
},
520 static const struct PartitionAttribute PartitionMBRPartitionAttrs
[]=
522 {PT_GEOMETRY
, PLAM_READ
},
523 {PT_TYPE
, PLAM_READ
| PLAM_WRITE
},
524 {PT_POSITION
, PLAM_READ
| PLAM_WRITE
},
525 {PT_ACTIVE
, PLAM_READ
| PLAM_WRITE
},
526 {PT_STARTBLOCK
, PLAM_READ
},
527 {PT_ENDBLOCK
, PLAM_READ
},
531 static ULONG
PartitionMBRDestroyPartitionTable(struct Library
*PartitionBase
, struct PartitionHandle
*root
)
533 struct MBR
*mbr
= root
->table
->data
;
535 memset(mbr
->pcpt
, 0, sizeof(mbr
->pcpt
));
536 /* deleting the magic value will invalidate the
537 * partition table so it cannot be opened again
540 if (writeBlock(PartitionBase
, root
, 0, root
->table
->data
))
545 const struct PTFunctionTable PartitionMBR
=
549 PartitionMBRCheckPartitionTable
,
550 PartitionMBROpenPartitionTable
,
551 PartitionMBRClosePartitionTable
,
552 PartitionMBRWritePartitionTable
,
553 PartitionMBRCreatePartitionTable
,
554 PartitionMBRAddPartition
,
555 PartitionMBRDeletePartition
,
556 PartitionMBRGetPartitionTableAttr
,
558 PartitionMBRGetPartitionAttr
,
559 PartitionMBRSetPartitionAttrs
,
560 PartitionMBRPartitionTableAttrs
,
561 PartitionMBRPartitionAttrs
,
562 PartitionMBRDestroyPartitionTable
,