2 Copyright 1995-2008, The AROS Development Team. All rights reserved.
3 $Id: dosboot_init.c 30220 2009-01-04 22:38:44Z schulz $
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
)
142 struct InfoData info
;
144 #if defined(AROS_BOOT_CHECKSIG)
145 #define AROSBOOTSIG_FILE ":AROS.boot"
146 bufferLength
= strlen(deviceName
) + sizeof(AROSBOOTSIG_FILE
) + 1;
148 if ((buffer
= AllocMem(bufferLength
, MEMF_ANY
)) == NULL
)
150 Alert(AT_DeadEnd
| AG_NoMemory
| AN_DOSLib
);
153 strcpy(buffer
, deviceName
);
154 strcat(buffer
, AROSBOOTSIG_FILE
);
156 if ((lock
= Open(buffer
, MODE_OLDFILE
)) == 0)
158 D(bug("[DOSBoot] __dosboot_IsBootable: Failed to open '%s'\n", buffer
));
162 D(bug("[DOSBoot] __dosboot_IsBootable: Opened '%s'\n", buffer
));
164 if (Read(lock
, buffer
, bufferLength
) != -1)
167 D(bug("[DOSBoot] __dosboot_IsBootable: Buffer contains '%s'\n", buffer
));
168 if ((sigptr
= strstr(buffer
, AROS_ARCHITECTURE
)) != NULL
)
170 D(bug("[DOSBoot] __dosboot_IsBootable: Signature '%s' found\n", sigptr
));
179 #define STARTUP_SEQUENCE_FILE ":C/Shell"
181 bufferLength
= strlen(deviceName
) + sizeof(STARTUP_SEQUENCE_FILE
) + 1;
183 if ((buffer
= AllocMem(bufferLength
, MEMF_ANY
)) == NULL
)
185 Alert(AT_DeadEnd
| AG_NoMemory
| AN_DOSLib
);
188 strcpy(buffer
, deviceName
);
189 strcat(buffer
, STARTUP_SEQUENCE_FILE
);
191 D(bug("[DOSBoot] __dosboot_IsBootable: Trying to get a lock on '%s'\n", buffer
));
193 if ((lock
= Lock(buffer
, SHARED_LOCK
)) == 0)
195 D(bug("[DOSBoot] __dosboot_IsBootable: could not lock '%s'\n", buffer
));
199 if (!Info(lock
, &info
))
201 D(bug("[DOSBoot] __dosboot_IsBootable: could not get info on '%s'\n", buffer
));
205 if (info
.id_DiskType
!= ID_NO_DISK_PRESENT
)
212 if (buffer
!= NULL
) FreeMem(buffer
, bufferLength
);
213 if (lock
!= 0 ) UnLock(lock
);
220 AROS_UFH3(void, __dosboot_BootProcess
,
221 AROS_UFHA(APTR
, argString
, A0
),
222 AROS_UFHA(ULONG
, argSize
, D0
),
223 AROS_UFHA(struct ExecBase
*,SysBase
, A6
)
228 struct ExpansionBase
*ExpansionBase
= NULL
;
229 struct DosLibrary
*DOSBase
= NULL
;
230 LIBBASETYPEPTR LIBBASE
= FindTask(NULL
)->tc_UserData
;
232 struct BootNode
*bootNode
= NULL
;
233 struct Node
*tmpNode
= NULL
;
239 struct MsgPort
*mp
; // Message port used with timer.device
240 struct timerequest
*tr
= NULL
; // timer's time request message
242 D(bug("[DOSBoot] __dosboot_BootProcess()\n" ));
244 LIBBASE
->db_bootdevicefound
= FALSE
;
245 LIBBASE
->db_attemptingboot
= FALSE
;
247 #define deviceName (((struct DosList *) bootNode->bn_DeviceNode)->dol_Ext.dol_AROS.dol_DevName)
249 /**** Open all required libraries **********************************************/
250 if ((DOSBase
= (struct DosLibrary
*)OpenLibrary("dos.library", 0)) == NULL
)
252 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open dos.library.\n" ));
253 Alert(AT_DeadEnd
| AG_OpenLib
| AN_DOSLib
| AO_DOSLib
);
256 if ((ExpansionBase
= (struct ExpansionBase
*)OpenLibrary("expansion.library", 0)) == NULL
)
258 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open expansion.library.\n"));
259 Alert(AT_DeadEnd
| AG_OpenLib
| AN_DOSLib
| AO_ExpansionLib
);
262 if ((mp
= CreateMsgPort()) != NULL
)
264 if ((tr
= (struct timerequest
*)CreateIORequest(mp
, sizeof(struct timerequest
))) != NULL
)
267 if ((OpenDevice("timer.device", UNIT_VBLANK
, (struct IORequest
*)tr
, 0)) == 0)
268 #define ioStd(x) ((struct IOStdReq *)x)
269 ioStd(tr
)->io_Command
= TR_ADDREQUEST
;
272 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open timer.device.\n"));
274 DeleteIORequest((struct IORequest
*)tr
);
285 /**** Try to mount all filesystems in the MountList ****************************/
286 D(bug("[DOSBoot] __dosboot_BootProcess: Checking MountList for useable nodes:\n"));
288 ForeachNode(&ExpansionBase
->MountList
, bootNode
)
290 D(bug("[DOSBoot] __dosboot_BootProcess: BootNode: %p, bn_DeviceNode: %p, Name '%s', Priority %4d\n",
291 bootNode
, bootNode
->bn_DeviceNode
,
292 deviceName
? deviceName
: "(null)",
293 bootNode
->bn_Node
.ln_Pri
296 Try to mount the filesystem. If it fails, mark the BootNode
297 so DOS doesn't try to boot from it later but will retry to
298 mount it after boot device is found and system directories
302 if (!(__dosboot_Mount( (struct DeviceNode
*) bootNode
->bn_DeviceNode
,
303 (struct DosLibrary
*) DOSBase
)))
305 bootNode
->bn_Flags
|= BNF_RETRY
;
306 D(bug("[DOSBoot] __dosboot_BootProcess: Marked '%s' as needing retry\n",
307 deviceName
? deviceName
: "(null)"));
311 bootNode
->bn_Flags
&= ~BNF_RETRY
;
312 D(bug("[DOSBoot] __dosboot_BootProcess: Marked '%s' as useable\n",
313 deviceName
? deviceName
: "(null)"));
317 /**** Try to find a bootable filesystem ****************************************/
318 while (LIBBASE
->db_bootdevicefound
== FALSE
)
320 ForeachNode(&ExpansionBase
->MountList
, bootNode
)
322 D(bug("[DOSBoot] __dosboot_BootProcess: Trying '%s' ...\n", deviceName
? deviceName
: "(null)"));
323 /* Check if the mounted filesystem is bootable. If it's not,
324 it's probably some kind of transient error (ie. no disk
325 in drive or wrong disk) so we only move it to the end of
327 if ((!(bootNode
->bn_Flags
& BNF_RETRY
)) && (bootNode
->bn_Node
.ln_Pri
!= -128) &&
328 __dosboot_IsBootable(deviceName
, (struct DosLibrary
*)DOSBase
))
330 LIBBASE
->db_bootdevicefound
= TRUE
;
335 if (!(LIBBASE
->db_bootdevicefound
))
337 if (!(LIBBASE
->db_attemptingboot
))
339 #warning "TODO: Show insert disc animation !"
340 LIBBASE
->db_attemptingboot
= TRUE
;
344 #warning "TODO: re-run insert disc animation !"
346 #if defined(DOSBOOT_DISCINSERT_SCREENPRINT)
347 kprintf("No bootable disk was found.\n");
348 kprintf("Please insert a bootable disk in any drive.\n");
350 kprintf("Retrying in 5 seconds...\n");
354 tr
->tr_time
.tv_secs
= 5;
355 tr
->tr_time
.tv_micro
= 0;
356 DoIO((struct IORequest
*)tr
);
367 CloseDevice((struct IORequest
*)tr
);
368 DeleteIORequest((struct IORequest
*)tr
);
371 if (LIBBASE
->db_bootdevicefound
)
373 /* Construct the complete device name of the boot device */
374 bootNameLength
= strlen(deviceName
) + 2;
376 if ((bootName
= AllocMem(bootNameLength
, MEMF_ANY
|MEMF_CLEAR
)) == NULL
)
378 Alert(AT_DeadEnd
| AG_NoMemory
| AO_DOSLib
| AN_StartMem
);
381 strcpy(bootName
, deviceName
);
382 strcat(bootName
, ":");
384 D(bug("[DOSBoot] __dosboot_BootProcess: Booting from device '%s'\n", bootName
));
386 /* Lock the boot device and add some default assigns */
387 lock
= Lock(bootName
, SHARED_LOCK
);
388 if (lock
) DOSBase
->dl_SYSLock
= DupLock(lock
);
390 if ((lock
!= NULL
) && (DOSBase
->dl_SYSLock
!= NULL
))
392 AssignLock("SYS", lock
);
396 Alert(AT_DeadEnd
| AG_BadParm
| AN_DOSLib
);
399 FreeMem( bootName
, bootNameLength
);
401 if ((lock
= Lock("SYS:", SHARED_LOCK
)) != NULL
)
407 Alert(AT_DeadEnd
| AG_BadParm
| AN_DOSLib
);
410 if ((lock
= Lock("SYS:C", SHARED_LOCK
)) != NULL
)
412 AssignLock("C", lock
);
415 if ((lock
= Lock("SYS:S", SHARED_LOCK
)) != NULL
)
417 AssignLock("S", lock
);
420 if ((lock
= Lock("SYS:Libs", SHARED_LOCK
)) != NULL
)
422 AssignLock("LIBS", lock
);
425 if ((lock
= Lock("SYS:Devs", SHARED_LOCK
)) != NULL
)
427 AssignLock("DEVS", lock
);
430 if ((lock
= Lock("DEVS:Drivers", SHARED_LOCK
)) != NULL
)
432 AssignLock("DRIVERS", lock
);
433 AssignAdd("LIBS", lock
); /* Let hidds in DRIVERS: directory be found by OpenLibrary */
436 if ((lock
= Lock("SYS:L", SHARED_LOCK
)) != NULL
)
438 AssignLock("L", lock
);
441 /* Late binding ENVARC: assign, only if used */
442 AssignLate("ENVARC", "SYS:Prefs/env-archive");
445 Attempt to mount filesystems marked for retry. If it fails again,
446 remove the BootNode from the list.
448 ForeachNodeSafe(&ExpansionBase
->MountList
, bootNode
, tmpNode
)
450 if (bootNode
->bn_Flags
& BNF_RETRY
)
452 D(bug("[DOSBoot] __dosboot_BootProcess: Retrying node: %p, DevNode: %p, Name = %s\n", bootNode
, bootNode
->bn_DeviceNode
, deviceName
? deviceName
: "(null)" ));
453 if( !__dosboot_Mount((struct DeviceNode
*)bootNode
->bn_DeviceNode
, (struct DosLibrary
*)DOSBase
))
460 /* We don't need expansion.library any more */
461 CloseLibrary( (struct Library
*) ExpansionBase
);
463 /* Initialize HIDDs */
464 hidds_ok
= __dosboot_InitHidds(SysBase
, (struct DosLibrary
*)DOSBase
);
466 /* We now call the system dependant boot - should NEVER return! */
467 __dosboot_Boot(SysBase
, hidds_ok
);
470 //We Should NEVER reach here!
476 int dosboot_Init(LIBBASETYPEPTR LIBBASE
)
478 struct TagItem bootprocess
[] =
480 { NP_Entry
, (IPTR
) __dosboot_BootProcess
},
481 { NP_Name
, (IPTR
) "Boot Process" },
482 { NP_UserData
, (IPTR
) LIBBASE
},
483 { NP_Input
, (IPTR
) NULL
},
484 { NP_Output
, (IPTR
) NULL
},
485 { NP_WindowPtr
, -1 },
486 { NP_CurrentDir
, (IPTR
) NULL
},
487 { NP_StackSize
, AROS_STACKSIZE
* 2 },
488 { NP_Cli
, (IPTR
) 0 },
492 D(bug("[DOSBoot] dosboot_Init()\n"));
493 D(bug("[DOSBoot] dosboot_Init: Launching Boot Process control task ..\n"));
495 if (CreateNewProc(bootprocess
) == NULL
)
497 D(bug("[DOSBoot] dosboot_Init: CreateNewProc() failed with %ld\n", ((struct Process
*)FindTask(NULL
))->pr_Result2
));
498 Alert( AT_DeadEnd
| AN_DOSLib
| AG_ProcCreate
);
503 ADD2INITLIB(dosboot_Init
, 0)