Update to lasso handling. Adjust scroll amount based on difference between mouse...
[AROS.git] / rom / boot / strap.c
blobd696e39d4d5e4fba55d1485fcb78b8fb71e9b981
1 /*
2 Copyright © 1995-2009, 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>
12 #include <stdio.h>
14 #include <exec/alerts.h>
15 #include <aros/asmcall.h>
16 #include <aros/bootloader.h>
17 #include <exec/lists.h>
18 #include <exec/memory.h>
19 #include <exec/resident.h>
20 #include <exec/types.h>
21 #include <libraries/configvars.h>
22 #include <libraries/expansionbase.h>
23 #include <libraries/partition.h>
24 #include <utility/tagitem.h>
25 #include <devices/bootblock.h>
26 #include <devices/timer.h>
28 #include <proto/exec.h>
29 #include <proto/expansion.h>
30 #include <proto/partition.h>
31 #include <proto/bootloader.h>
33 #include <aros/debug.h>
34 #include <aros/macros.h>
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;
62 STRPTR fs;
63 } DosTypes[] = {
64 { 0xffffffff, AROS_MAKE_ID('B','E','F','S' ), "befs.handler" },
65 { 0xffffff00, AROS_MAKE_ID('B','S','D','\0'), "bsd.handler" },
66 { 0xffffff00, AROS_MAKE_ID('C','P','M','\0'), "cpm.handler" },
67 { 0xffffff00, AROS_MAKE_ID('D','O','S','\0'), "afs.handler" },
68 { 0xffffff00, AROS_MAKE_ID('E','X','T','\0'), "ext.handler" },
69 { 0xffffff00, AROS_MAKE_ID('F','A','T','\0'), "fat.handler" },
70 { 0xffffff00, AROS_MAKE_ID('L','V','M','\0'), "lvm.handler" },
71 { 0xffffff00, AROS_MAKE_ID('M','N','X','\0'), "minix.handler" },
72 { 0xffffffff, AROS_MAKE_ID('N','T','F','S' ), "ntfs.handler" },
73 { 0xffffffff, AROS_MAKE_ID('R','A','I','D' ), "raid.handler" },
74 { 0xffffff00, AROS_MAKE_ID('S','F','S','\0'), "sfs.handler" },
75 { 0xffffff00, AROS_MAKE_ID('S','K','Y','\0'), "skyfs.handler" },
76 { 0xffffffff, AROS_MAKE_ID('V','F','A','T' ), "fat.handler" },
77 { 0,0,NULL }
80 static const struct _pt {
81 IPTR part,type;
82 } PartTypes[] = {
83 { 0x01, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 12-bit FAT */
84 { 0x04, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 16-bit FAT (up to 32M) */
85 { 0x06, AROS_MAKE_ID('F','A','T',' ') }, /* DOS 16-bit FAT (over 32M) */
86 { 0x07, AROS_MAKE_ID('N','T','F','S') }, /* Windows NT NTFS */
87 { 0x0b, AROS_MAKE_ID('V','F','A','T') }, /* W95 FAT32 */
88 { 0x0c, AROS_MAKE_ID('V','F','A','T') }, /* W95 LBA FAT32 */
89 { 0x0e, AROS_MAKE_ID('F','A','T',' ') }, /* W95 16-bit LBA FAT */
90 { 0x2c, AROS_MAKE_ID('D','O','S','\0') }, /* AOS OFS */
91 { 0x2d, AROS_MAKE_ID('D','O','S','\1') }, /* AOS FFS */
92 { 0x2e, AROS_MAKE_ID('D','O','S','\3') }, /* AOS FFS-I */
93 { 0x2f, AROS_MAKE_ID('S','F','S','\0') }, /* AOS SFS */
94 { 0x80, AROS_MAKE_ID('M','N','X','\0') }, /* MINIX until 1.4a */
95 { 0x81, AROS_MAKE_ID('M','N','X','\1') }, /* MINIX since 1.4b */
96 { 0x83, AROS_MAKE_ID('E','X','T','\2') }, /* linux native partition */
97 { 0x8e, AROS_MAKE_ID('L','V','M','\0') }, /* linux LVM partition */
98 { 0x9f, AROS_MAKE_ID('B','S','D','\0') }, /* BSD/OS */
99 { 0xa5, AROS_MAKE_ID('B','S','D','\1') }, /* NetBSD, FreeBSD */
100 { 0xa6, AROS_MAKE_ID('B','S','D','\2') }, /* OpenBSD */
101 { 0xdb, AROS_MAKE_ID('C','P','M','\2') }, /* CPM/M */
102 { 0xeb, AROS_MAKE_ID('B','E','F','S') }, /* BeOS FS */
103 { 0xec, AROS_MAKE_ID('S','K','Y','\0') }, /* SkyOS FS */
104 { 0xfd, AROS_MAKE_ID('R','A','I','D') }, /* linux RAID with autodetect */
105 { 0, 0 }
108 static STRPTR MatchHandler(IPTR DosType)
110 int i;
111 STRPTR fs = NULL;
113 for (i = 0; i < (sizeof(DosTypes) / sizeof(struct _dt)); i++)
115 if ((DosType & DosTypes[i].mask) == DosTypes[i].type)
117 fs = DosTypes[i].fs;
118 break;
121 return fs;
124 static IPTR MatchPartType(UBYTE PartType)
126 int i;
127 IPTR type = 0;
129 for (i = 0; i < (sizeof(PartTypes) / sizeof(struct _pt)); i++)
131 if ((IPTR)PartType == PartTypes[i].part)
133 type = PartTypes[i].type;
134 break;
137 return type;
140 static ULONG GetOffset(struct PartitionBase *PartitionBase,
141 struct PartitionHandle *ph)
143 IPTR tags[3];
144 struct DosEnvec de;
145 ULONG offset = 0;
147 tags[0] = PT_DOSENVEC;
148 tags[1] = (IPTR)&de;
149 tags[2] = TAG_DONE;
150 ph = ph->root;
151 while (ph->root)
153 GetPartitionAttrs(ph, (struct TagItem *)tags);
154 offset += de.de_LowCyl * de.de_Surfaces * de.de_BlocksPerTrack;
155 ph = ph->root;
157 return offset;
160 static VOID AddPartitionVolume
162 struct ExpansionBase *ExpansionBase,
163 struct PartitionBase *PartitionBase,
164 struct FileSysStartupMsg *fssm,
165 struct PartitionHandle *table,
166 struct PartitionHandle *pn,
167 struct ExecBase * SysBase
170 UBYTE name[32];
171 ULONG i, blockspercyl;
172 const struct PartitionAttribute *attrs;
173 IPTR tags[7];
174 IPTR *pp;
175 struct DeviceNode *devnode;
176 struct PartitionType ptyp;
177 LONG ppos;
178 TEXT *devname, *handler;
179 LONG bootable;
181 D(bug("[Boot] AddPartitionVolume\n"));
182 pp = AllocVec(sizeof(struct DosEnvec) + sizeof(IPTR) * 4,
183 MEMF_PUBLIC | MEMF_CLEAR);
184 if (pp)
186 attrs = QueryPartitionAttrs(table);
187 while ((attrs->attribute != PTA_DONE) && (attrs->attribute != PTA_NAME))
188 attrs++; /* look for name attr */
189 if (attrs->attribute != PTA_DONE)
191 D(bug("[Boot] RDB partition\n"));
192 /* partition has a name => RDB partition */
193 tags[0] = PT_NAME;
194 tags[1] = (IPTR)name;
195 tags[2] = PT_DOSENVEC;
196 tags[3] = (IPTR)&pp[4];
197 tags[4] = PT_BOOTABLE;
198 tags[5] = (IPTR)&bootable;
199 tags[6] = TAG_DONE;
200 GetPartitionAttrs(pn, (struct TagItem *)tags);
201 D(bug("[Boot] Partition name: %s bootable: %d\n", name, bootable));
202 /* BHFormat complains if this bit is not set, and it's really wrong to have it unset. So we explicitly set it here.
203 Pavel Fedin <sonic_amiga@rambler.ru> */
204 pp[4 + DE_BUFMEMTYPE] |= MEMF_PUBLIC;
206 else
208 D(bug("[Boot] MBR partition\n"));
209 /* partition doesn't have a name => MBR partition */
210 tags[0] = PT_POSITION;
211 tags[1] = (IPTR)&ppos;
212 tags[2] = PT_TYPE;
213 tags[3] = (IPTR)&ptyp;
214 tags[4] = PT_DOSENVEC;
215 tags[5] = (IPTR)&pp[4];
216 tags[6] = TAG_DONE;
217 GetPartitionAttrs(pn, (struct TagItem *)tags);
218 bootable = TRUE;
220 /* make the name */
221 devname = AROS_BSTR_ADDR(fssm->fssm_Device);
222 for (i = 0; i < 26; i++)
224 if (*devname == '.' || *devname == '\0')
225 break;
226 name[i] = (UBYTE)uppercase(*devname);
227 devname++;
229 if ((fssm->fssm_Unit / 10))
230 name[i++] = '0' + (UBYTE)(fssm->fssm_Unit / 10);
231 name[i++] = '0' + (UBYTE)(fssm->fssm_Unit % 10);
232 name[i++] = 'P';
233 if (table->table->type == PHPTT_EBR)
234 ppos += 4;
235 if ((ppos / 10))
236 name[i++] = '0' + (UBYTE)(ppos / 10);
237 name[i++] = '0' + (UBYTE)(ppos % 10);
238 name[i] = '\0';
239 D(bug("[Boot] Partition name: %s type: %lu bootable: %d\n", name, ptyp.id[0], bootable));
240 /* set DOSTYPE based on the partition type */
241 pp[4 + DE_DOSTYPE] = MatchPartType(ptyp.id[0]);
242 /* set some common DOSENV fields */
243 pp[4 + DE_TABLESIZE] = DE_BOOTBLOCKS;
244 pp[4 + DE_NUMBUFFERS] = 20;
245 pp[4 + DE_BUFMEMTYPE] = MEMF_PUBLIC;
246 pp[4 + DE_MAXTRANSFER] = 0x00200000;
247 pp[4 + DE_MASK] = 0x7ffffffe;
248 /* set some fs specific fields */
249 switch(ptyp.id[0])
251 case 0x2c: /* OFS */
252 case 0x2d: /* FFS */
253 case 0x2e: /* FFS I */
254 case 0x2f: /* SFS */
255 pp[4 + DE_SECSPERBLOCK] = 1;
256 pp[4 + DE_RESERVEDBLKS] = 2;
257 pp[4 + DE_BOOTBLOCKS] = 2;
258 break;
262 pp[0] = (IPTR)name;
263 pp[1] = (IPTR)AROS_BSTR_ADDR(fssm->fssm_Device);
264 pp[2] = fssm->fssm_Unit;
265 pp[3] = fssm->fssm_Flags;
266 i = GetOffset(PartitionBase, pn);
267 blockspercyl = pp[4 + DE_BLKSPERTRACK] * pp[4 + DE_NUMHEADS];
268 if (i % blockspercyl != 0)
269 return;
270 i /= blockspercyl;
271 pp[4 + DE_LOWCYL] += i;
272 pp[4 + DE_HIGHCYL] += i;
274 D(bug("[Boot] Looking up handler for 0x%08lX\n", pp[4+DE_DOSTYPE]));
275 handler = MatchHandler(pp[4 + DE_DOSTYPE]);
277 /* Skip unknown partition types */
278 if (handler != NULL)
280 D(bug("[Boot] found handler: %s\n", handler));
281 devnode = MakeDosNode(pp);
282 if (devnode != NULL)
284 devnode->dn_Handler = MKBADDR(AllocVec(AROS_BSTR_MEMSIZE4LEN(
285 strlen(handler)), MEMF_PUBLIC | MEMF_CLEAR));
286 if (devnode->dn_Handler)
288 i = 0;
289 while (handler[i] != '\0')
291 AROS_BSTR_putchar(devnode->dn_Handler, i, handler[i]);
292 i++;
294 AROS_BSTR_setstrlen(devnode->dn_Handler, i);
295 AddBootNode(bootable ? pp[4 + DE_BOOTPRI] : -128, 0, devnode, 0);
296 D(bug("[Boot] AddBootNode(%s,0x%lx,'%s')\n",
297 devnode->dn_Ext.dn_AROS.dn_DevName,
298 pp[4 + DE_DOSTYPE], handler));
299 return;
303 FreeVec(pp);
307 static BOOL CheckTables
309 struct ExpansionBase *ExpansionBase,
310 struct PartitionBase *PartitionBase,
311 struct FileSysStartupMsg *fssm,
312 struct PartitionHandle *table,
313 struct ExecBase *SysBase
316 BOOL retval = FALSE;
317 struct PartitionHandle *ph;
319 /* Traverse partition tables recursively, and attempt to add a BootNode
320 for any non-subtable partitions found */
321 if (OpenPartitionTable(table) == 0)
323 ph = (struct PartitionHandle *)table->table->list.lh_Head;
324 while (ph->ln.ln_Succ)
326 /* Attempt to add partition to system if it isn't a subtable */
327 if (!CheckTables(ExpansionBase, PartitionBase, fssm, ph, SysBase))
328 AddPartitionVolume(ExpansionBase, PartitionBase, fssm, table,
329 ph, SysBase);
330 ph = (struct PartitionHandle *)ph->ln.ln_Succ;
332 retval = TRUE;
333 ClosePartitionTable(table);
335 return retval;
338 static BOOL IsRemovable(struct ExecBase *SysBase, struct IOExtTD *ioreq)
340 struct DriveGeometry dg;
342 ioreq->iotd_Req.io_Command = TD_GETGEOMETRY;
343 ioreq->iotd_Req.io_Data = &dg;
344 ioreq->iotd_Req.io_Length = sizeof(struct DriveGeometry);
345 DoIO((struct IORequest *)ioreq);
346 return (dg.dg_Flags & DGF_REMOVABLE) ? TRUE : FALSE;
349 static VOID CheckPartitions
351 struct ExpansionBase *ExpansionBase,
352 struct ExecBase *SysBase,
353 struct BootNode *bn
356 struct PartitionBase *PartitionBase;
357 struct PartitionHandle *pt;
358 struct FileSysStartupMsg *fssm;
360 PartitionBase =
361 (struct PartitionBase *)OpenLibrary("partition.library", 1);
362 if (PartitionBase)
364 fssm = BADDR(((struct DeviceNode *)bn->bn_DeviceNode)->dn_Startup);
365 pt = OpenRootPartition(AROS_BSTR_ADDR(fssm->fssm_Device),
366 fssm->fssm_Unit);
367 if (pt)
369 if (IsRemovable(SysBase, pt->bd->ioreq))
371 /* don't check removable devices for partition tables */
372 Enqueue(&ExpansionBase->MountList, (struct Node *)bn);
374 else
376 if (!CheckTables(ExpansionBase, PartitionBase, fssm, pt,
377 SysBase))
379 /* no partition table found, so reinsert node */
380 Enqueue(&ExpansionBase->MountList, (struct Node *)bn);
383 CloseRootPartition(pt);
385 else
387 /* amicdrom fails here because of non-initialized libraries */
388 Enqueue(&ExpansionBase->MountList, (struct Node *)bn);
390 CloseLibrary((struct Library *)PartitionBase);
394 AROS_UFH3(int, AROS_SLIB_ENTRY(init, boot),
395 AROS_UFHA(ULONG, dummy, D0),
396 AROS_UFHA(ULONG, seglist, A0),
397 AROS_UFHA(struct ExecBase *, SysBase, A6)
400 AROS_USERFUNC_INIT
401 struct ExpansionBase *ExpansionBase;
402 struct BootNode *bootNode;
403 struct List list;
404 struct Resident *DOSResident;
405 void *BootLoaderBase;
407 #if !(AROS_FLAVOUR & AROS_FLAVOUR_EMULATION)
408 ExpansionBase =
409 (struct ExpansionBase *)OpenLibrary("expansion.library", 0);
410 if( ExpansionBase == NULL )
412 D(bug( "Could not open expansion.library, something's wrong!\n"));
413 Alert(AT_DeadEnd | AG_OpenLib | AN_BootStrap | AO_ExpansionLib);
416 /* Try to open bootloader.resource */
417 if ((BootLoaderBase = OpenResource("bootloader.resource")) != NULL)
419 struct List *args;
420 struct Node *node;
421 ULONG delay = 0;
423 args = GetBootInfo(BL_Args);
425 if (args)
428 * Search the kernel parameters for the bootdelay=%d string. It determines the
429 * delay in seconds.
431 ForeachNode(args, node)
433 if (strncmp(node->ln_Name, "bootdelay=", 10) == 0)
435 struct MsgPort *port = CreateMsgPort();
436 struct timerequest *tr = (struct timerequest *)
437 CreateIORequest(port, sizeof(struct timerequest));
439 OpenDevice("timer.device", UNIT_VBLANK,
440 (struct IORequest *)tr, 0);
442 sscanf(node->ln_Name, "bootdelay=%d", &delay);
443 D(bug("[Boot] delay of %d seconds requested.", delay));
445 tr->tr_node.io_Command = TR_ADDREQUEST;
446 tr->tr_time.tv_sec = delay;
447 tr->tr_time.tv_usec = 0;
449 DoIO((struct IORequest *)tr);
451 CloseDevice((struct IORequest *)tr);
452 DeleteIORequest((struct IORequest *)tr);
453 DeleteMsgPort(port);
459 /* move all boot nodes into another list */
460 NEWLIST(&list);
461 while ((bootNode = (struct BootNode *)RemHead(&ExpansionBase->MountList)))
462 AddTail(&list, &bootNode->bn_Node);
464 /* check boot nodes for partition tables */
465 while ((bootNode = (struct BootNode *)RemHead(&list)))
466 CheckPartitions(ExpansionBase, SysBase, bootNode);
467 CloseLibrary((struct Library *)ExpansionBase);
468 #endif
470 DOSResident = FindResident( "dos.library" );
472 if( DOSResident == NULL )
474 Alert( AT_DeadEnd | AG_OpenLib | AN_BootStrap | AO_DOSLib );
477 InitResident( DOSResident, NULL );
479 /* We don't get here if everything went well */
480 return 0;
482 AROS_USERFUNC_EXIT
485 static const UBYTE boot_end = 0;