revert between 56095 -> 55830 in arch
[AROS.git] / rom / partition / partitionmbr.c
blob5333f7727306f84af6bbff242918fda6bdd99296
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
4 */
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"
16 #include "platform.h"
17 #include "debug.h"
19 struct MBRData {
20 struct PCPartitionTable *entry;
21 UBYTE position;
24 struct FATBootSector {
25 UBYTE bs_jmp_boot[3];
26 UBYTE bs_oem_name[8];
27 UWORD bpb_bytes_per_sect;
28 UBYTE bpb_sect_per_clust;
29 UWORD bpb_rsvd_sect_count;
30 UBYTE bpb_num_fats;
31 UWORD bpb_root_entries_count;
32 UWORD bpb_total_sectors_16;
33 UBYTE bpb_media;
34 UWORD bpb_fat_size_16;
35 UWORD bpb_sect_per_track;
36 UWORD bpb_num_heads;
37 ULONG bpb_hidden_sect;
38 ULONG bpb_total_sectors_32;
40 union {
41 struct {
42 UBYTE bs_drvnum;
43 UBYTE bs_reserved1;
44 UBYTE bs_bootsig;
45 ULONG bs_volid;
46 UBYTE bs_vollab[11];
47 UBYTE bs_filsystype[8];
48 } __packed fat16;
50 struct {
51 ULONG bpb_fat_size_32;
52 UWORD bpb_extflags;
53 UWORD bpb_fs_verion;
54 ULONG bpb_root_cluster;
55 UWORD bpb_fs_info;
56 UWORD bpb_back_bootsec;
57 UBYTE bpb_reserved[12];
58 UBYTE bs_drvnum;
59 UBYTE bs_reserved1;
60 UBYTE bs_bootsig;
61 ULONG bs_volid;
62 UBYTE bs_vollab[11];
63 UBYTE bs_filsystype[8];
64 } __packed fat32;
65 } type;
66 UBYTE pad[420];
67 UBYTE bpb_signature[2];
68 } __packed;
70 struct rootblock
72 union
74 struct MBR mbr;
75 struct FATBootSector bs;
80 LONG MBRCheckPartitionTable(struct Library *PartitionBase, struct PartitionHandle *root, void *buffer)
82 struct rootblock *blk = buffer;
83 LONG res = 0;
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)
93 res = 1;
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)
98 res = 1;
100 /* Valid cluster size: 512, 1024, 2048, 4096, 8192, 16k, 32k, 64k */
101 if (clustersectors * sectorsize > 64 * 1024)
102 res = 1;
104 if (blk->u.bs.bpb_media < 0xF0)
105 res = 1;
107 if (res)
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)))
116 res = 0;
121 return res;
124 static LONG PartitionMBRCheckPartitionTable(struct Library *PartitionBase, struct PartitionHandle *root)
126 LONG res;
127 void *blk;
129 /* MBR can be placed only in the root of the disk */
130 if (root->root)
131 return 0;
133 blk = AllocMem(root->de.de_SizeBlock << 2, MEMF_ANY);
134 if (!blk)
135 return 0;
137 res = MBRCheckPartitionTable(PartitionBase, root, blk);
139 FreeMem(blk, root->de.de_SizeBlock << 2);
140 return res;
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);
150 if (ph)
152 struct MBRData *data;
154 data = AllocMem(sizeof(struct MBRData), MEMF_PUBLIC);
155 if (data)
157 data->entry = entry;
158 data->position = position;
159 ph->data = data;
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;
169 return ph;
171 FreeMem(ph, sizeof(struct PartitionHandle));
174 return NULL;
177 static LONG PartitionMBROpenPartitionTable(struct Library *PartitionBase, struct PartitionHandle *root)
179 struct PartitionHandle *ph;
180 struct MBR *mbr;
181 UBYTE i;
183 mbr = AllocMem(root->de.de_SizeBlock<<2, MEMF_PUBLIC);
184 if (mbr)
186 if (readBlock(PartitionBase, root, 0, mbr) == 0)
188 root->table->data = mbr;
189 for (i=0;i<4;i++)
191 ph = PartitionMBRNewHandle(PartitionBase, root, i, &mbr->pcpt[i]);
192 if (ph != NULL)
193 Enqueue(&root->table->list, &ph->ln);
195 return 0;
197 FreeMem(mbr, root->de.de_SizeBlock<<2);
199 return 1;
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))
236 return 1;
237 return 0;
240 static LONG PartitionMBRCreatePartitionTable
242 struct Library *PartitionBase,
243 struct PartitionHandle *ph
246 struct MBR *mbr;
248 mbr = AllocMem(ph->de.de_SizeBlock<<2, MEMF_PUBLIC);
249 if (mbr)
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);
259 return 0;
261 FreeMem(mbr, ph->de.de_SizeBlock<<2);
263 return 1;
266 void PartitionMBRSetGeometry
268 struct PartitionHandle *root,
269 struct PCPartitionTable *entry,
270 ULONG sector,
271 ULONG count,
272 ULONG relative_sector
275 ULONG track;
276 ULONG cyl;
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;
288 if (cyl<1024)
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);
296 else
298 entry->start_head = 0xFE;
299 entry->start_sector = 0xFF;
300 entry->start_cylinder = 0xFF;
303 /* Store CHS-address of last block */
305 sector += count - 1;
306 track = sector/root->de.de_BlocksPerTrack;
307 cyl = track/root->de.de_Surfaces;
308 if (cyl<1024)
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);
315 else
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,
327 struct DosEnvec *de
330 ULONG sector, count;
332 sector = de->de_LowCyl * de->de_Surfaces * de->de_BlocksPerTrack;
333 count = (de->de_HighCyl - de->de_LowCyl + 1) *
334 de->de_Surfaces *
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)
341 struct TagItem *tag;
343 tag = FindTagItem(PT_DOSENVEC, taglist);
345 if (tag)
347 struct PCPartitionTable *entry;
348 struct PartitionHandle *ph;
349 struct DosEnvec *de = (struct DosEnvec *)tag->ti_Data;
350 WORD pos = -1, i;
352 tag = FindTagItem(PT_POSITION, taglist);
353 if (tag != NULL)
354 pos = tag->ti_Data;
355 else
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)
362 pos = i;
366 if (pos != -1)
368 entry = &((struct MBR *)root->table->data)->pcpt[pos];
369 tag = FindTagItem(PT_ACTIVE, taglist);
370 if (tag)
371 entry->status = tag->ti_Data ? 0x80 : 0;
372 else
373 entry->status = 0;
374 tag = FindTagItem(PT_TYPE, taglist);
375 if (tag)
377 struct PartitionType *ptype = (struct PartitionType *)tag->ti_Data;
379 entry->type = ptype->id[0];
381 else
382 entry->type = 0;
383 PartitionMBRSetDosEnvec(root, entry, de);
384 ph = PartitionMBRNewHandle(PartitionBase, root, pos, entry);
385 if (ph != NULL)
386 Enqueue(&root->table->list, &ph->ln);
387 else
388 memset(entry, 0, sizeof(struct PCPartitionTable));
390 return ph;
393 return NULL;
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));
402 Remove(&ph->ln);
403 PartitionMBRFreeHandle(PartitionBase, ph);
406 static LONG PartitionMBRGetPartitionTableAttr(struct Library *PartitionBase,
407 struct PartitionHandle *root, const struct TagItem *tag)
409 switch (tag->ti_Tag)
411 case PTT_RESERVED:
412 *((LONG *)tag->ti_Data) = root->de.de_BlocksPerTrack; /* One track */
413 return TRUE;
415 case PTT_MAX_PARTITIONS:
416 *((LONG *)tag->ti_Data) = MBR_MAX_PARTITIONS;
417 return TRUE;
420 return 0;
423 static LONG PartitionMBRGetPartitionAttr(struct Library *PartitionBase,
424 struct PartitionHandle *ph, const struct TagItem *tag)
426 struct MBRData *data = (struct MBRData *)ph->data;
428 switch (tag->ti_Tag)
430 case PT_TYPE:
431 PTYPE(tag->ti_Data)->id[0] = (LONG)data->entry->type;
432 PTYPE(tag->ti_Data)->id_len = 1;
433 return TRUE;
435 case PT_POSITION:
436 *((LONG *)tag->ti_Data) = (LONG)data->position;
437 return TRUE;
439 case PT_ACTIVE:
440 *((LONG *)tag->ti_Data) = data->entry->status & 0x80 ? 1 : 0;
441 return TRUE;
443 case PT_STARTBLOCK:
444 *((UQUAD *)tag->ti_Data) = AROS_LE2LONG(data->entry->first_sector);
445 return TRUE;
447 case PT_ENDBLOCK:
448 *((UQUAD *)tag->ti_Data) = AROS_LE2LONG(data->entry->first_sector) + AROS_LE2LONG(data->entry->count_sector) - 1;
449 return TRUE;
452 /* Everything else gets default values */
453 return 0;
456 static LONG PartitionMBRSetPartitionAttrs(struct Library *PartitionBase, struct PartitionHandle *ph, const struct TagItem *taglist)
458 struct MBRData *data = (struct MBRData *)ph->data;
459 struct TagItem *tag;
461 while ((tag = NextTagItem((struct TagItem **)&taglist)))
463 switch (tag->ti_Tag)
465 case PT_DOSENVEC:
466 CopyMem((struct DosEnvec *)tag->ti_Data, &ph->de, sizeof(struct DosEnvec));
467 PartitionMBRSetDosEnvec(ph->root, data->entry, (struct DosEnvec *)tag->ti_Data);
468 break;
470 case PT_TYPE:
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));
474 break;
476 case PT_POSITION:
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)
486 goto posbreak;
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));
493 data->entry = entry;
494 ph->ln.ln_Pri = MBR_MAX_PARTITIONS-1-data->position;
495 Remove(&ph->ln);
496 Enqueue(&ph->root->table->list, &ph->ln);
497 posbreak:
500 break;
502 case PT_ACTIVE:
503 if (tag->ti_Data)
504 data->entry->status |= 0x80;
505 else
506 data->entry->status &= ~0x80;
507 break;
510 return 0;
513 static const struct PartitionAttribute PartitionMBRPartitionTableAttrs[]=
515 {PTT_TYPE, PLAM_READ},
516 {PTT_RESERVED, PLAM_READ},
517 {PTT_MAX_PARTITIONS, PLAM_READ},
518 {TAG_DONE, 0}
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},
529 {TAG_DONE, 0}
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
541 mbr->magic = 0;
542 if (writeBlock(PartitionBase, root, 0, root->table->data))
543 return 1;
544 return 0;
547 const struct PTFunctionTable PartitionMBR =
549 PHPTT_MBR,
550 "PC-MBR",
551 PartitionMBRCheckPartitionTable,
552 PartitionMBROpenPartitionTable,
553 PartitionMBRClosePartitionTable,
554 PartitionMBRWritePartitionTable,
555 PartitionMBRCreatePartitionTable,
556 PartitionMBRAddPartition,
557 PartitionMBRDeletePartition,
558 PartitionMBRGetPartitionTableAttr,
559 NULL,
560 PartitionMBRGetPartitionAttr,
561 PartitionMBRSetPartitionAttrs,
562 PartitionMBRPartitionTableAttrs,
563 PartitionMBRPartitionAttrs,
564 PartitionMBRDestroyPartitionTable,
565 NULL