Fix for the (stupid) case of app (always) passing
[tangerine.git] / rom / boot / strap.c
blobba56fc9d8e0c3da0b7b89d1abba752180d3c6a9b
1 /*
2 Copyright © 1995-2005, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Boot AROS
6 Lang: english
7 */
9 #define DEBUG 1
11 #include <string.h>
13 #include <exec/alerts.h>
14 #include <aros/asmcall.h>
15 #include <exec/lists.h>
16 #include <exec/memory.h>
17 #include <exec/resident.h>
18 #include <exec/types.h>
19 #include <libraries/configvars.h>
20 #include <libraries/expansionbase.h>
21 #include <libraries/partition.h>
22 #include <utility/tagitem.h>
23 #include <devices/bootblock.h>
25 #include <proto/exec.h>
26 #include <proto/expansion.h>
27 #include <proto/partition.h>
29 #ifdef DEBUG
30 #include <aros/debug.h>
31 #endif
32 #include <aros/macros.h>
34 #define BOOT_CHECK 0
36 #define uppercase(x) ((x >= 'a' && x <= 'z') ? (x & 0xdf) : x)
38 int boot_entry()
40 return -1;
43 static const UBYTE boot_end;
44 int AROS_SLIB_ENTRY(init,boot)();
46 const struct Resident boot_resident =
48 RTC_MATCHWORD,
49 (struct Resident *)&boot_resident,
50 (APTR)&boot_end,
51 RTF_COLDSTART,
52 41,
53 NT_PROCESS,
54 -50,
55 "Boot Strap",
56 "AROS Boot Strap 41.0\r\n",
57 (APTR)&boot_init
60 static const struct _dt {
61 IPTR mask,type,fs;
62 } DosTypes[] = {
63 { 0xffffffff, AROS_MAKE_ID('B','E','F','S' ), (IPTR)"befs.handler" },
64 { 0xffffff00, AROS_MAKE_ID('B','S','D','\0'), (IPTR)"bsd.handler" },
65 { 0xffffff00, AROS_MAKE_ID('C','P','M','\0'), (IPTR)"cpm.handler" },
66 { 0xffffff00, AROS_MAKE_ID('D','O','S','\0'), (IPTR)"afs.handler" },
67 { 0xffffff00, AROS_MAKE_ID('E','X','T','\0'), (IPTR)"ext.handler" },
68 { 0xffffff00, AROS_MAKE_ID('F','A','T','\0'), (IPTR)"fat.handler" },
69 { 0xffffff00, AROS_MAKE_ID('L','V','M','\0'), (IPTR)"lvm.handler" },
70 { 0xffffff00, AROS_MAKE_ID('M','N','X','\0'), (IPTR)"minix.handler" },
71 { 0xffffffff, AROS_MAKE_ID('N','T','F','S' ), (IPTR)"ntfs.handler" },
72 { 0xffffffff, AROS_MAKE_ID('R','A','I','D' ), (IPTR)"raid.handler" },
73 { 0xffffff00, AROS_MAKE_ID('S','F','S','\0'), (IPTR)"sfs.handler" },
74 { 0xffffff00, AROS_MAKE_ID('S','K','Y','\0'), (IPTR)"skyfs.handler" },
75 { 0xffffffff, AROS_MAKE_ID('V','F','A','T' ), (IPTR)"fat.handler" },
76 { 0,0,0, }
79 static const struct _pt {
80 IPTR part,type;
81 } PartTypes[] = {
82 { 0x01, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 12-bit FAT */
83 { 0x04, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 16-bit FAT (up to 32M) */
84 { 0x06, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 16-bit FAT (over 32M) */
85 { 0x07, AROS_MAKE_ID('N','T','F','S') }, /* Windows NT NTFS */
86 { 0x0b, AROS_MAKE_ID('V','F','A','T') }, /* W95 FAT32 */
87 { 0x0c, AROS_MAKE_ID('V','F','A','T') }, /* W95 LBA FAT32 */
88 { 0x0e, AROS_MAKE_ID('F','A','T',' ') }, /* W95 16-bit LBA FAT */
89 { 0x2c, AROS_MAKE_ID('D','O','S','\0') }, /* AOS OFS */
90 { 0x2d, AROS_MAKE_ID('D','O','S','\1') }, /* AOS FFS */
91 { 0x2e, AROS_MAKE_ID('D','O','S','\3') }, /* AOS FFS-I */
92 { 0x2f, AROS_MAKE_ID('S','F','S','\0') }, /* AOS SFS */
93 { 0x80, AROS_MAKE_ID('M','N','X','\0') }, /* MINIX until 1.4a */
94 { 0x81, AROS_MAKE_ID('M','N','X','\1') }, /* MINIX since 1.4b */
95 { 0x83, AROS_MAKE_ID('E','X','T','\2') }, /* linux native partition */
96 { 0x8e, AROS_MAKE_ID('L','V','M','\0') }, /* linux LVM partition */
97 { 0x9f, AROS_MAKE_ID('B','S','D','\0') }, /* BSD/OS */
98 { 0xa5, AROS_MAKE_ID('B','S','D','\1') }, /* NetBSD, FreeBSD */
99 { 0xa6, AROS_MAKE_ID('B','S','D','\2') }, /* OpenBSD */
100 { 0xdb, AROS_MAKE_ID('C','P','M','\2') }, /* CPM/M */
101 { 0xeb, AROS_MAKE_ID('B','E','F','S') }, /* BeOS FS */
102 { 0xec, AROS_MAKE_ID('S','K','Y','\0') }, /* SkyOS FS */
103 { 0xfd, AROS_MAKE_ID('R','A','I','D') }, /* linux RAID with autodetect */
104 { 0, 0 }
107 static IPTR MatchHandler(IPTR DosType)
109 int i;
110 IPTR fs = 0;
112 for (i = 0; i < (sizeof(DosTypes) / sizeof(struct _dt)); i++)
114 if ((DosType & DosTypes[i].mask) == DosTypes[i].type)
116 fs = DosTypes[i].fs;
117 break;
120 return fs;
123 static IPTR MatchPartType(UBYTE PartType)
125 int i;
126 IPTR type = 0;
128 for (i = 0; i < (sizeof(PartTypes) / sizeof(struct _pt)); i++)
130 if ((IPTR)PartType == PartTypes[i].part)
132 type = PartTypes[i].type;
133 break;
136 return type;
139 static ULONG GetOffset(struct PartitionBase *PartitionBase,
140 struct PartitionHandle *ph)
142 STACKIPTR tags[3];
143 struct DosEnvec de;
144 ULONG offset = 0;
146 tags[0] = PT_DOSENVEC;
147 tags[1] = (STACKIPTR)&de;
148 tags[2] = TAG_DONE;
149 ph = ph->root;
150 while (ph->root)
152 GetPartitionAttrs(ph, (struct TagItem *)tags);
153 offset += de.de_LowCyl;
154 ph = ph->root;
156 return offset;
159 static VOID AddPartitionVolume
161 struct ExpansionBase *ExpansionBase,
162 struct PartitionBase *PartitionBase,
163 struct FileSysStartupMsg *fssm,
164 struct PartitionHandle *table,
165 struct PartitionHandle *pn,
166 struct ExecBase * SysBase
169 UBYTE name[32];
170 ULONG i;
171 const struct PartitionAttribute *attrs;
172 STACKIPTR tags[7];
173 IPTR *pp;
174 struct DeviceNode *devnode;
175 struct PartitionType ptyp;
176 LONG ppos;
177 TEXT *devname;
179 pp = AllocVec(sizeof(struct DosEnvec) + sizeof(IPTR) * 4,
180 MEMF_PUBLIC | MEMF_CLEAR);
181 if (pp)
183 attrs = QueryPartitionAttrs(table);
184 while ((attrs->attribute != PTA_DONE) && (attrs->attribute != PTA_NAME))
185 attrs++; /* look for name attr */
186 if (attrs->attribute != PTA_DONE)
188 /* partition has a name => RDB partition */
189 tags[0] = PT_NAME;
190 tags[1] = (STACKIPTR)name;
191 tags[2] = PT_DOSENVEC;
192 tags[3] = (STACKIPTR)&pp[4];
193 tags[4] = TAG_DONE;
194 GetPartitionAttrs(pn, (struct TagItem *)tags);
196 else
198 /* partition doesn't have a name => MBR partition */
199 tags[0] = PT_POSITION;
200 tags[1] = (STACKIPTR)&ppos;
201 tags[2] = PT_TYPE;
202 tags[3] = (STACKIPTR)&ptyp;
203 tags[4] = PT_DOSENVEC;
204 tags[5] = (STACKIPTR)&pp[4];
205 tags[6] = TAG_DONE;
206 GetPartitionAttrs(pn, (struct TagItem *)tags);
208 /* make the name */
209 devname = AROS_BSTR_ADDR(fssm->fssm_Device);
210 for (i = 0; i < 26; i++)
212 if (*devname == '.' || *devname == '\0')
213 break;
214 name[i] = (UBYTE)uppercase(*devname);
215 devname++;
217 if ((fssm->fssm_Unit / 10))
218 name[i++] = '0' + (UBYTE)(fssm->fssm_Unit / 10);
219 name[i++] = '0' + (UBYTE)(fssm->fssm_Unit % 10);
220 name[i++] = 'P';
221 if ((ppos / 10))
222 name[i++] = '0' + (UBYTE)(ppos / 10);
223 name[i++] = '0' + (UBYTE)(ppos % 10);
224 name[i] = '\0';
225 /* set DOSTYPE based on the partition type */
226 pp[4 + DE_DOSTYPE] = MatchPartType(ptyp.id[0]);
227 /* set some common DOSENV fields */
228 pp[4 + DE_TABLESIZE] = DE_BOOTBLOCKS;
229 pp[4 + DE_NUMBUFFERS] = 20;
230 pp[4 + DE_BUFMEMTYPE] = MEMF_PUBLIC;
231 pp[4 + DE_MAXTRANSFER] = 0x00200000;
232 pp[4 + DE_MASK] = 0x7ffffffe;
233 /* set some fs specific fields */
234 switch(ptyp.id[0])
236 case 0x2c: /* OFS */
237 case 0x2d: /* FFS */
238 case 0x2e: /* FFS I */
239 case 0x2f: /* SFS */
240 pp[4 + DE_SECSPERBLOCK] = 1;
241 pp[4 + DE_RESERVEDBLKS] = 2;
242 pp[4 + DE_BOOTBLOCKS] = 2;
243 break;
247 pp[1] = (IPTR)AROS_BSTR_ADDR(fssm->fssm_Device);
248 pp[2] = fssm->fssm_Unit;
249 pp[3] = fssm->fssm_Flags;
250 i = GetOffset(PartitionBase, pn);
251 pp[4 + DE_LOWCYL] += i;
252 pp[4 + DE_HIGHCYL] += i;
254 pp[0] = MatchHandler(pp[4 + DE_DOSTYPE]);
256 /* Skip unknown partition types */
257 if (pp[0] != 0)
259 devnode = MakeDosNode(pp);
260 if (devnode)
262 devnode->dn_OldName = MKBADDR(AllocVec(strlen(name) + 2,
263 MEMF_PUBLIC | MEMF_CLEAR));
264 if (devnode->dn_OldName)
266 i = 0;
267 while (name[i])
269 AROS_BSTR_putchar(devnode->dn_OldName, i, name[i]);
270 i++;
272 AROS_BSTR_setstrlen(devnode->dn_OldName, i);
273 devnode->dn_NewName = AROS_BSTR_ADDR(devnode->dn_OldName);
274 AddBootNode(pp[4 + DE_BOOTPRI], 0, devnode, 0);
275 D(bug("[Boot] AddBootNode(%s,0x%lx,'%s')\n",
276 devnode->dn_NewName, pp[4 + DE_DOSTYPE], pp[0]));
277 return;
281 FreeVec(pp);
285 static BOOL CheckTables
287 struct ExpansionBase *ExpansionBase,
288 struct PartitionBase *PartitionBase,
289 struct FileSysStartupMsg *fssm,
290 struct PartitionHandle *table,
291 struct ExecBase *SysBase
294 BOOL retval = FALSE;
295 struct PartitionHandle *ph;
297 /* Traverse partition tables recursively, and attempt to add a BootNode
298 for any non-subtable partitions found */
299 if (OpenPartitionTable(table) == 0)
301 ph = (struct PartitionHandle *)table->table->list.lh_Head;
302 while (ph->ln.ln_Succ)
304 /* Attempt to add partition to system if it isn't a subtable */
305 if (!CheckTables(ExpansionBase, PartitionBase, fssm, ph, SysBase))
306 AddPartitionVolume(ExpansionBase, PartitionBase, fssm, table,
307 ph, SysBase);
308 ph = (struct PartitionHandle *)ph->ln.ln_Succ;
310 retval = TRUE;
311 ClosePartitionTable(table);
313 return retval;
316 static BOOL IsRemovable(struct ExecBase *SysBase, struct IOExtTD *ioreq)
318 struct DriveGeometry dg;
320 ioreq->iotd_Req.io_Command = TD_GETGEOMETRY;
321 ioreq->iotd_Req.io_Data = &dg;
322 ioreq->iotd_Req.io_Length = sizeof(struct DriveGeometry);
323 DoIO((struct IORequest *)ioreq);
324 return (dg.dg_Flags & DGF_REMOVABLE) ? TRUE : FALSE;
327 static VOID CheckPartitions
329 struct ExpansionBase *ExpansionBase,
330 struct ExecBase *SysBase,
331 struct BootNode *bn
334 struct PartitionBase *PartitionBase;
335 struct PartitionHandle *pt;
336 struct FileSysStartupMsg *fssm;
338 PartitionBase =
339 (struct PartitionBase *)OpenLibrary("partition.library", 1);
340 if (PartitionBase)
342 fssm = BADDR(((struct DeviceNode *)bn->bn_DeviceNode)->dn_Startup);
343 pt = OpenRootPartition(AROS_BSTR_ADDR(fssm->fssm_Device),
344 fssm->fssm_Unit);
345 if (pt)
347 if (IsRemovable(SysBase, pt->bd->ioreq))
349 /* don't check removable devices for partition tables */
350 Enqueue(&ExpansionBase->MountList, (struct Node *)bn);
352 else
354 if (!CheckTables(ExpansionBase, PartitionBase, fssm, pt,
355 SysBase))
357 /* no partition table found, so reinsert node */
358 Enqueue(&ExpansionBase->MountList, (struct Node *)bn);
361 CloseRootPartition(pt);
363 else
365 /* amicdrom fails here because of non-initialized libraries */
366 Enqueue(&ExpansionBase->MountList, (struct Node *)bn);
368 CloseLibrary((struct Library *)PartitionBase);
372 AROS_UFH3(int, AROS_SLIB_ENTRY(init, boot),
373 AROS_UFHA(ULONG, dummy, D0),
374 AROS_UFHA(ULONG, seglist, A0),
375 AROS_UFHA(struct ExecBase *, SysBase, A6)
378 AROS_USERFUNC_INIT
379 struct ExpansionBase *ExpansionBase;
380 struct BootNode *bootNode;
381 struct List list;
382 struct Resident *DOSResident;
384 #if !(AROS_FLAVOUR & AROS_FLAVOUR_EMULATION)
385 ExpansionBase =
386 (struct ExpansionBase *)OpenLibrary("expansion.library", 0);
387 if( ExpansionBase == NULL )
389 D(bug( "Could not open expansion.library, something's wrong!\n"));
390 Alert(AT_DeadEnd | AG_OpenLib | AN_BootStrap | AO_ExpansionLib);
393 /* move all boot nodes into another list */
394 NEWLIST(&list);
395 while ((bootNode = (struct BootNode *)RemHead(&ExpansionBase->MountList)))
396 AddTail(&list, &bootNode->bn_Node);
398 /* check boot nodes for partition tables */
399 while ((bootNode = (struct BootNode *)RemHead(&list)))
400 CheckPartitions(ExpansionBase, SysBase, bootNode);
401 CloseLibrary((struct Library *)ExpansionBase);
402 #endif
404 DOSResident = FindResident( "dos.library" );
406 if( DOSResident == NULL )
408 Alert( AT_DeadEnd | AG_OpenLib | AN_BootStrap | AO_DOSLib );
411 InitResident( DOSResident, NULL );
413 return 0;
415 AROS_USERFUNC_EXIT
418 static const UBYTE boot_end = 0;