2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
5 Desc: Find and mount partitions.
14 #include <exec/lists.h>
15 #include <exec/memory.h>
16 #include <exec/types.h>
17 #include <libraries/partition.h>
18 #include <utility/tagitem.h>
19 #include <devices/bootblock.h>
20 #include <devices/timer.h>
22 #include <proto/exec.h>
23 #include <proto/expansion.h>
24 #include <proto/partition.h>
25 #include <proto/bootloader.h>
27 #include <aros/debug.h>
28 #include <aros/macros.h>
30 #include "massstorage.h"
31 #include "massstorage.class.h"
33 #define PartitionBase ncm->ncm_ClsBase->nh_PartitionBase
34 #define ExpansionBase ncm->ncm_ClsBase->nh_ExpansionBase
36 #define uppercase(x) ((x >= 'a' && x <= 'z') ? (x & 0xdf) : x)
38 static const struct _dt
{
42 { 0xffffffff, AROS_MAKE_ID('B','E','F','S' ), "befs-handler" },
43 { 0xffffff00, AROS_MAKE_ID('B','S','D','\0'), "bsd-handler" },
44 { 0xffffff00, AROS_MAKE_ID('C','P','M','\0'), "cpm-handler" },
45 { 0xffffff00, AROS_MAKE_ID('D','O','S','\0'), "afs-handler" },
46 { 0xffffff00, AROS_MAKE_ID('E','X','T','\0'), "ext-handler" },
47 { 0xffffff00, AROS_MAKE_ID('F','A','T','\0'), "fat-handler" },
48 { 0xffffff00, AROS_MAKE_ID('L','V','M','\0'), "lvm-handler" },
49 { 0xffffff00, AROS_MAKE_ID('M','N','X','\0'), "minix-handler" },
50 { 0xffffffff, AROS_MAKE_ID('N','T','F','S' ), "ntfs-handler" },
51 { 0xffffffff, AROS_MAKE_ID('R','A','I','D' ), "raid-handler" },
52 { 0xffffff00, AROS_MAKE_ID('S','F','S','\0'), "sfs-handler" },
53 { 0xffffff00, AROS_MAKE_ID('S','K','Y','\0'), "skyfs-handler" },
54 { 0xffffffff, AROS_MAKE_ID('V','F','A','T' ), "fat-handler" },
58 static const struct _pt
{
61 { 0x01, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 12-bit FAT */
62 { 0x04, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 16-bit FAT (up to 32M) */
63 { 0x06, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 16-bit FAT (over 32M) */
64 { 0x07, AROS_MAKE_ID('N','T','F','S') }, /* Windows NT NTFS */
65 { 0x0b, AROS_MAKE_ID('V','F','A','T') }, /* W95 FAT32 */
66 { 0x0c, AROS_MAKE_ID('V','F','A','T') }, /* W95 LBA FAT32 */
67 { 0x0e, AROS_MAKE_ID('F','A','T',' ') }, /* W95 16-bit LBA FAT */
68 { 0x2c, AROS_MAKE_ID('D','O','S','\0') }, /* AOS OFS */
69 { 0x2d, AROS_MAKE_ID('D','O','S','\1') }, /* AOS FFS */
70 { 0x2e, AROS_MAKE_ID('D','O','S','\3') }, /* AOS FFS-I */
71 { 0x2f, AROS_MAKE_ID('S','F','S','\0') }, /* AOS SFS */
72 { 0x80, AROS_MAKE_ID('M','N','X','\0') }, /* MINIX until 1.4a */
73 { 0x81, AROS_MAKE_ID('M','N','X','\1') }, /* MINIX since 1.4b */
74 { 0x83, AROS_MAKE_ID('E','X','T','\2') }, /* linux native partition */
75 { 0x8e, AROS_MAKE_ID('L','V','M','\0') }, /* linux LVM partition */
76 { 0x9f, AROS_MAKE_ID('B','S','D','\0') }, /* BSD/OS */
77 { 0xa5, AROS_MAKE_ID('B','S','D','\1') }, /* NetBSD, FreeBSD */
78 { 0xa6, AROS_MAKE_ID('B','S','D','\2') }, /* OpenBSD */
79 { 0xdb, AROS_MAKE_ID('C','P','M','\2') }, /* CPM/M */
80 { 0xeb, AROS_MAKE_ID('B','E','F','S') }, /* BeOS FS */
81 { 0xec, AROS_MAKE_ID('S','K','Y','\0') }, /* SkyOS FS */
82 { 0xfd, AROS_MAKE_ID('R','A','I','D') }, /* linux RAID with autodetect */
86 static STRPTR
MatchHandler(IPTR DosType
)
91 for (i
= 0; i
< (sizeof(DosTypes
) / sizeof(struct _dt
)); i
++)
93 if ((DosType
& DosTypes
[i
].mask
) == DosTypes
[i
].type
)
102 static IPTR
MatchPartType(UBYTE PartType
)
107 for (i
= 0; i
< (sizeof(PartTypes
) / sizeof(struct _pt
)); i
++)
109 if ((IPTR
)PartType
== PartTypes
[i
].part
)
111 type
= PartTypes
[i
].type
;
118 static ULONG
GetOffset(struct NepClassMS
*ncm
,
119 struct PartitionHandle
*ph
)
125 tags
[0] = PT_DOSENVEC
;
131 GetPartitionAttrs(ph
, (struct TagItem
*)tags
);
132 offset
+= de
.de_LowCyl
* de
.de_Surfaces
* de
.de_BlocksPerTrack
;
138 static VOID
AddPartitionVolume(struct NepClassMS
*ncm
,
139 struct FileSysStartupMsg
*fssm
,
140 struct PartitionHandle
*table
,
141 struct PartitionHandle
*pn
)
144 ULONG i
, blockspercyl
;
145 const struct PartitionAttribute
*attrs
;
148 struct DeviceNode
*devnode
;
149 struct PartitionType ptyp
;
151 TEXT
*devname
, *handler
;
154 D(bug("[Boot] AddPartitionVolume\n"));
155 pp
= AllocVec(sizeof(struct DosEnvec
) + sizeof(IPTR
) * 4,
156 MEMF_PUBLIC
| MEMF_CLEAR
);
159 attrs
= QueryPartitionAttrs(table
);
160 while ((attrs
->attribute
!= PTA_DONE
) && (attrs
->attribute
!= PTA_NAME
))
161 attrs
++; /* look for name attr */
162 if (attrs
->attribute
!= PTA_DONE
)
164 D(bug("[Boot] RDB partition\n"));
165 /* partition has a name => RDB partition */
167 tags
[1] = (IPTR
)name
;
168 tags
[2] = PT_DOSENVEC
;
169 tags
[3] = (IPTR
)&pp
[4];
170 tags
[4] = PT_BOOTABLE
;
171 tags
[5] = (IPTR
)&bootable
;
173 GetPartitionAttrs(pn
, (struct TagItem
*)tags
);
174 D(bug("[Boot] Partition name: %s bootable: %d\n", name
, bootable
));
175 /* BHFormat complains if this bit is not set, and it's really wrong to have it unset. So we explicitly set it here.
176 Pavel Fedin <sonic_amiga@rambler.ru> */
177 pp
[4 + DE_TABLESIZE
] = DE_BOOTBLOCKS
;
178 pp
[4 + DE_BUFMEMTYPE
] |= MEMF_PUBLIC
;
182 D(bug("[Boot] MBR partition\n"));
183 /* partition doesn't have a name => MBR partition */
184 tags
[0] = PT_POSITION
;
185 tags
[1] = (IPTR
)&ppos
;
187 tags
[3] = (IPTR
)&ptyp
;
188 tags
[4] = PT_DOSENVEC
;
189 tags
[5] = (IPTR
)&pp
[4];
191 GetPartitionAttrs(pn
, (struct TagItem
*)tags
);
195 devname
= AROS_BSTR_ADDR(fssm
->fssm_Device
);
196 for (i
= 0; i
< 26; i
++)
198 if (*devname
== '.' || *devname
== '\0')
200 name
[i
] = (UBYTE
)uppercase(*devname
);
203 if ((fssm
->fssm_Unit
/ 10))
204 name
[i
++] = '0' + (UBYTE
)(fssm
->fssm_Unit
/ 10);
205 name
[i
++] = '0' + (UBYTE
)(fssm
->fssm_Unit
% 10);
207 if (table
->table
->type
== PHPTT_EBR
)
210 name
[i
++] = '0' + (UBYTE
)(ppos
/ 10);
211 name
[i
++] = '0' + (UBYTE
)(ppos
% 10);
213 D(bug("[Boot] Partition name: %s type: %lu bootable: %d\n", name
, ptyp
.id
[0], bootable
));
214 /* set DOSTYPE based on the partition type */
215 pp
[4 + DE_DOSTYPE
] = MatchPartType(ptyp
.id
[0]);
216 /* set some common DOSENV fields */
217 pp
[4 + DE_TABLESIZE
] = DE_BOOTBLOCKS
;
218 pp
[4 + DE_NUMBUFFERS
] = 20;
219 pp
[4 + DE_BUFMEMTYPE
] = MEMF_PUBLIC
;
220 pp
[4 + DE_MAXTRANSFER
] = 0x00200000;
221 pp
[4 + DE_MASK
] = 0x7ffffffe;
222 /* set some fs specific fields */
227 case 0x2e: /* FFS I */
229 pp
[4 + DE_SECSPERBLOCK
] = 1;
230 pp
[4 + DE_RESERVEDBLKS
] = 2;
231 pp
[4 + DE_BOOTBLOCKS
] = 2;
237 pp
[1] = (IPTR
)AROS_BSTR_ADDR(fssm
->fssm_Device
);
238 pp
[2] = fssm
->fssm_Unit
;
239 pp
[3] = fssm
->fssm_Flags
;
240 i
= GetOffset(ncm
, pn
);
241 blockspercyl
= pp
[4 + DE_BLKSPERTRACK
] * pp
[4 + DE_NUMHEADS
];
242 if (i
% blockspercyl
!= 0)
244 D(bug("[Boot] Start block of subtable not on cylinder boundary: "
245 "%ld (Blocks per Cylinder = %ld)\n", i
, blockspercyl
));
249 pp
[4 + DE_LOWCYL
] += i
;
250 pp
[4 + DE_HIGHCYL
] += i
;
252 D(bug("[Boot] Looking up handler for 0x%08lX\n", pp
[4+DE_DOSTYPE
]));
253 handler
= MatchHandler(pp
[4 + DE_DOSTYPE
]);
255 /* Skip unknown partition types */
258 D(bug("[Boot] found handler: %s\n", handler
));
259 devnode
= MakeDosNode(pp
);
262 devnode
->dn_Handler
= MKBADDR(AllocVec(AROS_BSTR_MEMSIZE4LEN(
263 strlen(handler
)), MEMF_PUBLIC
| MEMF_CLEAR
));
264 if (devnode
->dn_Handler
)
267 while (handler
[i
] != '\0')
269 AROS_BSTR_putchar(devnode
->dn_Handler
, i
, handler
[i
]);
272 AROS_BSTR_setstrlen(devnode
->dn_Handler
, i
);
273 AddBootNode(bootable
? pp
[4 + DE_BOOTPRI
] : -128, ADNF_STARTPROC
, devnode
, NULL
);
274 D(bug("[Boot] AddBootNode(%b, 0, 0x%p, NULL)\n",
275 devnode
->dn_Name
, pp
[4 + DE_DOSTYPE
]));
284 static BOOL
CheckTables(struct NepClassMS
*ncm
,
285 struct FileSysStartupMsg
*fssm
,
286 struct PartitionHandle
*table
)
289 struct PartitionHandle
*ph
;
291 /* Traverse partition tables recursively, and attempt to add a BootNode
292 for any non-subtable partitions found */
293 if (OpenPartitionTable(table
) == 0)
295 ph
= (struct PartitionHandle
*)table
->table
->list
.lh_Head
;
296 while (ph
->ln
.ln_Succ
)
298 /* Attempt to add partition to system if it isn't a subtable */
299 if (!CheckTables(ncm
, fssm
, ph
))
300 AddPartitionVolume(ncm
, fssm
, table
, ph
);
301 ph
= (struct PartitionHandle
*)ph
->ln
.ln_Succ
;
304 ClosePartitionTable(table
);
309 BOOL
CheckPartitions(struct NepClassMS
*ncm
)
312 struct PartitionHandle
*pt
;
313 struct FileSysStartupMsg fssm
;
315 pt
= OpenRootPartition(DEVNAME
, ncm
->ncm_UnitNo
);
318 fssm
.fssm_Device
= AROS_CONST_BSTR(DEVNAME
);
319 fssm
.fssm_Unit
= ncm
->ncm_UnitNo
;
322 found
= CheckTables(ncm
, &fssm
, pt
);
323 CloseRootPartition(pt
);