Update to lasso handling. Adjust scroll amount based on difference between mouse...
[AROS.git] / rom / dosboot / dosboot_init.c
blobecdfc97c8eb79b3381ede5584b4dd55b254f63f2
1 /*
2 Copyright � 1995-2009, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Start up the ol' Dos boot process.
6 Lang: english
7 */
9 #define AROS_BOOT_CHECKSIG
10 #define DOSBOOT_DISCINSERT_SCREENPRINT
12 # define DEBUG 0
13 # include <aros/debug.h>
15 #include <aros/macros.h>
16 #include <aros/asmcall.h>
17 #include <aros/symbolsets.h>
19 #include <proto/exec.h>
20 #include <proto/dos.h>
22 #include <exec/types.h>
23 #include <exec/nodes.h>
24 #include <exec/lists.h>
25 #include <exec/execbase.h>
26 #include <exec/alerts.h>
27 #include <exec/memory.h>
28 #include <dos/dosextens.h>
29 #include <dos/dostags.h>
30 #include <dos/filehandler.h>
31 #include <dos/filesystem.h>
32 #include <libraries/expansionbase.h>
33 #include <devices/trackdisk.h>
35 #include <string.h>
36 #include <stdio.h>
38 #include "dosboot_intern.h"
40 #include LC_LIBDEFS_FILE
42 #define BNF_RETRY 0x8000 /* Private flag for the BootNode */
44 extern BOOL __dosboot_InitHidds(struct ExecBase *, struct DosLibrary *);
45 extern void __dosboot_Boot(struct ExecBase *SysBase, BOOL hidds_ok);
47 /** Support Functions **/
48 /* Attempt to start a handler for the DeviceNode */
49 BOOL __dosboot_RunHandler(struct DeviceNode *deviceNode, struct DosLibrary *DOSBase)
51 struct MsgPort *mp;
52 struct IOFileSys *iofs;
53 BOOL ok = FALSE;
55 D(bug("[DOSBoot] __dosboot_RunHandler()\n" ));
56 mp = CreateMsgPort();
58 if (mp != NULL)
60 iofs = (struct IOFileSys *)CreateIORequest(mp, sizeof(struct IOFileSys));
62 if (iofs != NULL)
64 STRPTR handler;
65 struct FileSysStartupMsg *fssm;
66 ULONG fssmFlags = 0;
68 if (deviceNode->dn_Handler == NULL)
70 handler = "afs.handler";
72 else
74 handler = AROS_BSTR_ADDR(deviceNode->dn_Handler);
77 /* FIXME: this assumes that dol_Startup points to struct FileSysStartupMsg.
78 This is not true for plain handlers, dol_Startup is a BSTR in this case.
79 In order to make use of this we should implement direct support for
80 packet-style handlers in dos.library */
81 fssm = (struct FileSysStartupMsg *)BADDR(deviceNode->dn_Startup);
82 if (fssm != NULL)
84 iofs->io_Union.io_OpenDevice.io_DeviceName = AROS_BSTR_ADDR(fssm->fssm_Device);
85 iofs->io_Union.io_OpenDevice.io_Unit = fssm->fssm_Unit;
86 iofs->io_Union.io_OpenDevice.io_Environ = (IPTR *)BADDR(fssm->fssm_Environ);
87 fssmFlags = fssm->fssm_Flags;
89 iofs->io_Union.io_OpenDevice.io_DosName = deviceNode->dn_Ext.dn_AROS.dn_DevName;
90 iofs->io_Union.io_OpenDevice.io_DeviceNode = deviceNode;
92 D(bug("[DOSBoot] __dosboot_RunHandler: Starting up %s\n", handler));
93 if (!OpenDevice(handler, 0, &iofs->IOFS, fssmFlags) ||
94 !OpenDevice("packet.handler", 0, &iofs->IOFS, fssmFlags))
96 /* Ok, this means that the handler was able to open. */
97 D(bug("[DOSBoot] __dosboot_RunHandler: Handler started\n"));
98 deviceNode->dn_Ext.dn_AROS.dn_Device = iofs->IOFS.io_Device;
99 deviceNode->dn_Ext.dn_AROS.dn_Unit = iofs->IOFS.io_Unit;
100 ok = TRUE;
103 DeleteIORequest(&iofs->IOFS);
106 DeleteMsgPort(mp);
108 return ok;
111 static BOOL __dosboot_Mount(struct DeviceNode *dn, struct DosLibrary * DOSBase)
113 BOOL rc;
115 if (!dn->dn_Ext.dn_AROS.dn_Device)
117 D(bug("[DOSBoot] __dosboot_Mount: Attempting to mount\n"));
118 rc = __dosboot_RunHandler(dn, DOSBase);
120 else
122 D(bug("[DOSBoot] __dosboot_Mount: Volume already mounted\n"));
123 rc = TRUE;
126 if (rc)
128 if (!AddDosEntry((struct DosList *) dn))
130 Alert(AT_DeadEnd | AG_NoMemory | AN_DOSLib);
133 return rc;
136 static BOOL __dosboot_IsBootable(CONST_STRPTR deviceName, struct DosLibrary * DOSBase)
138 BOOL result = FALSE;
139 BPTR lock, seglist;
140 STRPTR buffer;
141 LONG bufferLength;
143 D(bug("[DOSBoot] __dosboot_IsBootable('%s')\n", deviceName));
145 #if defined(AROS_BOOT_CHECKSIG)
146 #define AROSBOOTSIG_FILE ":AROS.boot"
147 LONG readsize;
148 struct FileInfoBlock abfile_fib;
149 bufferLength = strlen(deviceName) + sizeof(AROSBOOTSIG_FILE) + 1;
151 if ((buffer = AllocMem(bufferLength, MEMF_ANY)) == NULL)
153 Alert(AT_DeadEnd | AG_NoMemory | AN_DOSLib);
156 strcpy(buffer, deviceName);
157 strcat(buffer, AROSBOOTSIG_FILE);
159 if ((lock = Open(buffer, MODE_OLDFILE)) == 0)
161 D(bug("[DOSBoot] __dosboot_IsBootable: Failed to open '%s'\n", buffer));
162 goto cleanup;
165 D(bug("[DOSBoot] __dosboot_IsBootable: Opened '%s'\n", buffer));
166 FreeMem(buffer, bufferLength);
167 buffer = NULL;
169 if (ExamineFH(lock, &abfile_fib))
171 bufferLength = abfile_fib.fib_Size + 1;
173 if ((buffer = AllocMem(bufferLength, MEMF_ANY)) == NULL)
175 Alert(AT_DeadEnd | AG_NoMemory | AN_DOSLib);
177 D(bug("[DOSBoot] __dosboot_IsBootable: Allocated %d bytes for Buffer @ %p\n", bufferLength, buffer));
178 if ((readsize = Read(lock, buffer, (bufferLength - 1))) != -1)
180 IPTR sigptr = 0;
182 if (readsize != 0)
183 buffer[readsize] = '\0';
184 else
185 buffer[bufferLength - 1] = '\0';
187 D(bug("[DOSBoot] __dosboot_IsBootable: Buffer contains '%s'\n", buffer));
188 if ((sigptr = (IPTR)strstr(buffer, AROS_ARCHITECTURE)) != 0)
190 D(bug("[DOSBoot] __dosboot_IsBootable: Signature '%s' found\n", sigptr));
191 result = TRUE;
195 Close(lock);
196 lock = NULL;
198 #else
199 #define SHELL_FILE ":C/Shell"
201 bufferLength = strlen(deviceName) + sizeof(SHELL_FILE) + 1;
203 if ((buffer = AllocMem(bufferLength, MEMF_PUBLIC)) == NULL)
205 Alert(AT_DeadEnd | AG_NoMemory | AN_DOSLib);
208 strcpy(buffer, deviceName);
209 strcat(buffer, SHELL_FILE);
211 D(bug("[DOSBoot] __dosboot_IsBootable: "
212 "Trying to load '%s' as an executable\n", buffer));
214 if ((seglist = LoadSeg(buffer)) == (BPTR)NULL)
216 D(bug("[DOSBoot] __dosboot_IsBootable: could not load '%s'\n", buffer));
218 else
220 UnLoadSeg(seglist);
221 result = TRUE;
223 #endif
225 cleanup:
226 if (buffer != NULL ) FreeMem(buffer, bufferLength);
228 return result;
231 /** Boot Code **/
233 AROS_UFH3(void, __dosboot_BootProcess,
234 AROS_UFHA(APTR, argString, A0),
235 AROS_UFHA(ULONG, argSize, D0),
236 AROS_UFHA(struct ExecBase *,SysBase, A6)
239 AROS_USERFUNC_INIT
241 struct ExpansionBase *ExpansionBase = NULL;
242 struct DosLibrary *DOSBase = NULL;
243 LIBBASETYPEPTR LIBBASE = FindTask(NULL)->tc_UserData;
245 struct BootNode *bootNode = NULL;
246 struct Node *tmpNode = NULL;
247 STRPTR bootName;
248 LONG bootNameLength;
249 BPTR lock;
250 BOOL hidds_ok;
252 struct MsgPort *mp; // Message port used with timer.device
253 struct timerequest *tr = NULL; // timer's time request message
255 D(bug("[DOSBoot] __dosboot_BootProcess()\n" ));
257 #define deviceName (((struct DosList *) bootNode->bn_DeviceNode)->dol_Ext.dol_AROS.dol_DevName)
259 /**** Open all required libraries **********************************************/
260 if ((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0)) == NULL)
262 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open dos.library.\n" ));
263 Alert(AT_DeadEnd| AG_OpenLib | AN_DOSLib | AO_DOSLib);
266 if ((ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library", 0)) == NULL)
268 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open expansion.library.\n"));
269 Alert(AT_DeadEnd | AG_OpenLib | AN_DOSLib | AO_ExpansionLib);
272 if ((mp = CreateMsgPort()) != NULL)
274 if ((tr = (struct timerequest *)CreateIORequest(mp, sizeof(struct timerequest))) != NULL)
277 if ((OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)tr, 0)) == 0)
278 #define ioStd(x) ((struct IOStdReq *)x)
279 ioStd(tr)->io_Command = TR_ADDREQUEST;
280 else
282 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open timer.device.\n"));
283 DeleteMsgPort(mp);
284 DeleteIORequest((struct IORequest *)tr);
285 tr = NULL;
289 if (tr == NULL)
291 DeleteMsgPort(mp);
295 /**** Try to mount all filesystems in the MountList ****************************/
296 D(bug("[DOSBoot] __dosboot_BootProcess: Checking expansion.library/MountList for useable nodes:\n"));
298 ForeachNode(&ExpansionBase->MountList, bootNode)
300 D(bug("[DOSBoot] __dosboot_BootProcess: BootNode: %p, bn_DeviceNode: %p, Name '%s', Priority %4d\n",
301 bootNode, bootNode->bn_DeviceNode,
302 deviceName ? deviceName : "(null)",
303 bootNode->bn_Node.ln_Pri
306 Try to mount the filesystem. If it fails, mark the BootNode
307 so DOS doesn't try to boot from it later but will retry to
308 mount it after boot device is found and system directories
309 assigned.
312 if (!(__dosboot_Mount( (struct DeviceNode *) bootNode->bn_DeviceNode ,
313 (struct DosLibrary *) DOSBase)))
315 bootNode->bn_Flags |= BNF_RETRY;
316 D(bug("[DOSBoot] __dosboot_BootProcess: Marked '%s' as needing retry\n",
317 deviceName ? deviceName : "(null)"));
319 else
321 bootNode->bn_Flags &= ~BNF_RETRY;
322 D(bug("[DOSBoot] __dosboot_BootProcess: Marked '%s' as useable\n",
323 deviceName ? deviceName : "(null)"));
327 /**** Try to find a bootable filesystem ****************************************/
328 while (LIBBASE->db_BootDevice == NULL)
330 ForeachNode(&ExpansionBase->MountList, bootNode)
332 D(bug("[DOSBoot] __dosboot_BootProcess: Trying '%s' ...\n", deviceName ? deviceName : "(null)"));
333 /* Check if the mounted filesystem is bootable. If it's not,
334 it's probably some kind of transient error (ie. no disk
335 in drive or wrong disk) so we only move it to the end of
336 the list. */
337 if ((!(bootNode->bn_Flags & BNF_RETRY)) && (bootNode->bn_Node.ln_Pri != -128) &&
338 __dosboot_IsBootable(deviceName, (struct DosLibrary *)DOSBase))
340 LIBBASE->db_BootDevice = deviceName;
341 break;
345 if (!(LIBBASE->db_BootDevice))
347 /* Check if Gfx are up .. and if so show insert media animation */
348 if (LIBBASE->db_attemptingboot == FALSE)
350 #warning "TODO: Show insert disc animation !"
351 LIBBASE->db_attemptingboot = TRUE;
353 else
355 #warning "TODO: re-run insert disc animation !"
357 #if defined(DOSBOOT_DISCINSERT_SCREENPRINT)
358 kprintf("No bootable disk was found.\n");
359 kprintf("Please insert a bootable disk in any drive.\n");
361 kprintf("Retrying in 5 seconds...\n");
362 #endif
364 if (tr != NULL) {
365 tr->tr_time.tv_secs = 5;
366 tr->tr_time.tv_micro = 0;
367 DoIO((struct IORequest *)tr);
368 } else
369 Delay(500);
373 if (mp)
374 DeleteMsgPort(mp);
376 if (tr)
378 CloseDevice((struct IORequest *)tr);
379 DeleteIORequest((struct IORequest *)tr);
382 if (LIBBASE->db_BootDevice != NULL)
384 /* Construct the complete device name of the boot device */
385 bootNameLength = strlen( LIBBASE->db_BootDevice) + 2;
387 if ((bootName = AllocMem(bootNameLength, MEMF_ANY|MEMF_CLEAR)) == NULL)
389 Alert(AT_DeadEnd | AG_NoMemory | AO_DOSLib | AN_StartMem);
392 strcpy(bootName, LIBBASE->db_BootDevice);
393 strcat(bootName, ":");
395 bug("[DOSBoot] __dosboot_BootProcess: Booting from device '%s'\n", bootName);
397 /* Lock the boot device and add some default assigns */
398 lock = Lock(bootName, SHARED_LOCK);
399 if (lock) DOSBase->dl_SYSLock = DupLock(lock);
401 if ((lock != NULL) && (DOSBase->dl_SYSLock != NULL))
403 AssignLock("SYS", lock);
405 else
407 Alert(AT_DeadEnd | AG_BadParm | AN_DOSLib);
410 FreeMem( bootName, bootNameLength );
412 if ((lock = Lock("SYS:", SHARED_LOCK)) != NULL)
414 CurrentDir(lock);
416 else
418 Alert(AT_DeadEnd | AG_BadParm | AN_DOSLib);
421 if ((lock = Lock("SYS:C", SHARED_LOCK)) != NULL)
423 AssignLock("C", lock);
426 if ((lock = Lock("SYS:S", SHARED_LOCK)) != NULL)
428 AssignLock("S", lock);
431 if ((lock = Lock("SYS:Libs", SHARED_LOCK)) != NULL)
433 AssignLock("LIBS", lock);
436 if ((lock = Lock("SYS:Devs", SHARED_LOCK)) != NULL)
438 AssignLock("DEVS", lock);
441 if ((lock = Lock("DEVS:Drivers", SHARED_LOCK)) != NULL)
443 AssignLock("DRIVERS", lock);
444 AssignAdd("LIBS", lock); /* Let hidds in DRIVERS: directory be found by OpenLibrary */
447 if ((lock = Lock("SYS:L", SHARED_LOCK)) != NULL)
449 AssignLock("L", lock);
452 /* Late binding ENVARC: assign, only if used */
453 AssignLate("ENVARC", "SYS:Prefs/env-archive");
456 Attempt to mount filesystems marked for retry. If it fails again,
457 remove the BootNode from the list.
459 ForeachNodeSafe(&ExpansionBase->MountList, bootNode, tmpNode)
461 if (bootNode->bn_Flags & BNF_RETRY)
463 D(bug("[DOSBoot] __dosboot_BootProcess: Retrying node: %p, DevNode: %p, Name = %s\n", bootNode, bootNode->bn_DeviceNode, deviceName ? deviceName : "(null)" ));
464 if( !__dosboot_Mount((struct DeviceNode *)bootNode->bn_DeviceNode, (struct DosLibrary *)DOSBase))
466 REMOVE( bootNode );
471 /* We don't need expansion.library any more */
472 CloseLibrary( (struct Library *) ExpansionBase );
474 /* Initialize HIDDs */
475 hidds_ok = __dosboot_InitHidds(SysBase, (struct DosLibrary *)DOSBase);
477 /* We now call the system dependant boot - should NEVER return! */
478 __dosboot_Boot(SysBase, hidds_ok);
481 //We Should NEVER reach here!
482 #undef deviceName
484 AROS_USERFUNC_EXIT
487 int dosboot_Init(LIBBASETYPEPTR LIBBASE)
489 struct TagItem bootprocess[] =
491 { NP_Entry, (IPTR) __dosboot_BootProcess },
492 { NP_Name, (IPTR) "Boot Process" },
493 { NP_UserData, (IPTR) LIBBASE },
494 { NP_Input, (IPTR) NULL },
495 { NP_Output, (IPTR) NULL },
496 { NP_WindowPtr, -1 },
497 { NP_CurrentDir, (IPTR) NULL },
498 { NP_StackSize, AROS_STACKSIZE * 2 },
499 { NP_Cli, (IPTR) 0 },
500 { TAG_END, }
503 D(bug("[DOSBoot] dosboot_Init()\n"));
504 D(bug("[DOSBoot] dosboot_Init: Launching Boot Process control task ..\n"));
506 LIBBASE->db_BootDevice = NULL;
507 LIBBASE->db_attemptingboot = FALSE;
509 if (CreateNewProc(bootprocess) == NULL)
511 D(bug("[DOSBoot] dosboot_Init: CreateNewProc() failed with %ld\n", ((struct Process *)FindTask(NULL))->pr_Result2));
512 Alert( AT_DeadEnd | AN_DOSLib | AG_ProcCreate );
514 return TRUE;
517 ADD2INITLIB(dosboot_Init, 0)