2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
5 Desc: Start up the ol' Dos boot process.
9 #define AROS_BOOT_CHECKSIG
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>
37 #include LC_LIBDEFS_FILE
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
)
58 D(bug("[DOSBoot] __dosboot_Mount: handler=%08lx stack=%08x seglist=%08x\n",
59 dn
->dn_Handler
, dn
->dn_StackSize
, dn
->dn_SegList
));
62 D(bug("[DOSBoot] __dosboot_Mount: Attempting to mount\n"));
63 rc
= __dosboot_RunHandler(dn
, DOSBase
);
67 D(bug("[DOSBoot] __dosboot_Mount: Volume already mounted\n"));
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
);
84 /** Support Functions **/
85 /* Attempt to start a handler for the DeviceNode */
86 BOOL
__dosboot_RunHandler(struct DeviceNode
*deviceNode
, struct DosLibrary
*DOSBase
)
89 struct IOFileSys
*iofs
;
93 D(bug("[DOSBoot] __dosboot_RunHandler()\n" ));
98 iofs
= (struct IOFileSys
*)CreateIORequest(mp
, sizeof(struct IOFileSys
));
103 struct FileSysStartupMsg
*fssm
;
106 if (deviceNode
->dn_Handler
== BNULL
)
108 handler
= "afs.handler";
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
);
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
);
134 D(bug("[DOSBoot] __dosboot_RunHandler: Retrying with packet.handler\n"));
135 opened
= !OpenDevice("packet.handler", 0, &iofs
->IOFS
, fssmFlags
);
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);
148 DeleteIORequest(&iofs
->IOFS
);
156 static BOOL
__dosboot_Mount(struct DeviceNode
*dn
, struct DosLibrary
* DOSBase
)
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
);
169 D(bug("[DOSBoot] __dosboot_Mount: Volume already mounted\n"));
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
);
186 static BOOL
__dosboot_IsBootable(CONST_STRPTR deviceName
, struct DosLibrary
* DOSBase
)
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
);
203 sprintf(buffer
, "%s:", deviceName
);
204 if ((lock
= Lock(buffer
, SHARED_LOCK
)))
212 #if defined(AROS_BOOT_CHECKSIG)
213 #define AROSBOOTSIG_FILE ":AROS.boot"
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
));
234 D(bug("[DOSBoot] __dosboot_IsBootable: Opened '%s'\n", buffer
));
235 FreeMem(buffer
, bufferLength
);
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)
252 buffer
[readsize
] = '\0';
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
));
268 #define SHELL_FILE ":C/Shell"
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
));
298 if (buffer
!= NULL
) FreeMem(buffer
, bufferLength
);
300 D(bug("[DOSBoot] __dosboot_IsBootable returned %d\n", result
));
305 static void AddBootAssign(CONST_STRPTR path
, CONST_STRPTR assign
)
308 if (!(lock
= Lock(path
, SHARED_LOCK
)))
309 lock
= Lock("SYS:", SHARED_LOCK
);
311 AssignLock(assign
, lock
);
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
)
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
;
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
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
));
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
391 if ((!(bootNode
->bn_Flags
& BNF_RETRY
)) && (bootNode
->bn_Node
.ln_Pri
!= -128)
392 && __dosboot_IsBootable(deviceName
, DOSBase
))
394 LIBBASE
->db_BootDevice
= deviceName
;
399 if (!(LIBBASE
->db_BootDevice
))
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"));
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
;
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
));
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
);
450 DOSBase
->dl_SYSLock
= DupLock(lock
);
452 if ((lock
!= BNULL
) && (DOSBase
->dl_SYSLock
!= BNULL
))
454 AssignLock("SYS", lock
);
458 Alert(AT_DeadEnd
| AG_BadParm
| AN_DOSLib
);
461 FreeMem( bootName
, bootNameLength
);
463 if ((lock
= Lock("SYS:", SHARED_LOCK
)) != BNULL
)
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");
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 */
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
))
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
);
515 /* Initialize HIDDs */
516 if (!(LIBBASE
->BootFlags
& BF_NO_DISPLAY_DRIVERS
))
518 D(bug("[DOSBoot] Loading display drivers\n"));
519 __dosboot_InitHidds(DOSBase
);
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!
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 },
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
);
565 ADD2INITLIB(dosboot_Init
, 1)