2 Copyright � 1995-2009, 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 D(bug("[DOSBoot] __dosboot_IsBootable('%s')\n", deviceName
));
146 #if defined(AROS_BOOT_CHECKSIG)
147 #define AROSBOOTSIG_FILE ":AROS.boot"
149 struct FileInfoBlock abfile_fib
;
150 bufferLength
= strlen(deviceName
) + sizeof(AROSBOOTSIG_FILE
) + 1;
152 if ((buffer
= AllocMem(bufferLength
, MEMF_ANY
)) == NULL
)
154 Alert(AT_DeadEnd
| AG_NoMemory
| AN_DOSLib
);
157 strcpy(buffer
, deviceName
);
158 strcat(buffer
, AROSBOOTSIG_FILE
);
160 if ((lock
= Open(buffer
, MODE_OLDFILE
)) == 0)
162 D(bug("[DOSBoot] __dosboot_IsBootable: Failed to open '%s'\n", buffer
));
166 D(bug("[DOSBoot] __dosboot_IsBootable: Opened '%s'\n", buffer
));
167 FreeMem(buffer
, bufferLength
);
170 if (ExamineFH(lock
, &abfile_fib
))
172 bufferLength
= abfile_fib
.fib_Size
+ 1;
174 if ((buffer
= AllocMem(bufferLength
, MEMF_ANY
)) == NULL
)
176 Alert(AT_DeadEnd
| AG_NoMemory
| AN_DOSLib
);
178 D(bug("[DOSBoot] __dosboot_IsBootable: Allocated %d bytes for Buffer @ %p\n", bufferLength
, buffer
));
179 if ((readsize
= Read(lock
, buffer
, (bufferLength
- 1))) != -1)
184 buffer
[readsize
] = '\0';
186 buffer
[bufferLength
- 1] = '\0';
188 D(bug("[DOSBoot] __dosboot_IsBootable: Buffer contains '%s'\n", buffer
));
189 if ((sigptr
= strstr(buffer
, AROS_ARCHITECTURE
)) != NULL
)
191 D(bug("[DOSBoot] __dosboot_IsBootable: Signature '%s' found\n", sigptr
));
200 #define SHELL_FILE ":C/Shell"
202 bufferLength
= strlen(deviceName
) + sizeof(SHELL_FILE
) + 1;
204 if ((buffer
= AllocMem(bufferLength
, MEMF_PUBLIC
)) == NULL
)
206 Alert(AT_DeadEnd
| AG_NoMemory
| AN_DOSLib
);
209 strcpy(buffer
, deviceName
);
210 strcat(buffer
, SHELL_FILE
);
212 D(bug("[DOSBoot] __dosboot_IsBootable: "
213 "Trying to load '%s' as an executable\n", buffer
));
215 if ((seglist
= LoadSeg(buffer
)) == (BPTR
)NULL
)
217 D(bug("[DOSBoot] __dosboot_IsBootable: could not load '%s'\n", buffer
));
227 if (buffer
!= NULL
) FreeMem(buffer
, bufferLength
);
234 AROS_UFH3(void, __dosboot_BootProcess
,
235 AROS_UFHA(APTR
, argString
, A0
),
236 AROS_UFHA(ULONG
, argSize
, D0
),
237 AROS_UFHA(struct ExecBase
*,SysBase
, A6
)
242 struct ExpansionBase
*ExpansionBase
= NULL
;
243 struct DosLibrary
*DOSBase
= NULL
;
244 LIBBASETYPEPTR LIBBASE
= FindTask(NULL
)->tc_UserData
;
246 struct BootNode
*bootNode
= NULL
;
247 struct Node
*tmpNode
= NULL
;
253 struct MsgPort
*mp
; // Message port used with timer.device
254 struct timerequest
*tr
= NULL
; // timer's time request message
256 D(bug("[DOSBoot] __dosboot_BootProcess()\n" ));
258 #define deviceName (((struct DosList *) bootNode->bn_DeviceNode)->dol_Ext.dol_AROS.dol_DevName)
260 /**** Open all required libraries **********************************************/
261 if ((DOSBase
= (struct DosLibrary
*)OpenLibrary("dos.library", 0)) == NULL
)
263 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open dos.library.\n" ));
264 Alert(AT_DeadEnd
| AG_OpenLib
| AN_DOSLib
| AO_DOSLib
);
267 if ((ExpansionBase
= (struct ExpansionBase
*)OpenLibrary("expansion.library", 0)) == NULL
)
269 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open expansion.library.\n"));
270 Alert(AT_DeadEnd
| AG_OpenLib
| AN_DOSLib
| AO_ExpansionLib
);
273 if ((mp
= CreateMsgPort()) != NULL
)
275 if ((tr
= (struct timerequest
*)CreateIORequest(mp
, sizeof(struct timerequest
))) != NULL
)
278 if ((OpenDevice("timer.device", UNIT_VBLANK
, (struct IORequest
*)tr
, 0)) == 0)
279 #define ioStd(x) ((struct IOStdReq *)x)
280 ioStd(tr
)->io_Command
= TR_ADDREQUEST
;
283 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open timer.device.\n"));
285 DeleteIORequest((struct IORequest
*)tr
);
296 /**** Try to mount all filesystems in the MountList ****************************/
297 D(bug("[DOSBoot] __dosboot_BootProcess: Checking expansion.library/MountList for useable nodes:\n"));
299 ForeachNode(&ExpansionBase
->MountList
, bootNode
)
301 D(bug("[DOSBoot] __dosboot_BootProcess: BootNode: %p, bn_DeviceNode: %p, Name '%s', Priority %4d\n",
302 bootNode
, bootNode
->bn_DeviceNode
,
303 deviceName
? deviceName
: "(null)",
304 bootNode
->bn_Node
.ln_Pri
307 Try to mount the filesystem. If it fails, mark the BootNode
308 so DOS doesn't try to boot from it later but will retry to
309 mount it after boot device is found and system directories
313 if (!(__dosboot_Mount( (struct DeviceNode
*) bootNode
->bn_DeviceNode
,
314 (struct DosLibrary
*) DOSBase
)))
316 bootNode
->bn_Flags
|= BNF_RETRY
;
317 D(bug("[DOSBoot] __dosboot_BootProcess: Marked '%s' as needing retry\n",
318 deviceName
? deviceName
: "(null)"));
322 bootNode
->bn_Flags
&= ~BNF_RETRY
;
323 D(bug("[DOSBoot] __dosboot_BootProcess: Marked '%s' as useable\n",
324 deviceName
? deviceName
: "(null)"));
328 /**** Try to find a bootable filesystem ****************************************/
329 while (LIBBASE
->db_BootDevice
== NULL
)
331 ForeachNode(&ExpansionBase
->MountList
, bootNode
)
333 D(bug("[DOSBoot] __dosboot_BootProcess: Trying '%s' ...\n", deviceName
? deviceName
: "(null)"));
334 /* Check if the mounted filesystem is bootable. If it's not,
335 it's probably some kind of transient error (ie. no disk
336 in drive or wrong disk) so we only move it to the end of
338 if ((!(bootNode
->bn_Flags
& BNF_RETRY
)) && (bootNode
->bn_Node
.ln_Pri
!= -128) &&
339 __dosboot_IsBootable(deviceName
, (struct DosLibrary
*)DOSBase
))
341 LIBBASE
->db_BootDevice
= deviceName
;
346 if (!(LIBBASE
->db_BootDevice
))
348 /* Check if Gfx are up .. and if so show insert media animation */
349 if (LIBBASE
->db_attemptingboot
== FALSE
)
351 #warning "TODO: Show insert disc animation !"
352 LIBBASE
->db_attemptingboot
= TRUE
;
356 #warning "TODO: re-run insert disc animation !"
358 #if defined(DOSBOOT_DISCINSERT_SCREENPRINT)
359 kprintf("No bootable disk was found.\n");
360 kprintf("Please insert a bootable disk in any drive.\n");
362 kprintf("Retrying in 5 seconds...\n");
366 tr
->tr_time
.tv_secs
= 5;
367 tr
->tr_time
.tv_micro
= 0;
368 DoIO((struct IORequest
*)tr
);
379 CloseDevice((struct IORequest
*)tr
);
380 DeleteIORequest((struct IORequest
*)tr
);
383 if (LIBBASE
->db_BootDevice
!= NULL
)
385 /* Construct the complete device name of the boot device */
386 bootNameLength
= strlen( LIBBASE
->db_BootDevice
) + 2;
388 if ((bootName
= AllocMem(bootNameLength
, MEMF_ANY
|MEMF_CLEAR
)) == NULL
)
390 Alert(AT_DeadEnd
| AG_NoMemory
| AO_DOSLib
| AN_StartMem
);
393 strcpy(bootName
, LIBBASE
->db_BootDevice
);
394 strcat(bootName
, ":");
396 bug("[DOSBoot] __dosboot_BootProcess: Booting from device '%s'\n", bootName
);
398 /* Lock the boot device and add some default assigns */
399 lock
= Lock(bootName
, SHARED_LOCK
);
400 if (lock
) DOSBase
->dl_SYSLock
= DupLock(lock
);
402 if ((lock
!= NULL
) && (DOSBase
->dl_SYSLock
!= NULL
))
404 AssignLock("SYS", lock
);
408 Alert(AT_DeadEnd
| AG_BadParm
| AN_DOSLib
);
411 FreeMem( bootName
, bootNameLength
);
413 if ((lock
= Lock("SYS:", SHARED_LOCK
)) != NULL
)
419 Alert(AT_DeadEnd
| AG_BadParm
| AN_DOSLib
);
422 if ((lock
= Lock("SYS:C", SHARED_LOCK
)) != NULL
)
424 AssignLock("C", lock
);
427 if ((lock
= Lock("SYS:S", SHARED_LOCK
)) != NULL
)
429 AssignLock("S", lock
);
432 if ((lock
= Lock("SYS:Libs", SHARED_LOCK
)) != NULL
)
434 AssignLock("LIBS", lock
);
437 if ((lock
= Lock("SYS:Devs", SHARED_LOCK
)) != NULL
)
439 AssignLock("DEVS", lock
);
442 if ((lock
= Lock("DEVS:Drivers", SHARED_LOCK
)) != NULL
)
444 AssignLock("DRIVERS", lock
);
445 AssignAdd("LIBS", lock
); /* Let hidds in DRIVERS: directory be found by OpenLibrary */
448 if ((lock
= Lock("SYS:L", SHARED_LOCK
)) != NULL
)
450 AssignLock("L", lock
);
453 /* Late binding ENVARC: assign, only if used */
454 AssignLate("ENVARC", "SYS:Prefs/env-archive");
457 Attempt to mount filesystems marked for retry. If it fails again,
458 remove the BootNode from the list.
460 ForeachNodeSafe(&ExpansionBase
->MountList
, bootNode
, tmpNode
)
462 if (bootNode
->bn_Flags
& BNF_RETRY
)
464 D(bug("[DOSBoot] __dosboot_BootProcess: Retrying node: %p, DevNode: %p, Name = %s\n", bootNode
, bootNode
->bn_DeviceNode
, deviceName
? deviceName
: "(null)" ));
465 if( !__dosboot_Mount((struct DeviceNode
*)bootNode
->bn_DeviceNode
, (struct DosLibrary
*)DOSBase
))
472 /* We don't need expansion.library any more */
473 CloseLibrary( (struct Library
*) ExpansionBase
);
475 /* Initialize HIDDs */
476 hidds_ok
= __dosboot_InitHidds(SysBase
, (struct DosLibrary
*)DOSBase
);
478 /* We now call the system dependant boot - should NEVER return! */
479 __dosboot_Boot(SysBase
, hidds_ok
);
482 //We Should NEVER reach here!
488 int dosboot_Init(LIBBASETYPEPTR LIBBASE
)
490 struct TagItem bootprocess
[] =
492 { NP_Entry
, (IPTR
) __dosboot_BootProcess
},
493 { NP_Name
, (IPTR
) "Boot Process" },
494 { NP_UserData
, (IPTR
) LIBBASE
},
495 { NP_Input
, (IPTR
) NULL
},
496 { NP_Output
, (IPTR
) NULL
},
497 { NP_WindowPtr
, -1 },
498 { NP_CurrentDir
, (IPTR
) NULL
},
499 { NP_StackSize
, AROS_STACKSIZE
* 2 },
500 { NP_Cli
, (IPTR
) 0 },
504 D(bug("[DOSBoot] dosboot_Init()\n"));
505 D(bug("[DOSBoot] dosboot_Init: Launching Boot Process control task ..\n"));
507 LIBBASE
->db_BootDevice
= NULL
;
508 LIBBASE
->db_attemptingboot
= FALSE
;
510 if (CreateNewProc(bootprocess
) == NULL
)
512 D(bug("[DOSBoot] dosboot_Init: CreateNewProc() failed with %ld\n", ((struct Process
*)FindTask(NULL
))->pr_Result2
));
513 Alert( AT_DeadEnd
| AN_DOSLib
| AG_ProcCreate
);
518 ADD2INITLIB(dosboot_Init
, 0)