2 Copyright © 1995-2009, The AROS Development Team. All rights reserved.
7 #include <proto/exec.h>
8 #include <proto/partition.h>
10 #include <exec/memory.h>
11 #include <exec/types.h>
12 #include <libraries/partition.h>
14 #include "partition_support.h"
15 #include "partitionmbr.h"
24 struct PCPartitionTable
*entry
;
28 struct FATBootSector
{
31 UWORD bpb_bytes_per_sect
;
32 UBYTE bpb_sect_per_clust
;
33 UWORD bpb_rsvd_sect_count
;
35 UWORD bpb_root_entries_count
;
36 UWORD bpb_total_sectors_16
;
38 UWORD bpb_fat_size_16
;
39 UWORD bpb_sect_per_track
;
41 ULONG bpb_hidden_sect
;
42 ULONG bpb_total_sectors_32
;
51 UBYTE bs_filsystype
[8];
52 } __attribute__ ((__packed__
)) fat16
;
55 ULONG bpb_fat_size_32
;
58 ULONG bpb_root_cluster
;
60 UWORD bpb_back_bootsec
;
61 UBYTE bpb_reserved
[12];
67 UBYTE bs_filsystype
[8];
68 } __attribute__ ((__packed__
)) fat32
;
71 UBYTE bpb_signature
[2];
72 } __attribute__ ((__packed__
));
74 static LONG PartitionMBRCheckPartitionTable
76 struct Library
*PartitionBase
,
77 struct PartitionHandle
*root
85 struct FATBootSector bs
;
86 UBYTE space
[root
->de
.de_SizeBlock
<< 2];
92 ULONG sectorsize
, clustersectors
;
93 struct PCPartitionTable
*pcpt
;
95 if (readBlock(PartitionBase
, root
, 0, &blk
) == 0)
97 /* Check it doesn't look like a FAT boot sector */
99 /* Valid sector size: 512, 1024, 2048, 4096 */
100 sectorsize
= AROS_LE2WORD(blk
.u
.bs
.bpb_bytes_per_sect
);
102 sectorsize
!= 512 && sectorsize
!= 1024 && sectorsize
!= 2048 &&
107 /* Valid bpb_sect_per_clust: 1, 2, 4, 8, 16, 32, 64, 128 */
108 clustersectors
= blk
.u
.bs
.bpb_sect_per_clust
;
110 (clustersectors
& (clustersectors
- 1)) != 0 ||
111 clustersectors
== 0 || clustersectors
> 128
115 /* Valid cluster size: 512, 1024, 2048, 4096, 8192, 16k, 32k, 64k */
116 if (clustersectors
* sectorsize
> 64 * 1024)
119 if (blk
.u
.bs
.bpb_media
< 0xF0)
122 /* Check status bytes of all partition slots and block signature */
123 pcpt
= blk
.u
.mbr
.pcpt
;
125 (AROS_LE2WORD(blk
.u
.mbr
.magic
) == 0xAA55) &&
126 (((pcpt
[0].status
& 0x0F)==0) || (pcpt
[0].status
& 0x80)) &&
127 (((pcpt
[1].status
& 0x0F)==0) || (pcpt
[1].status
& 0x80)) &&
128 (((pcpt
[2].status
& 0x0F)==0) || (pcpt
[2].status
& 0x80)) &&
129 (((pcpt
[3].status
& 0x0F)==0) || (pcpt
[3].status
& 0x80))
132 if (root
->root
|| isfat
)
142 static struct PartitionHandle
*PartitionMBRNewHandle
144 struct Library
*PartitionBase
,
145 struct PartitionHandle
*root
,
147 struct PCPartitionTable
*entry
150 struct PartitionHandle
*ph
;
153 if (entry
->first_sector
!= 0)
155 ph
= AllocMem(sizeof(struct PartitionHandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
158 struct MBRData
*data
;
160 data
= AllocMem(sizeof(struct MBRData
), MEMF_PUBLIC
);
163 cylsecs
= root
->de
.de_BlocksPerTrack
*root
->de
.de_Surfaces
;
165 data
->position
= position
;
170 /* initialize DosEnvec */
172 /* Check if partition starts and ends on a cylinder boundary */
173 CopyMem(&root
->de
, &ph
->de
, sizeof(struct DosEnvec
));
175 (AROS_LE2LONG(data
->entry
->first_sector
) % cylsecs
!= 0) ||
176 (AROS_LE2LONG(data
->entry
->count_sector
) % cylsecs
!= 0)
179 /* Treat each track as a cylinder if possible */
180 ph
->de
.de_Surfaces
= 1;
181 cylsecs
= ph
->de
.de_BlocksPerTrack
*ph
->de
.de_Surfaces
;
183 (AROS_LE2LONG(data
->entry
->first_sector
) % cylsecs
!= 0) ||
184 (AROS_LE2LONG(data
->entry
->count_sector
) % cylsecs
!= 0)
187 /* We can't. We could find the highest common factor of
188 first_sector and count_sector here, but currently we
189 simply use one block per cylinder */
190 ph
->de
.de_BlocksPerTrack
= 1;
191 cylsecs
= ph
->de
.de_BlocksPerTrack
*ph
->de
.de_Surfaces
;
194 ph
->de
.de_LowCyl
= AROS_LE2LONG(data
->entry
->first_sector
) / cylsecs
;
197 (AROS_LE2LONG(data
->entry
->count_sector
)/cylsecs
)-1;
198 ph
->de
.de_TableSize
= 10; // only until de_HighCyl
199 ph
->ln
.ln_Pri
= MBR_MAX_PARTITIONS
-1-position
;
201 /* initialize DriveGeometry */
202 ph
->dg
.dg_DeviceType
= DG_DIRECT_ACCESS
;
203 ph
->dg
.dg_SectorSize
= ph
->de
.de_SizeBlock
<<2;
204 ph
->dg
.dg_Heads
= ph
->de
.de_Surfaces
;
205 ph
->dg
.dg_TrackSectors
= ph
->de
.de_BlocksPerTrack
;
206 ph
->dg
.dg_Cylinders
= ph
->de
.de_HighCyl
- ph
->de
.de_LowCyl
+ 1;
207 ph
->dg
.dg_BufMemType
= ph
->de
.de_BufMemType
;
210 FreeMem(ph
, sizeof(struct PartitionHandle
));
216 static LONG PartitionMBROpenPartitionTable
218 struct Library
*PartitionBase
,
219 struct PartitionHandle
*root
222 struct PartitionHandle
*ph
;
226 mbr
= AllocMem(root
->de
.de_SizeBlock
<<2, MEMF_PUBLIC
);
229 if (readBlock(PartitionBase
, root
, 0, mbr
) == 0)
231 NEWLIST(&root
->table
->list
);
232 root
->table
->data
= mbr
;
235 ph
= PartitionMBRNewHandle(PartitionBase
, root
, i
, &mbr
->pcpt
[i
]);
237 Enqueue(&root
->table
->list
, &ph
->ln
);
241 FreeMem(mbr
, root
->de
.de_SizeBlock
<<2);
246 static void PartitionMBRFreeHandle
248 struct Library
*PartitionBase
,
249 struct PartitionHandle
*ph
252 ClosePartitionTable(ph
);
253 FreeMem(ph
->data
, sizeof(struct MBRData
));
254 FreeMem(ph
, sizeof(struct PartitionHandle
));
257 static void PartitionMBRClosePartitionTable
259 struct Library
*PartitionBase
,
260 struct PartitionHandle
*root
263 struct PartitionHandle
*ph
;
265 while ((ph
= (struct PartitionHandle
*)RemTail(&root
->table
->list
)))
266 PartitionMBRFreeHandle(PartitionBase
, ph
);
267 FreeMem(root
->table
->data
, root
->de
.de_SizeBlock
<<2);
270 static LONG PartitionMBRWritePartitionTable
272 struct Library
*PartitionBase
,
273 struct PartitionHandle
*root
276 #warning "FIXME: readBlock(0) and synchronize data"
278 /* root->data = mbr is up to date */
279 if (writeBlock(PartitionBase
, root
, 0, root
->table
->data
))
284 static LONG PartitionMBRCreatePartitionTable
286 struct Library
*PartitionBase
,
287 struct PartitionHandle
*ph
292 mbr
= AllocMem(ph
->de
.de_SizeBlock
<<2, MEMF_PUBLIC
);
295 if (readBlock(PartitionBase
, ph
, 0, mbr
) == 0)
297 ph
->table
->data
= mbr
;
298 fillMem((BYTE
*)mbr
->pcpt
, sizeof(mbr
->pcpt
), 0);
299 mbr
->magic
= AROS_WORD2LE(0xAA55);
300 NEWLIST(&ph
->table
->list
);
303 FreeMem(mbr
, ph
->de
.de_SizeBlock
<<2);
308 void PartitionMBRSetGeometry
310 struct PartitionHandle
*root
,
311 struct PCPartitionTable
*entry
,
314 ULONG relative_sector
320 /* Store LBA start block and block count */
322 entry
->first_sector
= AROS_LONG2LE(sector
- relative_sector
);
323 entry
->count_sector
= AROS_LONG2LE(count
);
325 /* Store CHS-address of start block. The upper two bits of the cylinder
326 number are stored in the upper two bits of the sector field */
328 track
= sector
/root
->de
.de_BlocksPerTrack
;
329 cyl
= track
/root
->de
.de_Surfaces
;
332 entry
->start_head
= track
% root
->de
.de_Surfaces
;
333 entry
->start_sector
=
334 ((sector
% root
->de
.de_BlocksPerTrack
) + 1)
335 | ((cyl
& 0x300) >> 2);
336 entry
->start_cylinder
= (cyl
& 0xFF);
340 entry
->start_head
= 0xFE;
341 entry
->start_sector
= 0xFF;
342 entry
->start_cylinder
= 0xFF;
345 /* Store CHS-address of last block */
348 track
= sector
/root
->de
.de_BlocksPerTrack
;
349 cyl
= track
/root
->de
.de_Surfaces
;
352 entry
->end_head
= track
% root
->de
.de_Surfaces
;
353 entry
->end_sector
= ((sector
% root
->de
.de_BlocksPerTrack
) + 1)
354 | ((cyl
& 0x300)>>2);
355 entry
->end_cylinder
= (cyl
& 0xFF);
359 entry
->end_head
= 0xFE;
360 entry
->end_sector
= 0xFF;
361 entry
->end_cylinder
= 0xFF;
365 static void PartitionMBRSetDosEnvec
367 struct PartitionHandle
*root
,
368 struct PCPartitionTable
*entry
,
374 sector
= de
->de_LowCyl
* de
->de_Surfaces
* de
->de_BlocksPerTrack
;
375 count
= (de
->de_HighCyl
- de
->de_LowCyl
+ 1) *
377 de
->de_BlocksPerTrack
;
378 PartitionMBRSetGeometry(root
, entry
, sector
, count
, 0);
381 static struct PartitionHandle
*PartitionMBRAddPartition
383 struct Library
*PartitionBase
,
384 struct PartitionHandle
*root
,
385 struct TagItem
*taglist
390 tag
= findTagItem(PT_DOSENVEC
, taglist
);
393 struct PCPartitionTable
*entry
;
394 struct PartitionHandle
*ph
;
398 de
= (struct DosEnvec
*)tag
->ti_Data
;
399 tag
= findTagItem(PT_POSITION
, taglist
);
404 // Find an unused slot
405 for (i
= 0; i
< MBR_MAX_PARTITIONS
&& pos
== -1; i
++)
407 entry
= &((struct MBR
*)root
->table
->data
)->pcpt
[i
];
408 if (entry
->type
== 0)
415 entry
= &((struct MBR
*)root
->table
->data
)->pcpt
[pos
];
416 tag
= findTagItem(PT_ACTIVE
, taglist
);
418 entry
->status
= tag
->ti_Data
? 0x80 : 0;
421 tag
= findTagItem(PT_TYPE
, taglist
);
424 struct PartitionType
*ptype
= (struct PartitionType
*)tag
->ti_Data
;
426 entry
->type
= ptype
->id
[0];
430 PartitionMBRSetDosEnvec(root
, entry
, de
);
431 ph
= PartitionMBRNewHandle(PartitionBase
, root
, pos
, entry
);
433 Enqueue(&root
->table
->list
, &ph
->ln
);
435 fillMem((BYTE
*)entry
, sizeof(struct PCPartitionTable
), 0);
442 static void PartitionMBRDeletePartition
444 struct Library
*PartitionBase
,
445 struct PartitionHandle
*ph
448 struct MBRData
*data
;
450 data
= (struct MBRData
*)ph
->data
;
451 fillMem((BYTE
*)data
->entry
, sizeof(struct PCPartitionTable
), 0);
453 PartitionMBRFreeHandle(PartitionBase
, ph
);
456 static LONG PartitionMBRGetPartitionTableAttrs
458 struct Library
*PartitionBase
,
459 struct PartitionHandle
*root
,
460 struct TagItem
*taglist
464 while (taglist
[0].ti_Tag
!= TAG_DONE
)
467 switch (taglist
[0].ti_Tag
)
470 *((LONG
*)taglist
[0].ti_Data
) = root
->table
->type
;
473 *((LONG
*)taglist
[0].ti_Data
) =
474 root
->de
.de_BlocksPerTrack
; /* One track */
476 case PTT_MAX_PARTITIONS
:
477 *((LONG
*)taglist
[0].ti_Data
) = MBR_MAX_PARTITIONS
;
484 static LONG PartitionMBRSetPartitionTableAttrs
486 struct Library
*PartitionBase
,
487 struct PartitionHandle
*root
,
488 struct TagItem
*taglist
492 while (taglist
[0].ti_Tag
!= TAG_DONE
)
495 switch (taglist
[0].ti_Tag
)
503 static LONG PartitionMBRGetPartitionAttrs
505 struct Library
*PartitionBase
,
506 struct PartitionHandle
*ph
,
507 struct TagItem
*taglist
511 while (taglist
[0].ti_Tag
!= TAG_DONE
)
513 struct MBRData
*data
= (struct MBRData
*)ph
->data
;
515 switch (taglist
[0].ti_Tag
)
519 struct DriveGeometry
*dg
= (struct DriveGeometry
*)taglist
[0].ti_Data
;
520 CopyMem(&ph
->dg
, dg
, sizeof(struct DriveGeometry
));
524 CopyMem(&ph
->de
, (struct DosEnvec
*)taglist
[0].ti_Data
, sizeof(struct DosEnvec
));
528 struct PartitionType
*ptype
=(struct PartitionType
*)taglist
[0].ti_Data
;
530 ptype
->id
[0] = (LONG
)data
->entry
->type
;
535 *((LONG
*)taglist
[0].ti_Data
) = (LONG
)data
->position
;
538 *((LONG
*)taglist
[0].ti_Data
) = data
->entry
->status
& 0x80 ? 1 : 0;
546 static LONG PartitionMBRSetPartitionAttrs
548 struct Library
*PartitionBase
,
549 struct PartitionHandle
*ph
,
550 struct TagItem
*taglist
554 while (taglist
[0].ti_Tag
!= TAG_DONE
)
556 struct MBRData
*data
= (struct MBRData
*)ph
->data
;
558 switch (taglist
[0].ti_Tag
)
563 de
= (struct DosEnvec
*)taglist
[0].ti_Data
;
564 CopyMem(de
, &ph
->de
, sizeof(struct DosEnvec
));
565 PartitionMBRSetDosEnvec(ph
->root
, data
->entry
, de
);
570 struct PartitionType
*ptype
=(struct PartitionType
*)taglist
[0].ti_Data
;
572 data
->entry
->type
= ptype
->id
[0];
576 if (taglist
[0].ti_Data
!= data
->position
)
578 struct PartitionHandle
*node
;
579 struct PCPartitionTable
*entry
;
581 node
= (struct PartitionHandle
*)ph
->root
->table
->list
.lh_Head
;
582 while (node
->ln
.ln_Succ
)
584 if (taglist
[0].ti_Data
== ((struct MBRData
*)node
->data
)->position
)
586 node
= (struct PartitionHandle
*)node
->ln
.ln_Succ
;
588 data
->position
= taglist
[0].ti_Data
;
589 entry
= &((struct MBR
*)ph
->root
->table
->data
)->pcpt
[data
->position
];
590 CopyMem(data
->entry
, entry
, sizeof(struct PCPartitionTable
));
591 fillMem((BYTE
*)data
->entry
, sizeof(struct PCPartitionTable
), 0);
593 ph
->ln
.ln_Pri
= MBR_MAX_PARTITIONS
-1-data
->position
;
595 Enqueue(&ph
->root
->table
->list
, &ph
->ln
);
601 if (taglist
[0].ti_Data
)
602 data
->entry
->status
|= 0x80;
604 data
->entry
->status
&= ~0x80;
612 static struct PartitionAttribute PartitionMBRPartitionTableAttrs
[]=
614 {PTTA_TYPE
, PLAM_READ
},
615 {PTTA_RESERVED
, PLAM_READ
},
616 {PTTA_MAX_PARTITIONS
, PLAM_READ
},
620 static struct PartitionAttribute
*PartitionMBRQueryPartitionTableAttrs(struct Library
*PartitionBase
)
622 return PartitionMBRPartitionTableAttrs
;
625 static struct PartitionAttribute PartitionMBRPartitionAttrs
[]=
627 {PTA_GEOMETRY
, PLAM_READ
},
628 {PTA_TYPE
, PLAM_READ
| PLAM_WRITE
},
629 {PTA_POSITION
, PLAM_READ
| PLAM_WRITE
},
630 {PTA_ACTIVE
, PLAM_READ
| PLAM_WRITE
},
634 struct PartitionAttribute
*PartitionMBRQueryPartitionAttrs(struct Library
*PartitionBase
)
636 return PartitionMBRPartitionAttrs
;
639 static ULONG PartitionMBRDestroyPartitionTable
641 struct Library
*PartitionBase
,
642 struct PartitionHandle
*root
647 mbr
= root
->table
->data
;
648 fillMem((BYTE
*)mbr
->pcpt
, sizeof(mbr
->pcpt
), 0);
649 if (writeBlock(PartitionBase
, root
, 0, root
->table
->data
))
654 struct PTFunctionTable PartitionMBR
=
658 PartitionMBRCheckPartitionTable
,
659 PartitionMBROpenPartitionTable
,
660 PartitionMBRClosePartitionTable
,
661 PartitionMBRWritePartitionTable
,
662 PartitionMBRCreatePartitionTable
,
663 PartitionMBRAddPartition
,
664 PartitionMBRDeletePartition
,
665 PartitionMBRGetPartitionTableAttrs
,
666 PartitionMBRSetPartitionTableAttrs
,
667 PartitionMBRGetPartitionAttrs
,
668 PartitionMBRSetPartitionAttrs
,
669 PartitionMBRQueryPartitionTableAttrs
,
670 PartitionMBRQueryPartitionAttrs
,
671 PartitionMBRDestroyPartitionTable