some fixes to accented characters
[tangerine.git] / rom / dosboot / dosboot_init.c
blob8ab3386785b87fcb44bf53bd75bee5e6d641a9b6
1 /*
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.
6 Lang: english
7 */
9 #define AROS_BOOT_CHECKSIG
10 #define DOSBOOT_DISCINSERT_SCREENPRINT
12 # define DEBUG 0
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>
35 #include <string.h>
36 #include <stdio.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)
51 struct MsgPort *mp;
52 struct IOFileSys *iofs;
53 BOOL ok = FALSE;
55 D(bug("[DOSBoot] __dosboot_RunHandler()\n" ));
56 mp = CreateMsgPort();
58 if (mp != NULL)
60 iofs = (struct IOFileSys *)CreateIORequest(mp, sizeof(struct IOFileSys));
62 if (iofs != NULL)
64 STRPTR handler;
65 struct FileSysStartupMsg *fssm;
66 ULONG fssmFlags = 0;
68 if (deviceNode->dn_Handler == NULL)
70 handler = "afs.handler";
72 else
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);
82 if (fssm != NULL)
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;
100 ok = TRUE;
103 DeleteIORequest(&iofs->IOFS);
106 DeleteMsgPort(mp);
108 return ok;
111 static BOOL __dosboot_Mount(struct DeviceNode *dn, struct DosLibrary * DOSBase)
113 BOOL rc;
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);
120 else
122 D(bug("[DOSBoot] __dosboot_Mount: Volume already mounted\n"));
123 rc = TRUE;
126 if (rc)
128 if (!AddDosEntry((struct DosList *) dn))
130 Alert(AT_DeadEnd | AG_NoMemory | AN_DOSLib);
133 return rc;
136 static BOOL __dosboot_IsBootable(CONST_STRPTR deviceName, struct DosLibrary * DOSBase)
138 BOOL result = FALSE;
139 BPTR lock;
140 STRPTR buffer;
141 LONG bufferLength;
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));
159 goto cleanup;
162 D(bug("[DOSBoot] __dosboot_IsBootable: Opened '%s'\n", buffer));
164 if (Read(lock, buffer, bufferLength) != -1)
166 IPTR sigptr = NULL;
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));
171 result = TRUE;
175 Close(lock);
176 lock = NULL;
178 #else
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));
196 goto cleanup;
199 if (!Info(lock, &info))
201 D(bug("[DOSBoot] __dosboot_IsBootable: could not get info on '%s'\n", buffer));
202 goto cleanup;
205 if (info.id_DiskType != ID_NO_DISK_PRESENT)
207 result = TRUE;
209 #endif
211 cleanup:
212 if (buffer != NULL ) FreeMem(buffer, bufferLength);
213 if (lock != 0 ) UnLock(lock);
215 return result;
218 /** Boot Code **/
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)
226 AROS_USERFUNC_INIT
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;
234 STRPTR bootName;
235 LONG bootNameLength;
236 BPTR lock;
237 BOOL hidds_ok;
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;
270 else
272 D(bug("[DOSBoot] __dosboot_BootProcess: Failed to open timer.device.\n"));
273 DeleteMsgPort(mp);
274 DeleteIORequest((struct IORequest *)tr);
275 tr = NULL;
279 if (tr == NULL)
281 DeleteMsgPort(mp);
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
299 assigned.
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)"));
309 else
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
326 the list. */
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;
331 break;
335 if (!(LIBBASE->db_bootdevicefound))
337 if (!(LIBBASE->db_attemptingboot))
339 #warning "TODO: Show insert disc animation !"
340 LIBBASE->db_attemptingboot = TRUE;
342 else
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");
351 #endif
353 if (tr != NULL) {
354 tr->tr_time.tv_secs = 5;
355 tr->tr_time.tv_micro = 0;
356 DoIO((struct IORequest *)tr);
357 } else
358 Delay(500);
362 if (mp)
363 DeleteMsgPort(mp);
365 if (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);
394 else
396 Alert(AT_DeadEnd | AG_BadParm | AN_DOSLib);
399 FreeMem( bootName, bootNameLength );
401 if ((lock = Lock("SYS:", SHARED_LOCK)) != NULL)
403 CurrentDir(lock);
405 else
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))
455 REMOVE( bootNode );
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!
471 #undef deviceName
473 AROS_USERFUNC_EXIT
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 },
489 { TAG_END, }
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 );
500 return TRUE;
503 ADD2INITLIB(dosboot_Init, 0)