2 Copyright � 1995-2009, The AROS Development Team. All rights reserved.
5 Desc: Start up the ol' Dos boot process.
9 #define AROS_BOOT_CHECKSIG
10 #define DOSBOOT_DISCINSERT_SCREENPRINT
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>
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
)
52 struct IOFileSys
*iofs
;
55 D(bug("[DOSBoot] __dosboot_RunHandler()\n" ));
60 iofs
= (struct IOFileSys
*)CreateIORequest(mp
, sizeof(struct IOFileSys
));
65 struct FileSysStartupMsg
*fssm
;
68 if (deviceNode
->dn_Handler
== NULL
)
70 handler
= "afs.handler";
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
);
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
;
103 DeleteIORequest(&iofs
->IOFS
);
111 static BOOL
__dosboot_Mount(struct DeviceNode
*dn
, struct DosLibrary
* DOSBase
)
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
);
122 D(bug("[DOSBoot] __dosboot_Mount: Volume already mounted\n"));
128 if (!AddDosEntry((struct DosList
*) dn
))
130 Alert(AT_DeadEnd
| AG_NoMemory
| AN_DOSLib
);
136 static BOOL
__dosboot_IsBootable(CONST_STRPTR deviceName
, struct DosLibrary
* DOSBase
)
143 D(bug("[DOSBoot] __dosboot_IsBootable('%s')\n", deviceName
));
145 #if defined(AROS_BOOT_CHECKSIG)
146 #define AROSBOOTSIG_FILE ":AROS.boot"
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
));
165 D(bug("[DOSBoot] __dosboot_IsBootable: Opened '%s'\n", buffer
));
166 FreeMem(buffer
, bufferLength
);
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)
183 buffer
[readsize
] = '\0';
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
));
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
));
226 if (buffer
!= NULL
) FreeMem(buffer
, bufferLength
);
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
)
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
;
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
;
282 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open timer.device.\n"));
284 DeleteIORequest((struct IORequest
*)tr
);
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
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)"));
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
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
;
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
;
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");
365 tr
->tr_time
.tv_secs
= 5;
366 tr
->tr_time
.tv_micro
= 0;
367 DoIO((struct IORequest
*)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
);
407 Alert(AT_DeadEnd
| AG_BadParm
| AN_DOSLib
);
410 FreeMem( bootName
, bootNameLength
);
412 if ((lock
= Lock("SYS:", SHARED_LOCK
)) != NULL
)
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
))
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!
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 },
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
);
517 ADD2INITLIB(dosboot_Init
, 0)