poseidon: Fix a number of BPTR issues
[AROS.git] / rom / usb / classes / massstorage / partitions.c
bloba014181ba1b93da40ed61cd7289faa574f767963
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Find and mount partitions.
6 Lang: English
7 */
9 #define DEBUG 0
11 #include <string.h>
12 #include <stdio.h>
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 {
39 IPTR mask,type;
40 STRPTR fs;
41 } DosTypes[] = {
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" },
55 { 0,0,NULL }
58 static const struct _pt {
59 IPTR part,type;
60 } PartTypes[] = {
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 */
83 { 0, 0 }
86 static STRPTR MatchHandler(IPTR DosType)
88 int i;
89 STRPTR fs = NULL;
91 for (i = 0; i < (sizeof(DosTypes) / sizeof(struct _dt)); i++)
93 if ((DosType & DosTypes[i].mask) == DosTypes[i].type)
95 fs = DosTypes[i].fs;
96 break;
99 return fs;
102 static IPTR MatchPartType(UBYTE PartType)
104 int i;
105 IPTR type = 0;
107 for (i = 0; i < (sizeof(PartTypes) / sizeof(struct _pt)); i++)
109 if ((IPTR)PartType == PartTypes[i].part)
111 type = PartTypes[i].type;
112 break;
115 return type;
118 static ULONG GetOffset(struct NepClassMS *ncm,
119 struct PartitionHandle *ph)
121 IPTR tags[3];
122 struct DosEnvec de;
123 ULONG offset = 0;
125 tags[0] = PT_DOSENVEC;
126 tags[1] = (IPTR)&de;
127 tags[2] = TAG_DONE;
128 ph = ph->root;
129 while (ph->root)
131 GetPartitionAttrs(ph, (struct TagItem *)tags);
132 offset += de.de_LowCyl * de.de_Surfaces * de.de_BlocksPerTrack;
133 ph = ph->root;
135 return offset;
138 static VOID AddPartitionVolume(struct NepClassMS *ncm,
139 struct FileSysStartupMsg *fssm,
140 struct PartitionHandle *table,
141 struct PartitionHandle *pn)
143 UBYTE name[32];
144 ULONG i, blockspercyl;
145 const struct PartitionAttribute *attrs;
146 IPTR tags[7];
147 IPTR *pp;
148 struct DeviceNode *devnode;
149 struct PartitionType ptyp;
150 LONG ppos;
151 TEXT *devname, *handler;
152 LONG bootable;
154 D(bug("[Boot] AddPartitionVolume\n"));
155 pp = AllocVec(sizeof(struct DosEnvec) + sizeof(IPTR) * 4,
156 MEMF_PUBLIC | MEMF_CLEAR);
157 if (pp)
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 */
166 tags[0] = PT_NAME;
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;
172 tags[6] = TAG_DONE;
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;
180 else
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;
186 tags[2] = PT_TYPE;
187 tags[3] = (IPTR)&ptyp;
188 tags[4] = PT_DOSENVEC;
189 tags[5] = (IPTR)&pp[4];
190 tags[6] = TAG_DONE;
191 GetPartitionAttrs(pn, (struct TagItem *)tags);
192 bootable = TRUE;
194 /* make the name */
195 devname = AROS_BSTR_ADDR(fssm->fssm_Device);
196 for (i = 0; i < 26; i++)
198 if (*devname == '.' || *devname == '\0')
199 break;
200 name[i] = (UBYTE)uppercase(*devname);
201 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);
206 name[i++] = 'P';
207 if (table->table->type == PHPTT_EBR)
208 ppos += 4;
209 if ((ppos / 10))
210 name[i++] = '0' + (UBYTE)(ppos / 10);
211 name[i++] = '0' + (UBYTE)(ppos % 10);
212 name[i] = '\0';
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 */
223 switch(ptyp.id[0])
225 case 0x2c: /* OFS */
226 case 0x2d: /* FFS */
227 case 0x2e: /* FFS I */
228 case 0x2f: /* SFS */
229 pp[4 + DE_SECSPERBLOCK] = 1;
230 pp[4 + DE_RESERVEDBLKS] = 2;
231 pp[4 + DE_BOOTBLOCKS] = 2;
232 break;
236 pp[0] = (IPTR)name;
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));
246 return;
248 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 */
256 if (handler != NULL)
258 D(bug("[Boot] found handler: %s\n", handler));
259 devnode = MakeDosNode(pp);
260 if (devnode != NULL)
262 devnode->dn_Handler = MKBADDR(AllocVec(AROS_BSTR_MEMSIZE4LEN(
263 strlen(handler)), MEMF_PUBLIC | MEMF_CLEAR));
264 if (devnode->dn_Handler)
266 i = 0;
267 while (handler[i] != '\0')
269 AROS_BSTR_putchar(devnode->dn_Handler, i, handler[i]);
270 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]));
276 return;
280 FreeVec(pp);
284 static BOOL CheckTables(struct NepClassMS *ncm,
285 struct FileSysStartupMsg *fssm,
286 struct PartitionHandle *table)
288 BOOL retval = FALSE;
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;
303 retval = TRUE;
304 ClosePartitionTable(table);
306 return retval;
309 BOOL CheckPartitions(struct NepClassMS *ncm)
311 BOOL found = FALSE;
312 struct PartitionHandle *pt;
313 struct FileSysStartupMsg fssm;
315 pt = OpenRootPartition(DEVNAME, ncm->ncm_UnitNo);
316 if(pt)
318 fssm.fssm_Device = AROS_CONST_BSTR(DEVNAME);
319 fssm.fssm_Unit = ncm->ncm_UnitNo;
320 fssm.fssm_Flags = 0;
322 found = CheckTables(ncm, &fssm, pt);
323 CloseRootPartition(pt);
326 return found;