- Removed unused HandleEvent method.
[AROS.git] / rom / partition / partitionmbr.c
blob2000428222631257d9394eff6fd66d2f9367ec6d
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 */
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"
17 #include "platform.h"
18 #include "debug.h"
20 struct MBRData {
21 struct PCPartitionTable *entry;
22 UBYTE position;
25 struct FATBootSector {
26 UBYTE bs_jmp_boot[3];
27 UBYTE bs_oem_name[8];
28 UWORD bpb_bytes_per_sect;
29 UBYTE bpb_sect_per_clust;
30 UWORD bpb_rsvd_sect_count;
31 UBYTE bpb_num_fats;
32 UWORD bpb_root_entries_count;
33 UWORD bpb_total_sectors_16;
34 UBYTE bpb_media;
35 UWORD bpb_fat_size_16;
36 UWORD bpb_sect_per_track;
37 UWORD bpb_num_heads;
38 ULONG bpb_hidden_sect;
39 ULONG bpb_total_sectors_32;
41 union {
42 struct {
43 UBYTE bs_drvnum;
44 UBYTE bs_reserved1;
45 UBYTE bs_bootsig;
46 ULONG bs_volid;
47 UBYTE bs_vollab[11];
48 UBYTE bs_filsystype[8];
49 } __attribute__ ((__packed__)) fat16;
51 struct {
52 ULONG bpb_fat_size_32;
53 UWORD bpb_extflags;
54 UWORD bpb_fs_verion;
55 ULONG bpb_root_cluster;
56 UWORD bpb_fs_info;
57 UWORD bpb_back_bootsec;
58 UBYTE bpb_reserved[12];
59 UBYTE bs_drvnum;
60 UBYTE bs_reserved1;
61 UBYTE bs_bootsig;
62 ULONG bs_volid;
63 UBYTE bs_vollab[11];
64 UBYTE bs_filsystype[8];
65 } __attribute__ ((__packed__)) fat32;
66 } type;
67 UBYTE pad[420];
68 UBYTE bpb_signature[2];
69 } __attribute__ ((__packed__));
71 struct rootblock
73 union
75 struct MBR mbr;
76 struct FATBootSector bs;
81 LONG MBRCheckPartitionTable(struct Library *PartitionBase, struct PartitionHandle *root, void *buffer)
83 struct rootblock *blk = buffer;
84 LONG res = 0;
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)
94 res = 1;
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)
99 res = 1;
101 /* Valid cluster size: 512, 1024, 2048, 4096, 8192, 16k, 32k, 64k */
102 if (clustersectors * sectorsize > 64 * 1024)
103 res = 1;
105 if (blk->u.bs.bpb_media < 0xF0)
106 res = 1;
108 if (res)
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)))
117 res = 0;
122 return res;
125 static LONG PartitionMBRCheckPartitionTable(struct Library *PartitionBase, struct PartitionHandle *root)
127 LONG res;
128 void *blk;
130 /* MBR can be placed only in the root of the disk */
131 if (root->root)
132 return 0;
134 blk = AllocMem(root->de.de_SizeBlock << 2, MEMF_ANY);
135 if (!blk)
136 return 0;
138 res = MBRCheckPartitionTable(PartitionBase, root, blk);
140 FreeMem(blk, root->de.de_SizeBlock << 2);
141 return res;
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);
151 if (ph)
153 struct MBRData *data;
155 data = AllocMem(sizeof(struct MBRData), MEMF_PUBLIC);
156 if (data)
158 data->entry = entry;
159 data->position = position;
160 ph->data = data;
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;
170 return ph;
172 FreeMem(ph, sizeof(struct PartitionHandle));
175 return NULL;
178 static LONG PartitionMBROpenPartitionTable(struct Library *PartitionBase, struct PartitionHandle *root)
180 struct PartitionHandle *ph;
181 struct MBR *mbr;
182 UBYTE i;
184 mbr = AllocMem(root->de.de_SizeBlock<<2, MEMF_PUBLIC);
185 if (mbr)
187 if (readBlock(PartitionBase, root, 0, mbr) == 0)
189 root->table->data = mbr;
190 for (i=0;i<4;i++)
192 ph = PartitionMBRNewHandle(PartitionBase, root, i, &mbr->pcpt[i]);
193 if (ph != NULL)
194 Enqueue(&root->table->list, &ph->ln);
196 return 0;
198 FreeMem(mbr, root->de.de_SizeBlock<<2);
200 return 1;
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))
237 return 1;
238 return 0;
241 static LONG PartitionMBRCreatePartitionTable
243 struct Library *PartitionBase,
244 struct PartitionHandle *ph
247 struct MBR *mbr;
249 mbr = AllocMem(ph->de.de_SizeBlock<<2, MEMF_PUBLIC);
250 if (mbr)
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);
260 return 0;
262 FreeMem(mbr, ph->de.de_SizeBlock<<2);
264 return 1;
267 void PartitionMBRSetGeometry
269 struct PartitionHandle *root,
270 struct PCPartitionTable *entry,
271 ULONG sector,
272 ULONG count,
273 ULONG relative_sector
276 ULONG track;
277 ULONG cyl;
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;
289 if (cyl<1024)
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);
297 else
299 entry->start_head = 0xFE;
300 entry->start_sector = 0xFF;
301 entry->start_cylinder = 0xFF;
304 /* Store CHS-address of last block */
306 sector += count - 1;
307 track = sector/root->de.de_BlocksPerTrack;
308 cyl = track/root->de.de_Surfaces;
309 if (cyl<1024)
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);
316 else
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,
328 struct DosEnvec *de
331 ULONG sector, count;
333 sector = de->de_LowCyl * de->de_Surfaces * de->de_BlocksPerTrack;
334 count = (de->de_HighCyl - de->de_LowCyl + 1) *
335 de->de_Surfaces *
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)
342 struct TagItem *tag;
344 tag = FindTagItem(PT_DOSENVEC, taglist);
346 if (tag)
348 struct PCPartitionTable *entry;
349 struct PartitionHandle *ph;
350 struct DosEnvec *de = (struct DosEnvec *)tag->ti_Data;
351 WORD pos = -1, i;
353 tag = FindTagItem(PT_POSITION, taglist);
354 if (tag != NULL)
355 pos = tag->ti_Data;
356 else
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)
363 pos = i;
367 if (pos != -1)
369 entry = &((struct MBR *)root->table->data)->pcpt[pos];
370 tag = FindTagItem(PT_ACTIVE, taglist);
371 if (tag)
372 entry->status = tag->ti_Data ? 0x80 : 0;
373 else
374 entry->status = 0;
375 tag = FindTagItem(PT_TYPE, taglist);
376 if (tag)
378 struct PartitionType *ptype = (struct PartitionType *)tag->ti_Data;
380 entry->type = ptype->id[0];
382 else
383 entry->type = 0;
384 PartitionMBRSetDosEnvec(root, entry, de);
385 ph = PartitionMBRNewHandle(PartitionBase, root, pos, entry);
386 if (ph != NULL)
387 Enqueue(&root->table->list, &ph->ln);
388 else
389 memset(entry, 0, sizeof(struct PCPartitionTable));
391 return ph;
394 return NULL;
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));
403 Remove(&ph->ln);
404 PartitionMBRFreeHandle(PartitionBase, ph);
407 static LONG PartitionMBRGetPartitionTableAttr(struct Library *PartitionBase, struct PartitionHandle *root, 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, struct PartitionHandle *ph, struct TagItem *tag)
425 struct MBRData *data = (struct MBRData *)ph->data;
427 switch (tag->ti_Tag)
429 case PT_TYPE:
430 PTYPE(tag->ti_Data)->id[0] = (LONG)data->entry->type;
431 PTYPE(tag->ti_Data)->id_len = 1;
432 return TRUE;
434 case PT_POSITION:
435 *((LONG *)tag->ti_Data) = (LONG)data->position;
436 return TRUE;
438 case PT_ACTIVE:
439 *((LONG *)tag->ti_Data) = data->entry->status & 0x80 ? 1 : 0;
440 return TRUE;
442 case PT_STARTBLOCK:
443 *((ULONG *)tag->ti_Data) = AROS_LE2LONG(data->entry->first_sector);
444 return TRUE;
446 case PT_ENDBLOCK:
447 *((ULONG *)tag->ti_Data) = AROS_LE2LONG(data->entry->first_sector) + AROS_LE2LONG(data->entry->count_sector) - 1;
448 return TRUE;
451 /* Everything else gets default values */
452 return 0;
455 static LONG PartitionMBRSetPartitionAttrs(struct Library *PartitionBase, struct PartitionHandle *ph, const struct TagItem *taglist)
457 struct MBRData *data = (struct MBRData *)ph->data;
458 struct TagItem *tag;
460 while ((tag = NextTagItem((struct TagItem **)&taglist)))
462 switch (tag->ti_Tag)
464 case PT_DOSENVEC:
465 CopyMem((struct DosEnvec *)tag->ti_Data, &ph->de, sizeof(struct DosEnvec));
466 PartitionMBRSetDosEnvec(ph->root, data->entry, (struct DosEnvec *)tag->ti_Data);
467 break;
469 case PT_TYPE:
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));
473 break;
475 case PT_POSITION:
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)
485 goto posbreak;
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));
492 data->entry = entry;
493 ph->ln.ln_Pri = MBR_MAX_PARTITIONS-1-data->position;
494 Remove(&ph->ln);
495 Enqueue(&ph->root->table->list, &ph->ln);
496 posbreak:
499 break;
501 case PT_ACTIVE:
502 if (tag->ti_Data)
503 data->entry->status |= 0x80;
504 else
505 data->entry->status &= ~0x80;
506 break;
509 return 0;
512 static const struct PartitionAttribute PartitionMBRPartitionTableAttrs[]=
514 {PTT_TYPE, PLAM_READ},
515 {PTT_RESERVED, PLAM_READ},
516 {PTT_MAX_PARTITIONS, PLAM_READ},
517 {TAG_DONE, 0}
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},
528 {TAG_DONE, 0}
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
539 mbr->magic = 0;
540 if (writeBlock(PartitionBase, root, 0, root->table->data))
541 return 1;
542 return 0;
545 const struct PTFunctionTable PartitionMBR =
547 PHPTT_MBR,
548 "PC-MBR",
549 PartitionMBRCheckPartitionTable,
550 PartitionMBROpenPartitionTable,
551 PartitionMBRClosePartitionTable,
552 PartitionMBRWritePartitionTable,
553 PartitionMBRCreatePartitionTable,
554 PartitionMBRAddPartition,
555 PartitionMBRDeletePartition,
556 PartitionMBRGetPartitionTableAttr,
557 NULL,
558 PartitionMBRGetPartitionAttr,
559 PartitionMBRSetPartitionAttrs,
560 PartitionMBRPartitionTableAttrs,
561 PartitionMBRPartitionAttrs,
562 PartitionMBRDestroyPartitionTable,
563 NULL