use same location as .configured, etc, to store .files-touched
[AROS.git] / rom / dosboot / dosboot_init.c
blob5b82c6914c02c87e03ad6e9b63342a3249b14648
1 /*
2 Copyright © 1995-2010, 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
11 # define DEBUG 0
12 # include <aros/debug.h>
14 #include <aros/macros.h>
15 #include <aros/asmcall.h>
16 #include <aros/symbolsets.h>
18 #include <proto/exec.h>
19 #include <proto/dos.h>
21 #include <exec/types.h>
22 #include <exec/nodes.h>
23 #include <exec/lists.h>
24 #include <exec/execbase.h>
25 #include <exec/alerts.h>
26 #include <exec/memory.h>
27 #include <dos/dosextens.h>
28 #include <dos/dostags.h>
29 #include <dos/filehandler.h>
30 #include <dos/filesystem.h>
31 #include <libraries/expansionbase.h>
32 #include <devices/trackdisk.h>
34 #include <string.h>
35 #include <stdio.h>
37 #include LC_LIBDEFS_FILE
39 #include "menu.h"
40 #include "dosboot_intern.h"
42 #define BNF_RETRY 0x8000 /* Private flag for the BootNode */
43 #define BNF_MOUNTED 0x4000 /* Private flag for the BootNode */
45 #ifdef AROS_DOS_PACKETS
47 struct Process *RunPacketHandler(struct DeviceNode *dn, const char *name, struct DosLibrary *DOSBase);
49 BOOL __dosboot_RunHandler(struct DeviceNode *deviceNode, struct DosLibrary *DOSBase)
51 return RunPacketHandler(deviceNode, NULL, DOSBase) != NULL;
54 static BOOL __dosboot_Mount(struct DeviceNode *dn, struct DosLibrary * DOSBase)
56 BOOL rc;
58 D(bug("[DOSBoot] __dosboot_Mount: handler=%08lx stack=%08x seglist=%08x\n",
59 dn->dn_Handler, dn->dn_StackSize, dn->dn_SegList));
60 if (!dn->dn_Task)
62 D(bug("[DOSBoot] __dosboot_Mount: Attempting to mount\n"));
63 rc = __dosboot_RunHandler(dn, DOSBase);
65 else
67 D(bug("[DOSBoot] __dosboot_Mount: Volume already mounted\n"));
68 rc = TRUE;
71 if (rc)
73 if (!AddDosEntry((struct DosList *) dn))
75 kprintf("Mounting node %08lx (%s) failed at AddDosEntry() -- maybe it was already added by someone else!\n", dn, AROS_DOSDEVNAME(dn));
76 Alert(AT_DeadEnd | AG_NoMemory | AN_DOSLib);
79 return rc;
82 #else
84 /** Support Functions **/
85 /* Attempt to start a handler for the DeviceNode */
86 BOOL __dosboot_RunHandler(struct DeviceNode *deviceNode, struct DosLibrary *DOSBase)
88 struct MsgPort *mp;
89 struct IOFileSys *iofs;
90 BOOL ok = FALSE;
91 BOOL opened = FALSE;
93 D(bug("[DOSBoot] __dosboot_RunHandler()\n" ));
94 mp = CreateMsgPort();
96 if (mp != NULL)
98 iofs = (struct IOFileSys *)CreateIORequest(mp, sizeof(struct IOFileSys));
100 if (iofs != NULL)
102 STRPTR handler;
103 struct FileSysStartupMsg *fssm;
104 ULONG fssmFlags = 0;
106 if (deviceNode->dn_Handler == BNULL)
108 handler = "afs.handler";
110 else
112 handler = AROS_BSTR_ADDR(deviceNode->dn_Handler);
115 /* FIXME: this assumes that dol_Startup points to struct FileSysStartupMsg.
116 This is not true for plain handlers, dol_Startup is a BSTR in this case.
117 In order to make use of this we should implement direct support for
118 packet-style handlers in dos.library */
119 fssm = (struct FileSysStartupMsg *)BADDR(deviceNode->dn_Startup);
120 if (fssm != NULL)
122 iofs->io_Union.io_OpenDevice.io_DeviceName = AROS_BSTR_ADDR(fssm->fssm_Device);
123 iofs->io_Union.io_OpenDevice.io_Unit = fssm->fssm_Unit;
124 iofs->io_Union.io_OpenDevice.io_Environ = (IPTR *)BADDR(fssm->fssm_Environ);
125 fssmFlags = fssm->fssm_Flags;
127 iofs->io_Union.io_OpenDevice.io_DosName = deviceNode->dn_Ext.dn_AROS.dn_DevName;
128 iofs->io_Union.io_OpenDevice.io_DeviceNode = deviceNode;
130 D(bug("[DOSBoot] __dosboot_RunHandler: Starting up %s\n", handler));
131 opened = !OpenDevice(handler, 0, &iofs->IOFS, fssmFlags);
132 if(!opened)
134 D(bug("[DOSBoot] __dosboot_RunHandler: Retrying with packet.handler\n"));
135 opened = !OpenDevice("packet.handler", 0, &iofs->IOFS, fssmFlags);
137 if (opened)
139 /* Ok, this means that the handler was able to open. */
140 D(bug("[DOSBoot] __dosboot_RunHandler: Handler started\n"));
141 deviceNode->dn_Ext.dn_AROS.dn_Device = iofs->IOFS.io_Device;
142 deviceNode->dn_Ext.dn_AROS.dn_Unit = iofs->IOFS.io_Unit;
143 // FIXME I think the device must be closed again, especially because the IORequest is freed a few lines below (chodges, 04-08-2009)
144 //CloseDevice(&iofs->IOFS);
145 ok = TRUE;
148 DeleteIORequest(&iofs->IOFS);
151 DeleteMsgPort(mp);
153 return ok;
156 static BOOL __dosboot_Mount(struct DeviceNode *dn, struct DosLibrary * DOSBase)
158 BOOL rc;
160 D(bug("[DOSBoot] __dosboot_Mount: handler=%08lx stack=%08x seglist=%08x\n",
161 dn->dn_Handler, dn->dn_StackSize, dn->dn_SegList));
162 if (!dn->dn_Ext.dn_AROS.dn_Device)
164 D(bug("[DOSBoot] __dosboot_Mount: Attempting to mount\n"));
165 rc = __dosboot_RunHandler(dn, DOSBase);
167 else
169 D(bug("[DOSBoot] __dosboot_Mount: Volume already mounted\n"));
170 rc = TRUE;
173 if (rc)
175 if (!AddDosEntry((struct DosList *) dn))
177 kprintf("Mounting node %08lx (%s) failed at AddDosEntry() -- maybe it was already added by someone else!\n", dn, dn->dn_Ext.dn_AROS.dn_DevName);
178 Alert(AT_DeadEnd | AG_NoMemory | AN_DOSLib);
181 return rc;
184 #endif
186 static BOOL __dosboot_IsBootable(CONST_STRPTR deviceName, struct DosLibrary * DOSBase)
188 BPTR lock;
189 BOOL result = FALSE;
190 STRPTR buffer;
191 LONG bufferLength;
193 D(bug("[DOSBoot] __dosboot_IsBootable('%s')\n", deviceName));
195 #if (AROS_FLAVOUR & AROS_FLAVOUR_BINCOMPAT) && defined(mc68000)
198 bufferLength = strlen(deviceName) + 1 + 1;
199 /* bootable if we can lock the device */
200 buffer = AllocMem(bufferLength, MEMF_ANY);
201 if (!buffer)
202 return FALSE;
203 sprintf(buffer, "%s:", deviceName);
204 if ((lock = Lock(buffer, SHARED_LOCK)))
205 result = TRUE;
206 UnLock(lock);
207 lock = 0;
210 #else
212 #if defined(AROS_BOOT_CHECKSIG)
213 #define AROSBOOTSIG_FILE ":AROS.boot"
215 LONG readsize;
216 struct FileInfoBlock abfile_fib;
218 bufferLength = strlen(deviceName) + sizeof(AROSBOOTSIG_FILE) + 1;
220 if ((buffer = AllocMem(bufferLength, MEMF_ANY)) == NULL)
222 Alert(AT_DeadEnd | AG_NoMemory | AN_DOSLib);
225 strcpy(buffer, deviceName);
226 strcat(buffer, AROSBOOTSIG_FILE);
228 if ((lock = Open(buffer, MODE_OLDFILE)) == 0)
230 D(bug("[DOSBoot] __dosboot_IsBootable: Failed to open '%s'\n", buffer));
231 goto cleanup;
234 D(bug("[DOSBoot] __dosboot_IsBootable: Opened '%s'\n", buffer));
235 FreeMem(buffer, bufferLength);
236 buffer = NULL;
238 if (ExamineFH(lock, &abfile_fib))
240 bufferLength = abfile_fib.fib_Size + 1;
242 if ((buffer = AllocMem(bufferLength, MEMF_ANY)) == NULL)
244 Alert(AT_DeadEnd | AG_NoMemory | AN_DOSLib);
246 D(bug("[DOSBoot] __dosboot_IsBootable: Allocated %d bytes for Buffer @ %p\n", bufferLength, buffer));
247 if ((readsize = Read(lock, buffer, (bufferLength - 1))) != -1)
249 char *sigptr = NULL;
251 if (readsize != 0)
252 buffer[readsize] = '\0';
253 else
254 buffer[bufferLength - 1] = '\0';
256 D(bug("[DOSBoot] __dosboot_IsBootable: Buffer contains '%s'\n", buffer));
257 if ((sigptr = strstr(buffer, AROS_CPU)) != 0)
259 D(bug("[DOSBoot] __dosboot_IsBootable: Signature '%s' found\n", sigptr));
260 result = TRUE;
264 Close(lock);
265 lock = BNULL;
267 #else
268 #define SHELL_FILE ":C/Shell"
270 BPTR seglist;
272 bufferLength = strlen(deviceName) + sizeof(SHELL_FILE) + 1;
274 if ((buffer = AllocMem(bufferLength, MEMF_PUBLIC)) == NULL)
276 Alert(AT_DeadEnd | AG_NoMemory | AN_DOSLib);
279 strcpy(buffer, deviceName);
280 strcat(buffer, SHELL_FILE);
282 D(bug("[DOSBoot] __dosboot_IsBootable: "
283 "Trying to load '%s' as an executable\n", buffer));
285 if ((seglist = LoadSeg(buffer)) == (BPTR)NULL)
287 D(bug("[DOSBoot] __dosboot_IsBootable: could not load '%s'\n", buffer));
288 goto cleanup;
291 UnLoadSeg(seglist);
292 result = TRUE;
293 #endif
295 #endif
297 cleanup:
298 if (buffer != NULL ) FreeMem(buffer, bufferLength);
300 D(bug("[DOSBoot] __dosboot_IsBootable returned %d\n", result));
302 return result;
305 static void AddBootAssign(CONST_STRPTR path, CONST_STRPTR assign)
307 BPTR lock;
308 if (!(lock = Lock(path, SHARED_LOCK)))
309 lock = Lock("SYS:", SHARED_LOCK);
310 if (lock)
311 AssignLock(assign, lock);
314 /** Boot Code **/
316 AROS_UFH3(void, __dosboot_BootProcess,
317 AROS_UFHA(APTR, argString, A0),
318 AROS_UFHA(ULONG, argSize, D0),
319 AROS_UFHA(struct ExecBase *,SysBase, A6)
322 AROS_USERFUNC_INIT
324 struct ExpansionBase *ExpansionBase = NULL;
325 struct DosLibrary *DOSBase = NULL;
326 LIBBASETYPEPTR LIBBASE = FindTask(NULL)->tc_UserData;
328 struct BootNode *bootNode = NULL;
329 struct Node *tmpNode = NULL;
330 STRPTR bootName;
331 LONG bootNameLength;
332 BPTR lock;
333 APTR BootLoaderBase = OpenResource("bootloader.resource");
334 struct Screen *bootScreen = NULL;
336 D(bug("[DOSBoot] __dosboot_BootProcess()\n"));
338 #define deviceName AROS_DOSDEVNAME(bootNode->bn_DeviceNode)
340 /**** Open all required libraries **********************************************/
341 if ((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0)) == NULL)
343 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open dos.library.\n" ));
344 Alert(AT_DeadEnd| AG_OpenLib | AN_DOSLib | AO_DOSLib);
347 if ((ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library", 0)) == NULL)
349 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open expansion.library.\n"));
350 Alert(AT_DeadEnd | AG_OpenLib | AN_DOSLib | AO_ExpansionLib);
353 /**** Try to mount all filesystems in the MountList ****************************/
354 D(bug("[DOSBoot] __dosboot_BootProcess: Checking expansion.library/MountList for useable nodes:\n"));
356 ForeachNode(&ExpansionBase->MountList, bootNode)
358 D(bug("[DOSBoot] __dosboot_BootProcess: BootNode: %p, bn_DeviceNode: %p, Name '%s', Priority %4d\n",
359 bootNode, bootNode->bn_DeviceNode, deviceName, bootNode->bn_Node.ln_Pri
362 Try to mount the filesystem. If it fails, mark the BootNode
363 so DOS doesn't try to boot from it later but will retry to
364 mount it after boot device is found and system directories
365 assigned.
368 if (!(__dosboot_Mount( (struct DeviceNode *) bootNode->bn_DeviceNode, DOSBase)))
370 bootNode->bn_Flags |= BNF_RETRY;
371 D(bug("[DOSBoot] __dosboot_BootProcess: Marked '%s' as needing retry\n", deviceName));
373 else
375 bootNode->bn_Flags |= BNF_MOUNTED;
376 bootNode->bn_Flags &= ~BNF_RETRY;
377 D(bug("[DOSBoot] __dosboot_BootProcess: Marked '%s' as useable\n", deviceName));
381 /**** Try to find a bootable filesystem ****************************************/
382 while (LIBBASE->db_BootDevice == NULL)
384 ForeachNode(&ExpansionBase->MountList, bootNode)
386 D(bug("[DOSBoot] __dosboot_BootProcess: Trying '%s' ...\n", deviceName));
387 /* Check if the mounted filesystem is bootable. If it's not,
388 it's probably some kind of transient error (ie. no disk
389 in drive or wrong disk) so we only move it to the end of
390 the list. */
391 if ((!(bootNode->bn_Flags & BNF_RETRY)) && (bootNode->bn_Node.ln_Pri != -128)
392 && __dosboot_IsBootable(deviceName, DOSBase))
394 LIBBASE->db_BootDevice = deviceName;
395 break;
399 if (!(LIBBASE->db_BootDevice))
401 if (!bootScreen)
402 bootScreen = NoBootMediaScreen(LIBBASE);
404 D(kprintf("No bootable disk was found.\n"));
405 D(kprintf("Please insert a bootable disk in any drive.\n"));
406 D(kprintf("Retrying in 5 seconds...\n"));
408 Delay(500);
410 /* retry to mount stuff -- there might be some additional device in the meanwhile */
411 ForeachNode(&ExpansionBase->MountList, bootNode)
413 D(bug("[DOSBoot] __dosboot_BootProcess: Retrying to mount '%s' ...\n", deviceName));
414 if(((bootNode->bn_Flags & BNF_RETRY) || (!(bootNode->bn_Flags & BNF_MOUNTED))) && (bootNode->bn_Node.ln_Pri != -128))
416 if (!(__dosboot_Mount( (struct DeviceNode *) bootNode->bn_DeviceNode, DOSBase)))
418 bootNode->bn_Flags |= BNF_RETRY;
419 } else {
420 bootNode->bn_Flags |= BNF_MOUNTED;
421 bootNode->bn_Flags &= ~BNF_RETRY;
422 D(bug("[DOSBoot] __dosboot_BootProcess: Late marked '%s' as useable\n", deviceName));
429 if (bootScreen)
430 CloseBootScreen(bootScreen, LIBBASE);
432 if (LIBBASE->db_BootDevice != NULL)
434 /* Construct the complete device name of the boot device */
435 bootNameLength = strlen(LIBBASE->db_BootDevice) + 2;
437 if ((bootName = AllocMem(bootNameLength, MEMF_ANY|MEMF_CLEAR)) == NULL)
439 Alert(AT_DeadEnd | AG_NoMemory | AO_DOSLib | AN_StartMem);
442 strcpy(bootName, LIBBASE->db_BootDevice);
443 strcat(bootName, ":");
445 D(bug("[DOSBoot] __dosboot_BootProcess: Booting from device '%s'\n", bootName));
447 /* Lock the boot device and add some default assigns */
448 lock = Lock(bootName, SHARED_LOCK);
449 if (lock)
450 DOSBase->dl_SYSLock = DupLock(lock);
452 if ((lock != BNULL) && (DOSBase->dl_SYSLock != BNULL))
454 AssignLock("SYS", lock);
456 else
458 Alert(AT_DeadEnd | AG_BadParm | AN_DOSLib);
461 FreeMem( bootName, bootNameLength );
463 if ((lock = Lock("SYS:", SHARED_LOCK)) != BNULL)
465 CurrentDir(lock);
467 else
469 Alert(AT_DeadEnd | AG_BadParm | AN_DOSLib);
472 AddBootAssign("SYS:C", "C");
473 AddBootAssign("SYS:S", "S");
474 AddBootAssign("SYS:Libs", "LIBS");
475 AddBootAssign("SYS:Devs", "DEVS");
476 AddBootAssign("SYS:L", "L");
477 AddBootAssign("SYS:Fonts", "FONTS");
479 #if !(mc68000)
480 if ((lock = Lock("DEVS:Drivers", SHARED_LOCK)) != BNULL)
482 AssignLock("DRIVERS", lock);
483 AssignAdd("LIBS", lock); /* Let hidds in DRIVERS: directory be found by OpenLibrary */
485 #endif
487 /* Late binding ENVARC: assign, only if used */
488 AssignLate("ENVARC", "SYS:Prefs/env-archive");
491 Attempt to mount filesystems marked for retry. If it fails again,
492 remove the BootNode from the list.
494 D(bug("[DOSBoot] Assigns done, retrying mounting handlers\n"));
495 ForeachNodeSafe(&ExpansionBase->MountList, bootNode, tmpNode)
497 if (bootNode->bn_Flags & BNF_RETRY)
499 D(bug("[DOSBoot] __dosboot_BootProcess: Retrying node: %p, DevNode: %p, Name = %s\n", bootNode, bootNode->bn_DeviceNode, deviceName));
500 if( !__dosboot_Mount((struct DeviceNode *)bootNode->bn_DeviceNode, DOSBase))
502 Forbid();
503 REMOVE( bootNode );
504 Permit();
508 ExpansionBase->Flags |= EBF_BOOTFINISHED;
510 /* We don't need expansion.library any more */
511 D(bug("[DOSBoot] Closing expansion.library\n"));
512 CloseLibrary( (struct Library *) ExpansionBase );
514 #if !(mc68000)
515 /* Initialize HIDDs */
516 if (!(LIBBASE->BootFlags & BF_NO_DISPLAY_DRIVERS))
518 D(bug("[DOSBoot] Loading display drivers\n"));
519 __dosboot_InitHidds(DOSBase);
521 #endif
522 /* We now call the system dependant boot - should NEVER return! */
523 D(bug("[DOSBoot] Calling bootstrap code\n"));
524 __dosboot_Boot(BootLoaderBase, DOSBase, LIBBASE->BootFlags);
527 //We Should NEVER reach here!
528 #undef deviceName
530 AROS_USERFUNC_EXIT
533 int dosboot_Init(LIBBASETYPEPTR LIBBASE)
535 struct TagItem bootprocess[] =
537 { NP_Entry, (IPTR) __dosboot_BootProcess },
538 { NP_Name, (IPTR) "Boot Process" },
539 { NP_UserData, (IPTR) LIBBASE },
540 { NP_Input, (IPTR) NULL },
541 { NP_Output, (IPTR) NULL },
542 { NP_WindowPtr, -1 },
543 { NP_CurrentDir, (IPTR) NULL },
544 { NP_StackSize, AROS_STACKSIZE * 2 },
545 { NP_Cli, (IPTR) 0 },
546 { TAG_END, }
549 D(bug("[DOSBoot] dosboot_Init()\n"));
550 D(bug("[DOSBoot] dosboot_Init: Launching Boot Process control task ..\n"));
552 LIBBASE->db_BootDevice = NULL;
553 LIBBASE->BootFlags = 0;
555 bootmenu_Init(LIBBASE);
557 if (CreateNewProc(bootprocess) == NULL)
559 D(bug("[DOSBoot] dosboot_Init: CreateNewProc() failed with %ld\n", ((struct Process *)FindTask(NULL))->pr_Result2));
560 Alert( AT_DeadEnd | AN_DOSLib | AG_ProcCreate );
562 return TRUE;
565 ADD2INITLIB(dosboot_Init, 1)