- Geometry fix: pass cylinders to AddVolume() instead of sectors.
[tangerine.git] / rom / dos / dosboot.c
blobd94b33e70dbfb0d9ae82698f55b32fca5d62f757
1 /*
2 Copyright 1995-2008, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Start up the ol' Dos boot process.
6 Lang: english
7 */
9 #define DOSBOOT_DISCINSERT_SCREENPRINT
11 # define DEBUG 0
12 # include <aros/debug.h>
14 #include <aros/macros.h>
15 #include <aros/asmcall.h>
17 #include <proto/bootmenu.h>
18 #include <proto/bootloader.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 <libraries/bootmenu.h>
34 #include <devices/trackdisk.h>
36 #include <string.h>
37 #include <stdio.h>
39 #include "dos_intern.h"
41 #define BNF_RETRY 0x8000 /* Private flag for the BootNode */
43 extern BOOL init_hidds(struct ExecBase *, struct DosLibrary *);
44 extern void boot(struct ExecBase *SysBase, BOOL hidds_ok);
46 BOOL attemptingboot = FALSE;
47 BOOL bootdevicefound = FALSE;
49 /** Support Functions **/
50 static BOOL __dosboot_Mount(struct DeviceNode *dn, struct DosLibrary * DOSBase)
52 BOOL rc;
54 if (!dn->dn_Ext.dn_AROS.dn_Device)
55 rc = RunHandler(dn, DOSBase);
56 else
57 rc = TRUE;
59 if (rc)
61 if (!AddDosEntry((struct DosList *) dn))
63 Alert(AT_DeadEnd | AG_NoMemory | AN_DOSLib);
66 return rc;
69 static BOOL __dosboot_IsBootable(CONST_STRPTR deviceName, struct DosLibrary * DOSBase)
71 BOOL result = FALSE;
72 BPTR lock;
73 STRPTR buffer;
74 LONG bufferLength;
75 struct InfoData info;
77 #define STARTUP_SEQUENCE_FILE ":C/Shell"
79 bufferLength = strlen(deviceName) + sizeof(STARTUP_SEQUENCE_FILE) + 1;
81 if ((buffer = AllocMem(bufferLength, MEMF_ANY)) == NULL)
83 Alert(AT_DeadEnd | AG_NoMemory | AN_DOSLib);
86 strcpy(buffer, deviceName);
87 strcat(buffer, STARTUP_SEQUENCE_FILE);
89 D(bug("[DOS] __dosboot_IsBootable: Trying to get a lock on '%s'\n", buffer));
91 if ((lock = Lock(buffer, SHARED_LOCK)) == 0)
93 D(bug("[DOS] __dosboot_IsBootable: could not lock '%s'\n", buffer));
94 goto cleanup;
97 if (!Info(lock, &info))
99 D(bug("[DOS] __dosboot_IsBootable: could not get info on '%s'\n", buffer));
100 goto cleanup;
103 if (info.id_DiskType != ID_NO_DISK_PRESENT)
105 result = TRUE;
108 cleanup:
109 if (buffer != NULL ) FreeMem(buffer, bufferLength);
110 if (lock != 0 ) UnLock(lock);
112 return result;
115 /** Boot Code **/
117 AROS_UFH3(void, __dosboot_IntBoot,
118 AROS_UFHA(APTR, argString, A0),
119 AROS_UFHA(ULONG, argSize, D0),
120 AROS_UFHA(struct ExecBase *,SysBase, A6)
123 AROS_USERFUNC_INIT
125 struct ExpansionBase *ExpansionBase = NULL;
126 struct DosLibrary *DOSBase = NULL;
127 struct BootMenuBase *BootMenuBase = NULL;
128 void *BootLoaderBase = NULL;
130 struct BootNode *bootNode = NULL;
131 STRPTR bootName;
132 LONG bootNameLength;
133 BPTR lock;
134 BOOL hidds_ok;
136 struct MsgPort *mp; // Message port used with timer.device
137 struct timerequest *tr = NULL; // timer's time request message
139 #define deviceName (((struct DosList *) bootNode->bn_DeviceNode)->dol_Ext.dol_AROS.dol_DevName)
141 /**** Open all required libraries **********************************************/
142 if ((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0)) == NULL)
144 D(bug("[DOS] __dosboot_IntBoot: Could not open dos.library, something's wrong!\n" ));
145 Alert(AT_DeadEnd| AG_OpenLib | AN_DOSLib | AO_DOSLib);
149 if ((ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library", 0)) == NULL)
151 D(bug("[DOS] __dosboot_IntBoot: Could not open expansion.library, something's wrong!\n"));
152 Alert(AT_DeadEnd | AG_OpenLib | AN_DOSLib | AO_ExpansionLib);
155 if ((BootMenuBase = (struct BootMenuBase *)OpenResource("bootmenu.resource")) == NULL)
157 D(bug("[DOS] __dosboot_IntBoot: Could not open bootmenu.resource, something's wrong!\n"));
160 if ((mp = CreateMsgPort()) != NULL)
162 if ((tr = (struct timerequest *)CreateIORequest(mp, sizeof(struct timerequest))) != NULL)
165 if ((OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)tr, 0)) == 0)
166 #define ioStd(x) ((struct IOStdReq *)x)
167 ioStd(tr)->io_Command = TR_ADDREQUEST;
168 else
170 D(bug("[DOS] __dosboot_IntBoot: Could not open timer.device, something's wrong!\n"));
171 DeleteMsgPort(mp);
172 DeleteIORequest((struct IORequest *)tr);
173 tr = NULL;
176 else
178 DeleteMsgPort(mp);
182 /* Check if bootmenu is requested ... and setup base options */
183 if (BootMenuBase != NULL)
184 bootmenu_CheckAndDisplay();
186 /**** Try to mount all filesystems in the MountList ****************************/
187 D(bug("[DOS] __dosboot_IntBoot: Checking MountList for useable nodes:\n" ));
189 ForeachNode(&ExpansionBase->MountList, bootNode)
191 D(bug("[DOS] __dosboot_IntBoot: BootNode: %p, bn_DeviceNode: %p, Name '%s', Priority %4d\n",
192 bootNode, bootNode->bn_DeviceNode,
193 deviceName ? deviceName : "(null)", bootNode->bn_Node.ln_Pri
196 Try to mount the filesystem. If it fails, mark the BootNode
197 so DOS doesn't try to boot from it later but will retry to
198 mount it after boot device is found and system directories
199 assigned.
202 if( !__dosboot_Mount( (struct DeviceNode *) bootNode->bn_DeviceNode ,
203 (struct DosLibrary *) DOSBase))
204 bootNode->bn_Flags |= BNF_RETRY;
205 else
206 bootNode->bn_Flags &= ~BNF_RETRY;
209 /**** Try to find a bootable filesystem ****************************************/
210 while (bootdevicefound == FALSE)
212 ForeachNode(&ExpansionBase->MountList, bootNode)
214 /* Check if the mounted filesystem is bootable. If it's not,
215 it's probably some kind of transient error (ie. no disk
216 in drive or wrong disk) so we only move it to the end of
217 the list. */
218 if ((!(bootNode->bn_Flags & BNF_RETRY)) && (bootNode->bn_Node.ln_Pri != -128) &&
219 __dosboot_IsBootable(deviceName, (struct DosLibrary *)DOSBase))
221 bootdevicefound = TRUE;
222 break;
226 if (!bootdevicefound)
228 if (!attemptingboot)
230 #warning "TODO: Show insert disc animation !"
231 attemptingboot = TRUE;
233 else
235 #warning "TODO: re-run insert disc animation !"
237 #if defined(DOSBOOT_DISCINSERT_SCREENPRINT)
238 kprintf("No bootable disk was found.\n");
239 kprintf("Please insert a bootable disk in any drive.\n");
241 kprintf("Retrying in 5 seconds...\n");
242 #endif
244 if (tr != NULL) {
245 tr->tr_time.tv_secs = 5;
246 tr->tr_time.tv_micro = 0;
247 DoIO((struct IORequest *)tr);
248 } else
249 Delay(500);
253 if (mp)
254 DeleteMsgPort(mp);
256 if (tr)
258 CloseDevice((struct IORequest *)tr);
259 DeleteIORequest((struct IORequest *)tr);
262 if (bootdevicefound)
264 /* Construct the complete device name of the boot device */
265 bootNameLength = strlen(deviceName) + 2;
267 if ((bootName = AllocMem(bootNameLength, MEMF_ANY|MEMF_CLEAR)) == NULL)
269 Alert(AT_DeadEnd | AG_NoMemory | AO_DOSLib | AN_StartMem);
272 strcpy(bootName, deviceName);
273 strcat(bootName, ":");
275 D(bug("[DOS] __dosboot_IntBoot: Booting from device '%s'\n", bootName));
277 /* Lock the boot device and add some default assigns */
278 lock = Lock(bootName, SHARED_LOCK);
279 if (lock) DOSBase->dl_SYSLock = DupLock(lock);
281 if ((lock != NULL) && (DOSBase->dl_SYSLock != NULL))
283 AssignLock("SYS", lock);
285 else
287 Alert(AT_DeadEnd | AG_BadParm | AN_DOSLib);
290 FreeMem( bootName, bootNameLength );
292 if ((lock = Lock("SYS:", SHARED_LOCK)) != NULL)
294 CurrentDir(lock);
296 else
298 Alert(AT_DeadEnd | AG_BadParm | AN_DOSLib);
301 if ((lock = Lock("SYS:C", SHARED_LOCK)) != NULL)
303 AssignLock("C", lock);
306 if ((lock = Lock("SYS:S", SHARED_LOCK)) != NULL)
308 AssignLock("S", lock);
311 if ((lock = Lock("SYS:Libs", SHARED_LOCK)) != NULL)
313 AssignLock("LIBS", lock);
316 if ((lock = Lock("SYS:Devs", SHARED_LOCK)) != NULL)
318 AssignLock("DEVS", lock);
321 if ((lock = Lock("DEVS:Drivers", SHARED_LOCK)) != NULL)
323 AssignLock("DRIVERS", lock);
324 AssignAdd("LIBS", lock); /* Let hidds in DRIVERS: directory be found by OpenLibrary */
327 if ((lock = Lock("SYS:L", SHARED_LOCK)) != NULL)
329 AssignLock("L", lock);
332 /* Late binding ENVARC: assign, only if used */
333 AssignLate("ENVARC", "SYS:Prefs/env-archive");
336 Attempt to mount filesystems marked for retry. If it fails again,
337 remove the BootNode from the list.
339 ForeachNode(&ExpansionBase->MountList, bootNode)
341 if (bootNode->bn_Flags & BNF_RETRY)
343 D(bug("[DOS] __dosboot_IntBoot: Retrying node: %p, DevNode: %p, Name = %s\n", bootNode, bootNode->bn_DeviceNode, deviceName ? deviceName : "(null)" ));
344 if( !__dosboot_Mount((struct DeviceNode *)bootNode->bn_DeviceNode, (struct DosLibrary *)DOSBase))
346 REMOVE( bootNode );
351 /* We don't need expansion.library any more */
352 CloseLibrary( (struct Library *) ExpansionBase );
354 /* Initialize HIDDs */
355 hidds_ok = init_hidds(SysBase, (struct DosLibrary *)DOSBase);
357 /* We now call the system dependant boot - should NEVER return! */
358 boot(SysBase, hidds_ok);
361 //We Should NEVER reach here!
362 #undef deviceName
364 AROS_USERFUNC_EXIT
367 void DOSBoot(struct ExecBase *SysBase, struct DosLibrary *DOSBase)
369 struct TagItem bootprocess[] =
371 { NP_Entry, (IPTR) __dosboot_IntBoot },
372 { NP_Name, (IPTR) "Boot Process" },
373 { NP_Input, (IPTR) NULL },
374 { NP_Output, (IPTR) NULL },
375 { NP_WindowPtr, -1 },
376 { NP_CurrentDir, (IPTR) NULL },
377 { NP_StackSize, AROS_STACKSIZE * 2 },
378 { NP_Cli, (IPTR) 0 },
379 { TAG_END, }
382 if (CreateNewProc(bootprocess) == NULL)
384 D(bug("[DOS] DOSBoot: CreateNewProc() failed with %ld\n", ((struct Process *)FindTask(NULL))->pr_Result2));
385 Alert( AT_DeadEnd | AN_DOSLib | AG_ProcCreate );