2 Copyright © 1995-2007, 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 static LONG PartitionMBRCheckPartitionTable
30 struct Library
*PartitionBase
,
31 struct PartitionHandle
*root
36 if (readBlock(PartitionBase
, root
, 0, &mbr
) == 0)
39 (AROS_LE2WORD(mbr
.magic
) == 0xAA55) &&
40 (((mbr
.pcpt
[0].status
& 0x0F)==0) || (mbr
.pcpt
[0].status
& 0x80)) &&
41 (((mbr
.pcpt
[1].status
& 0x0F)==0) || (mbr
.pcpt
[1].status
& 0x80)) &&
42 (((mbr
.pcpt
[2].status
& 0x0F)==0) || (mbr
.pcpt
[2].status
& 0x80)) &&
43 (((mbr
.pcpt
[3].status
& 0x0F)==0) || (mbr
.pcpt
[3].status
& 0x80))
56 static struct PartitionHandle
*PartitionMBRNewHandle
58 struct Library
*PartitionBase
,
59 struct PartitionHandle
*root
,
61 struct PCPartitionTable
*entry
64 struct PartitionHandle
*ph
;
67 if (entry
->first_sector
!= 0)
69 ph
= AllocMem(sizeof(struct PartitionHandle
), MEMF_PUBLIC
| MEMF_CLEAR
);
74 data
= AllocMem(sizeof(struct MBRData
), MEMF_PUBLIC
);
77 cylsecs
= root
->de
.de_BlocksPerTrack
*root
->de
.de_Surfaces
;
79 data
->position
= position
;
84 /* initialize DosEnvec */
86 /* Check if partition starts and ends on a cylinder boundary */
87 CopyMem(&root
->de
, &ph
->de
, sizeof(struct DosEnvec
));
89 (AROS_LE2LONG(data
->entry
->first_sector
) % cylsecs
!= 0) ||
90 (AROS_LE2LONG(data
->entry
->count_sector
) % cylsecs
!= 0)
93 /* Treat each track as a cylinder if possible */
94 ph
->de
.de_Surfaces
= 1;
95 cylsecs
= ph
->de
.de_BlocksPerTrack
*ph
->de
.de_Surfaces
;
97 (AROS_LE2LONG(data
->entry
->first_sector
) % cylsecs
!= 0) ||
98 (AROS_LE2LONG(data
->entry
->count_sector
) % cylsecs
!= 0)
101 /* We can't. We could find the highest common factor of
102 first_sector and count_sector here, but currently we
103 simply use one block per cylinder */
104 ph
->de
.de_BlocksPerTrack
= 1;
105 cylsecs
= ph
->de
.de_BlocksPerTrack
*ph
->de
.de_Surfaces
;
108 ph
->de
.de_LowCyl
= AROS_LE2LONG(data
->entry
->first_sector
) / cylsecs
;
111 (AROS_LE2LONG(data
->entry
->count_sector
)/cylsecs
)-1;
112 ph
->de
.de_TableSize
= 10; // only until de_HighCyl
113 ph
->ln
.ln_Pri
= MBR_MAX_PARTITIONS
-1-position
;
115 /* initialize DriveGeometry */
116 ph
->dg
.dg_DeviceType
= DG_DIRECT_ACCESS
;
117 ph
->dg
.dg_SectorSize
= ph
->de
.de_SizeBlock
<<2;
118 ph
->dg
.dg_Heads
= ph
->de
.de_Surfaces
;
119 ph
->dg
.dg_TrackSectors
= ph
->de
.de_BlocksPerTrack
;
120 ph
->dg
.dg_Cylinders
= ph
->de
.de_HighCyl
- ph
->de
.de_LowCyl
+ 1;
121 ph
->dg
.dg_BufMemType
= ph
->de
.de_BufMemType
;
124 FreeMem(ph
, sizeof(struct PartitionHandle
));
130 static LONG PartitionMBROpenPartitionTable
132 struct Library
*PartitionBase
,
133 struct PartitionHandle
*root
136 struct PartitionHandle
*ph
;
140 mbr
= AllocMem(root
->de
.de_SizeBlock
<<2, MEMF_PUBLIC
);
143 if (readBlock(PartitionBase
, root
, 0, mbr
) == 0)
145 NEWLIST(&root
->table
->list
);
146 root
->table
->data
= mbr
;
149 ph
= PartitionMBRNewHandle(PartitionBase
, root
, i
, &mbr
->pcpt
[i
]);
151 Enqueue(&root
->table
->list
, &ph
->ln
);
155 FreeMem(mbr
, root
->de
.de_SizeBlock
<<2);
160 static void PartitionMBRFreeHandle
162 struct Library
*PartitionBase
,
163 struct PartitionHandle
*ph
166 ClosePartitionTable(ph
);
167 FreeMem(ph
->data
, sizeof(struct MBRData
));
168 FreeMem(ph
, sizeof(struct PartitionHandle
));
171 static void PartitionMBRClosePartitionTable
173 struct Library
*PartitionBase
,
174 struct PartitionHandle
*root
177 struct PartitionHandle
*ph
;
179 while ((ph
= (struct PartitionHandle
*)RemTail(&root
->table
->list
)))
180 PartitionMBRFreeHandle(PartitionBase
, ph
);
181 FreeMem(root
->table
->data
, root
->de
.de_SizeBlock
<<2);
184 static LONG PartitionMBRWritePartitionTable
186 struct Library
*PartitionBase
,
187 struct PartitionHandle
*root
190 #warning "FIXME: readBlock(0) and synchronize data"
192 /* root->data = mbr is up to date */
193 if (writeBlock(PartitionBase
, root
, 0, root
->table
->data
))
198 static LONG PartitionMBRCreatePartitionTable
200 struct Library
*PartitionBase
,
201 struct PartitionHandle
*ph
206 mbr
= AllocMem(ph
->de
.de_SizeBlock
<<2, MEMF_PUBLIC
);
209 if (readBlock(PartitionBase
, ph
, 0, mbr
) == 0)
211 ph
->table
->data
= mbr
;
212 fillMem((BYTE
*)mbr
->pcpt
, sizeof(mbr
->pcpt
), 0);
213 mbr
->magic
= AROS_WORD2LE(0xAA55);
214 NEWLIST(&ph
->table
->list
);
217 FreeMem(mbr
, ph
->de
.de_SizeBlock
<<2);
222 void PartitionMBRSetGeometry
224 struct PartitionHandle
*root
,
225 struct PCPartitionTable
*entry
,
228 ULONG relative_sector
234 /* Store LBA start block and block count */
236 entry
->first_sector
= AROS_LONG2LE(sector
- relative_sector
);
237 entry
->count_sector
= AROS_LONG2LE(count
);
239 /* Store CHS-address of start block. The upper two bits of the cylinder
240 number are stored in the upper two bits of the sector field */
242 track
= sector
/root
->de
.de_BlocksPerTrack
;
243 cyl
= track
/root
->de
.de_Surfaces
;
246 entry
->start_head
= track
% root
->de
.de_Surfaces
;
247 entry
->start_sector
=
248 ((sector
% root
->de
.de_BlocksPerTrack
) + 1)
249 | ((cyl
& 0x300) >> 2);
250 entry
->start_cylinder
= (cyl
& 0xFF);
254 entry
->start_head
= 0xFE;
255 entry
->start_sector
= 0xFF;
256 entry
->start_cylinder
= 0xFF;
259 /* Store CHS-address of last block */
262 track
= sector
/root
->de
.de_BlocksPerTrack
;
263 cyl
= track
/root
->de
.de_Surfaces
;
266 entry
->end_head
= track
% root
->de
.de_Surfaces
;
267 entry
->end_sector
= ((sector
% root
->de
.de_BlocksPerTrack
) + 1)
268 | ((cyl
& 0x300)>>2);
269 entry
->end_cylinder
= (cyl
& 0xFF);
273 entry
->end_head
= 0xFE;
274 entry
->end_sector
= 0xFF;
275 entry
->end_cylinder
= 0xFF;
279 static void PartitionMBRSetDosEnvec
281 struct PartitionHandle
*root
,
282 struct PCPartitionTable
*entry
,
288 sector
= de
->de_LowCyl
* de
->de_Surfaces
* de
->de_BlocksPerTrack
;
289 count
= (de
->de_HighCyl
- de
->de_LowCyl
+ 1) *
291 de
->de_BlocksPerTrack
;
292 PartitionMBRSetGeometry(root
, entry
, sector
, count
, 0);
295 static struct PartitionHandle
*PartitionMBRAddPartition
297 struct Library
*PartitionBase
,
298 struct PartitionHandle
*root
,
299 struct TagItem
*taglist
304 tag
= findTagItem(PT_DOSENVEC
, taglist
);
307 struct PCPartitionTable
*entry
;
308 struct PartitionHandle
*ph
;
312 de
= (struct DosEnvec
*)tag
->ti_Data
;
313 tag
= findTagItem(PT_POSITION
, taglist
);
318 // Find an unused slot
319 for (i
= 0; i
< MBR_MAX_PARTITIONS
&& pos
== -1; i
++)
321 entry
= &((struct MBR
*)root
->table
->data
)->pcpt
[i
];
322 if (entry
->type
== 0)
329 entry
= &((struct MBR
*)root
->table
->data
)->pcpt
[pos
];
330 tag
= findTagItem(PT_ACTIVE
, taglist
);
332 entry
->status
= tag
->ti_Data
? 0x80 : 0;
335 tag
= findTagItem(PT_TYPE
, taglist
);
338 struct PartitionType
*ptype
= (struct PartitionType
*)tag
->ti_Data
;
340 entry
->type
= ptype
->id
[0];
344 PartitionMBRSetDosEnvec(root
, entry
, de
);
345 ph
= PartitionMBRNewHandle(PartitionBase
, root
, pos
, entry
);
347 Enqueue(&root
->table
->list
, &ph
->ln
);
349 fillMem((BYTE
*)entry
, sizeof(struct PCPartitionTable
), 0);
356 static void PartitionMBRDeletePartition
358 struct Library
*PartitionBase
,
359 struct PartitionHandle
*ph
362 struct MBRData
*data
;
364 data
= (struct MBRData
*)ph
->data
;
365 fillMem((BYTE
*)data
->entry
, sizeof(struct PCPartitionTable
), 0);
367 PartitionMBRFreeHandle(PartitionBase
, ph
);
370 static LONG PartitionMBRGetPartitionTableAttrs
372 struct Library
*PartitionBase
,
373 struct PartitionHandle
*root
,
374 struct TagItem
*taglist
378 while (taglist
[0].ti_Tag
!= TAG_DONE
)
381 switch (taglist
[0].ti_Tag
)
384 *((LONG
*)taglist
[0].ti_Data
) = root
->table
->type
;
387 *((LONG
*)taglist
[0].ti_Data
) =
388 root
->de
.de_BlocksPerTrack
; /* One track */
390 case PTT_MAX_PARTITIONS
:
391 *((LONG
*)taglist
[0].ti_Data
) = MBR_MAX_PARTITIONS
;
398 static LONG PartitionMBRSetPartitionTableAttrs
400 struct Library
*PartitionBase
,
401 struct PartitionHandle
*root
,
402 struct TagItem
*taglist
406 while (taglist
[0].ti_Tag
!= TAG_DONE
)
409 switch (taglist
[0].ti_Tag
)
417 static LONG PartitionMBRGetPartitionAttrs
419 struct Library
*PartitionBase
,
420 struct PartitionHandle
*ph
,
421 struct TagItem
*taglist
425 while (taglist
[0].ti_Tag
!= TAG_DONE
)
427 struct MBRData
*data
= (struct MBRData
*)ph
->data
;
429 switch (taglist
[0].ti_Tag
)
433 struct DriveGeometry
*dg
= (struct DriveGeometry
*)taglist
[0].ti_Data
;
434 CopyMem(&ph
->dg
, dg
, sizeof(struct DriveGeometry
));
438 CopyMem(&ph
->de
, (struct DosEnvec
*)taglist
[0].ti_Data
, sizeof(struct DosEnvec
));
442 struct PartitionType
*ptype
=(struct PartitionType
*)taglist
[0].ti_Data
;
444 ptype
->id
[0] = (LONG
)data
->entry
->type
;
449 *((LONG
*)taglist
[0].ti_Data
) = (LONG
)data
->position
;
452 *((LONG
*)taglist
[0].ti_Data
) = data
->entry
->status
& 0x80 ? 1 : 0;
460 static LONG PartitionMBRSetPartitionAttrs
462 struct Library
*PartitionBase
,
463 struct PartitionHandle
*ph
,
464 struct TagItem
*taglist
468 while (taglist
[0].ti_Tag
!= TAG_DONE
)
470 struct MBRData
*data
= (struct MBRData
*)ph
->data
;
472 switch (taglist
[0].ti_Tag
)
477 de
= (struct DosEnvec
*)taglist
[0].ti_Data
;
478 CopyMem(de
, &ph
->de
, sizeof(struct DosEnvec
));
479 PartitionMBRSetDosEnvec(ph
->root
, data
->entry
, de
);
484 struct PartitionType
*ptype
=(struct PartitionType
*)taglist
[0].ti_Data
;
486 data
->entry
->type
= ptype
->id
[0];
490 if (taglist
[0].ti_Data
!= data
->position
)
492 struct PartitionHandle
*node
;
493 struct PCPartitionTable
*entry
;
495 node
= (struct PartitionHandle
*)ph
->root
->table
->list
.lh_Head
;
496 while (node
->ln
.ln_Succ
)
498 if (taglist
[0].ti_Data
== ((struct MBRData
*)node
->data
)->position
)
500 node
= (struct PartitionHandle
*)node
->ln
.ln_Succ
;
502 data
->position
= taglist
[0].ti_Data
;
503 entry
= &((struct MBR
*)ph
->root
->table
->data
)->pcpt
[data
->position
];
504 CopyMem(data
->entry
, entry
, sizeof(struct PCPartitionTable
));
505 fillMem((BYTE
*)data
->entry
, sizeof(struct PCPartitionTable
), 0);
507 ph
->ln
.ln_Pri
= MBR_MAX_PARTITIONS
-1-data
->position
;
509 Enqueue(&ph
->root
->table
->list
, &ph
->ln
);
515 if (taglist
[0].ti_Data
)
516 data
->entry
->status
|= 0x80;
518 data
->entry
->status
&= ~0x80;
526 static struct PartitionAttribute PartitionMBRPartitionTableAttrs
[]=
528 {PTTA_TYPE
, PLAM_READ
},
529 {PTTA_RESERVED
, PLAM_READ
},
530 {PTTA_MAX_PARTITIONS
, PLAM_READ
},
534 static struct PartitionAttribute
*PartitionMBRQueryPartitionTableAttrs(struct Library
*PartitionBase
)
536 return PartitionMBRPartitionTableAttrs
;
539 static struct PartitionAttribute PartitionMBRPartitionAttrs
[]=
541 {PTA_GEOMETRY
, PLAM_READ
},
542 {PTA_TYPE
, PLAM_READ
| PLAM_WRITE
},
543 {PTA_POSITION
, PLAM_READ
| PLAM_WRITE
},
544 {PTA_ACTIVE
, PLAM_READ
| PLAM_WRITE
},
548 struct PartitionAttribute
*PartitionMBRQueryPartitionAttrs(struct Library
*PartitionBase
)
550 return PartitionMBRPartitionAttrs
;
553 static ULONG PartitionMBRDestroyPartitionTable
555 struct Library
*PartitionBase
,
556 struct PartitionHandle
*root
561 mbr
= root
->table
->data
;
562 fillMem((BYTE
*)mbr
->pcpt
, sizeof(mbr
->pcpt
), 0);
563 if (writeBlock(PartitionBase
, root
, 0, root
->table
->data
))
568 struct PTFunctionTable PartitionMBR
=
572 PartitionMBRCheckPartitionTable
,
573 PartitionMBROpenPartitionTable
,
574 PartitionMBRClosePartitionTable
,
575 PartitionMBRWritePartitionTable
,
576 PartitionMBRCreatePartitionTable
,
577 PartitionMBRAddPartition
,
578 PartitionMBRDeletePartition
,
579 PartitionMBRGetPartitionTableAttrs
,
580 PartitionMBRSetPartitionTableAttrs
,
581 PartitionMBRGetPartitionAttrs
,
582 PartitionMBRSetPartitionAttrs
,
583 PartitionMBRQueryPartitionTableAttrs
,
584 PartitionMBRQueryPartitionAttrs
,
585 PartitionMBRDestroyPartitionTable