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>
30 #include <proto/exec.h>
31 #include <proto/expansion.h>
32 #include <proto/partition.h>
33 #include <proto/bootloader.h>
35 #include LC_LIBDEFS_FILE
37 #include "dosboot_intern.h"
38 #include "../expansion/expansion_intern.h"
41 /* Delay just like Dos/Delay(), ticks are
42 * in 1/50th of a second.
44 static void bootDelay(ULONG timeout
)
46 struct timerequest timerio
;
47 struct MsgPort timermp
;
49 memset(&timermp
, 0, sizeof(timermp
));
51 timermp
.mp_Node
.ln_Type
= NT_MSGPORT
;
52 timermp
.mp_Flags
= PA_SIGNAL
;
53 timermp
.mp_SigBit
= SIGB_SINGLE
;
54 timermp
.mp_SigTask
= FindTask(NULL
);
55 NEWLIST(&timermp
.mp_MsgList
);
57 timerio
.tr_node
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
58 timerio
.tr_node
.io_Message
.mn_ReplyPort
= &timermp
;
59 timerio
.tr_node
.io_Message
.mn_Length
= sizeof(timermp
);
61 if (OpenDevice("timer.device", UNIT_VBLANK
, (struct IORequest
*)&timerio
, 0) != 0) {
62 D(bug("dosboot: Can't open timer.device unit 0\n"));
66 timerio
.tr_node
.io_Command
= TR_ADDREQUEST
;
67 timerio
.tr_time
.tv_secs
= timeout
/ TICKS_PER_SECOND
;
68 timerio
.tr_time
.tv_micro
= 1000000UL / TICKS_PER_SECOND
* (timeout
% TICKS_PER_SECOND
);
70 SetSignal(0, SIGF_SINGLE
);
72 DoIO(&timerio
.tr_node
);
74 CloseDevice((struct IORequest
*)&timerio
);
77 static BOOL
bstreqcstr(BSTR bstr
, CONST_STRPTR cstr
)
83 blen
= AROS_BSTR_strlen(bstr
);
87 return (memcmp(AROS_BSTR_ADDR(bstr
),cstr
,clen
) == 0);
90 static void selectBootDevice(LIBBASETYPEPTR DOSBootBase
, STRPTR bootDeviceName
)
92 struct BootNode
*bn
= NULL
;
94 if (bootDeviceName
== NULL
&&
95 DOSBootBase
->db_BootNode
!= NULL
)
98 Forbid(); /* .. access to ExpansionBase->MountList */
100 if (bootDeviceName
!= NULL
)
103 ForeachNode(&DOSBootBase
->bm_ExpansionBase
->MountList
, i
)
105 struct DeviceNode
*dn
;
107 dn
= i
->bn_DeviceNode
;
108 if (dn
== NULL
|| dn
->dn_Name
== BNULL
)
111 if (bstreqcstr(dn
->dn_Name
, bootDeviceName
))
121 bn
= (APTR
)GetHead(&DOSBootBase
->bm_ExpansionBase
->MountList
);
125 DOSBootBase
->db_BootNode
= bn
;
128 /* This makes the selected boot device the actual
129 * boot device. It also updates the boot flags.
131 static void setBootDevice(LIBBASETYPEPTR DOSBootBase
)
135 bn
= DOSBootBase
->db_BootNode
;
139 Remove((struct Node
*)bn
);
140 bn
->bn_Node
.ln_Type
= NT_BOOTNODE
;
141 bn
->bn_Node
.ln_Pri
= 127;
142 /* We use AddHead() instead of Enqueue() here
143 * to *insure* that this gets to the front of
146 AddHead(&DOSBootBase
->bm_ExpansionBase
->MountList
, (struct Node
*)bn
);
149 IntExpBase(DOSBootBase
->bm_ExpansionBase
)->BootFlags
=
150 DOSBootBase
->db_BootFlags
;
153 int dosboot_Init(LIBBASETYPEPTR LIBBASE
)
155 struct ExpansionBase
*ExpansionBase
;
156 void *BootLoaderBase
;
157 BOOL WantBootMenu
= FALSE
;
159 STRPTR bootDeviceName
= NULL
;
161 LIBBASE
->delayTicks
= 50;
163 D(bug("dosboot_Init: GO GO GO!\n"));
165 ExpansionBase
= (APTR
)OpenLibrary("expansion.library", 0);
167 D(bug("[Strap] ExpansionBase 0x%p\n", ExpansionBase
));
168 if( ExpansionBase
== NULL
)
170 D(bug( "Could not open expansion.library, something's wrong!\n"));
171 Alert(AT_DeadEnd
| AG_OpenLib
| AN_BootStrap
| AO_ExpansionLib
);
174 ExpansionBase
->Flags
|= EBF_SILENTSTART
;
176 LIBBASE
->bm_ExpansionBase
= ExpansionBase
;
179 * Search the kernel parameters for the bootdelay=%d string. It determines the
182 if ((BootLoaderBase
= OpenResource("bootloader.resource")) != NULL
)
184 struct List
*args
= GetBootInfo(BL_Args
);
190 ForeachNode(args
, node
)
192 if (0 == strncmp(node
->ln_Name
, "bootdelay=", 10))
194 ULONG delay
= atoi(&node
->ln_Name
[10]);
196 D(bug("[Boot] delay of %d seconds requested.", delay
));
198 bootDelay(delay
* 50);
200 else if (0 == stricmp(node
->ln_Name
, "bootmenu"))
202 D(bug("[BootMenu] bootmenu_Init: Forced with bootloader argument\n"));
206 * TODO: The following two flags should have corresponding switches
207 * in 'display options' page.
209 else if (0 == stricmp(node
->ln_Name
, "nomonitors"))
211 LIBBASE
->db_BootFlags
|= BF_NO_DISPLAY_DRIVERS
;
213 else if (0 == stricmp(node
->ln_Name
, "nocomposition"))
215 LIBBASE
->db_BootFlags
|= BF_NO_COMPOSITION
;
217 else if (0 == strnicmp(node
->ln_Name
, "bootdevice=", 11))
219 bootDeviceName
= &node
->ln_Name
[11];
221 else if (0 == stricmp(node
->ln_Name
, "econsole"))
223 LIBBASE
->db_BootFlags
|= BF_EMERGENCY_CONSOLE
;
224 D(bug("[Boot] Emergency console selected\n"));
227 IntExpBase(ExpansionBase
)->BootFlags
= LIBBASE
->db_BootFlags
;
231 /* Scan for any additional partition volumes */
232 dosboot_BootScan(LIBBASE
);
234 /* Select the initial boot device, so that the choice is available in the menu */
235 selectBootDevice(LIBBASE
, bootDeviceName
);
237 /* Show the boot menu if needed */
238 bootmenu_Init(LIBBASE
, WantBootMenu
);
240 /* Set final boot device */
241 setBootDevice(LIBBASE
);
243 /* We want to be able to find ourselves in RTF_AFTERDOS */
244 LIBBASE
->bm_Screen
= NULL
;
245 AddResource(&LIBBASE
->db_Node
);
247 /* Attempt to boot until we succeed */
250 dosboot_BootStrap(LIBBASE
);
252 if (!LIBBASE
->bm_Screen
)
253 LIBBASE
->bm_Screen
= NoBootMediaScreen(LIBBASE
);
255 D(bug("No bootable disk was found.\n"));
256 D(bug("Please insert a bootable disk in any drive.\n"));
257 D(bug("Retrying in 3 seconds...\n"));
259 for (t
= 0; t
< 150; t
+= LIBBASE
->delayTicks
)
261 bootDelay(LIBBASE
->delayTicks
);
263 if (LIBBASE
->bm_Screen
)
264 anim_Animate(LIBBASE
->bm_Screen
, LIBBASE
);
268 /* We never get here */
272 ADD2INITLIB(dosboot_Init
, 1)