2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
12 #include <aros/debug.h>
13 #include <exec/alerts.h>
14 #include <aros/asmcall.h>
15 #include <aros/bootloader.h>
16 #include <exec/lists.h>
17 #include <exec/memory.h>
18 #include <exec/resident.h>
19 #include <exec/types.h>
20 #include <libraries/configvars.h>
21 #include <libraries/expansion.h>
22 #include <libraries/expansionbase.h>
23 #include <libraries/partition.h>
24 #include <utility/tagitem.h>
25 #include <devices/bootblock.h>
26 #include <devices/timer.h>
27 #include <dos/dosextens.h>
28 #include <resources/filesysres.h>
29 #include <clib/alib_protos.h>
31 #include <proto/exec.h>
32 #include <proto/expansion.h>
33 #include <proto/partition.h>
34 #include <proto/bootloader.h>
36 #include LC_LIBDEFS_FILE
38 #include "dosboot_intern.h"
39 #include "../expansion/expansion_intern.h"
42 /* Delay just like Dos/Delay(), ticks are
43 * in 1/50th of a second.
45 static void bootDelay(ULONG timeout
)
47 struct timerequest timerio
;
48 struct MsgPort timermp
;
50 memset(&timermp
, 0, sizeof(timermp
));
52 timermp
.mp_Node
.ln_Type
= NT_MSGPORT
;
53 timermp
.mp_Flags
= PA_SIGNAL
;
54 timermp
.mp_SigBit
= SIGB_SINGLE
;
55 timermp
.mp_SigTask
= FindTask(NULL
);
56 NEWLIST(&timermp
.mp_MsgList
);
58 timerio
.tr_node
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
59 timerio
.tr_node
.io_Message
.mn_ReplyPort
= &timermp
;
60 timerio
.tr_node
.io_Message
.mn_Length
= sizeof(timermp
);
62 if (OpenDevice("timer.device", UNIT_VBLANK
, (struct IORequest
*)&timerio
, 0) != 0) {
63 D(bug("dosboot: Can't open timer.device unit 0\n"));
67 timerio
.tr_node
.io_Command
= TR_ADDREQUEST
;
68 timerio
.tr_time
.tv_secs
= timeout
/ TICKS_PER_SECOND
;
69 timerio
.tr_time
.tv_micro
= 1000000UL / TICKS_PER_SECOND
* (timeout
% TICKS_PER_SECOND
);
71 SetSignal(0, SIGF_SINGLE
);
73 DoIO(&timerio
.tr_node
);
75 CloseDevice((struct IORequest
*)&timerio
);
78 static BOOL
bstreqcstr(BSTR bstr
, CONST_STRPTR cstr
)
84 blen
= AROS_BSTR_strlen(bstr
);
88 return (memcmp(AROS_BSTR_ADDR(bstr
),cstr
,clen
) == 0);
91 static void selectBootDevice(LIBBASETYPEPTR DOSBootBase
, STRPTR bootDeviceName
)
93 struct BootNode
*bn
= NULL
;
95 if (bootDeviceName
== NULL
&&
96 DOSBootBase
->db_BootNode
!= NULL
)
99 Forbid(); /* .. access to ExpansionBase->MountList */
101 if (bootDeviceName
!= NULL
)
104 ForeachNode(&DOSBootBase
->bm_ExpansionBase
->MountList
, i
)
106 struct DeviceNode
*dn
;
108 dn
= i
->bn_DeviceNode
;
109 if (dn
== NULL
|| dn
->dn_Name
== BNULL
)
112 if (bstreqcstr(dn
->dn_Name
, bootDeviceName
))
122 bn
= (APTR
)GetHead(&DOSBootBase
->bm_ExpansionBase
->MountList
);
126 DOSBootBase
->db_BootNode
= bn
;
129 /* This makes the selected boot device the actual
130 * boot device. It also updates the boot flags.
132 static void setBootDevice(LIBBASETYPEPTR DOSBootBase
)
136 bn
= DOSBootBase
->db_BootNode
;
140 Remove((struct Node
*)bn
);
141 bn
->bn_Node
.ln_Type
= NT_BOOTNODE
;
142 bn
->bn_Node
.ln_Pri
= 127;
143 /* We use AddHead() instead of Enqueue() here
144 * to *insure* that this gets to the front of
147 AddHead(&DOSBootBase
->bm_ExpansionBase
->MountList
, (struct Node
*)bn
);
150 IntExpBase(DOSBootBase
->bm_ExpansionBase
)->BootFlags
=
151 DOSBootBase
->db_BootFlags
;
154 int dosboot_Init(LIBBASETYPEPTR LIBBASE
)
156 struct ExpansionBase
*ExpansionBase
;
157 void *BootLoaderBase
;
158 BOOL WantBootMenu
= FALSE
;
160 STRPTR bootDeviceName
= NULL
;
162 LIBBASE
->delayTicks
= 50;
164 D(bug("dosboot_Init: GO GO GO!\n"));
166 ExpansionBase
= (APTR
)OpenLibrary("expansion.library", 0);
168 D(bug("[Strap] ExpansionBase 0x%p\n", ExpansionBase
));
169 if( ExpansionBase
== NULL
)
171 D(bug( "Could not open expansion.library, something's wrong!\n"));
172 Alert(AT_DeadEnd
| AG_OpenLib
| AN_BootStrap
| AO_ExpansionLib
);
175 ExpansionBase
->Flags
|= EBF_SILENTSTART
;
177 LIBBASE
->bm_ExpansionBase
= ExpansionBase
;
180 * Search the kernel parameters for the bootdelay=%d string. It determines the
183 if ((BootLoaderBase
= OpenResource("bootloader.resource")) != NULL
)
185 struct List
*args
= GetBootInfo(BL_Args
);
191 ForeachNode(args
, node
)
193 if (0 == strncmp(node
->ln_Name
, "bootdelay=", 10))
195 ULONG delay
= atoi(&node
->ln_Name
[10]);
197 D(bug("[Boot] delay of %d seconds requested.", delay
));
199 bootDelay(delay
* 50);
201 else if (0 == stricmp(node
->ln_Name
, "bootmenu"))
203 D(bug("[BootMenu] bootmenu_Init: Forced with bootloader argument\n"));
207 * TODO: The following two flags should have corresponding switches
208 * in 'display options' page.
210 else if (0 == stricmp(node
->ln_Name
, "nomonitors"))
212 LIBBASE
->db_BootFlags
|= BF_NO_DISPLAY_DRIVERS
;
214 else if (0 == stricmp(node
->ln_Name
, "nocomposition"))
216 LIBBASE
->db_BootFlags
|= BF_NO_COMPOSITION
;
218 else if (0 == strnicmp(node
->ln_Name
, "bootdevice=", 11))
220 bootDeviceName
= &node
->ln_Name
[11];
222 else if (0 == stricmp(node
->ln_Name
, "econsole"))
224 LIBBASE
->db_BootFlags
|= BF_EMERGENCY_CONSOLE
;
225 D(bug("[Boot] Emergency console selected\n"));
228 IntExpBase(ExpansionBase
)->BootFlags
= LIBBASE
->db_BootFlags
;
232 /* Scan for any additional partition volumes */
233 dosboot_BootScan(LIBBASE
);
235 /* Select the initial boot device, so that the choice is available in the menu */
236 selectBootDevice(LIBBASE
, bootDeviceName
);
238 /* Show the boot menu if needed */
239 bootmenu_Init(LIBBASE
, WantBootMenu
);
241 /* Set final boot device */
242 setBootDevice(LIBBASE
);
244 /* We want to be able to find ourselves in RTF_AFTERDOS */
245 LIBBASE
->bm_Screen
= NULL
;
246 AddResource(&LIBBASE
->db_Node
);
248 /* Attempt to boot until we succeed */
251 dosboot_BootStrap(LIBBASE
);
253 if (!LIBBASE
->bm_Screen
)
254 LIBBASE
->bm_Screen
= NoBootMediaScreen(LIBBASE
);
256 D(bug("No bootable disk was found.\n"));
257 D(bug("Please insert a bootable disk in any drive.\n"));
258 D(bug("Retrying in 3 seconds...\n"));
260 for (t
= 0; t
< 150; t
+= LIBBASE
->delayTicks
)
262 bootDelay(LIBBASE
->delayTicks
);
264 if (LIBBASE
->bm_Screen
)
265 anim_Animate(LIBBASE
->bm_Screen
, LIBBASE
);
269 /* We never get here */
273 ADD2INITLIB(dosboot_Init
, 1)