2 Copyright © 1995-2016, 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>
34 #include <proto/dos.h>
36 #include LC_LIBDEFS_FILE
38 #include "dosboot_intern.h"
39 #include "../expansion/expansion_intern.h"
43 /* These two functions are implemented in arch/m68k/all/dosboot/bootcode.c */
45 extern VOID_FUNC
CallBootBlockCode(APTR bootcode
, struct IOStdReq
*io
, struct ExpansionBase
*ExpansionBase
);
46 extern void dosboot_BootPoint(struct BootNode
*bn
);
50 #define CallBootBlockCode(bootcode, io, ExpansionBase) NULL
51 #define dosboot_BootPoint(bn)
55 static BOOL
GetBootNodeDeviceUnit(struct BootNode
*bn
, BPTR
*device
, IPTR
*unit
, ULONG
*bootblocks
)
57 struct DeviceNode
*dn
;
58 struct FileSysStartupMsg
*fssm
;
64 dn
= bn
->bn_DeviceNode
;
68 fssm
= BADDR(dn
->dn_Startup
);
72 *unit
= fssm
->fssm_Unit
;
73 *device
= fssm
->fssm_Device
;
75 de
= BADDR(fssm
->fssm_Environ
);
76 /* Following check from Guru Book */
77 if (de
== NULL
|| (de
->de_TableSize
& 0xffffff00) != 0 || de
->de_TableSize
< DE_BOOTBLOCKS
)
79 *bootblocks
= de
->de_BootBlocks
* de
->de_SizeBlock
* sizeof(ULONG
);
85 static BOOL
BootBlockCheckSum(UBYTE
*bootblock
, ULONG bootblock_size
)
87 ULONG crc
= 0, crc2
= 0;
90 for (i
= 0; i
< bootblock_size
; i
+= 4) {
91 ULONG v
= AROS_LONG2BE(*(ULONG
*)(bootblock
+ i
));
101 D(bug("[Strap] bootblock %08x checksum %s (%08x %08x)\n",
102 AROS_LONG2BE(*(ULONG
*)bootblock
), crc
== crc2
? "ok" : "error", crc
, crc2
));
106 static BOOL
BootBlockCheck(UBYTE
*bootblock
, ULONG bootblock_size
)
108 struct FileSysResource
*fsr
;
109 struct FileSysEntry
*fse
;
112 if (!BootBlockCheckSum(bootblock
, bootblock_size
))
114 if (!(fsr
= OpenResource("FileSystem.resource")))
116 dostype
= AROS_LONG2BE(*(ULONG
*)bootblock
);
117 ForeachNode(&fsr
->fsr_FileSysEntries
, fse
) {
118 if (fse
->fse_DosType
== dostype
)
121 D(bug("[Strap] unknown bootblock dostype %08x\n", dostype
));
125 static inline void SetBootNodeDosType(struct BootNode
*bn
, ULONG dostype
)
127 struct DeviceNode
*dn
;
128 struct FileSysStartupMsg
*fssm
;
131 dn
= bn
->bn_DeviceNode
;
135 fssm
= BADDR(dn
->dn_Startup
);
139 de
= BADDR(fssm
->fssm_Environ
);
140 if (de
== NULL
|| de
->de_TableSize
< DE_DOSTYPE
)
143 de
->de_DosType
= dostype
;
146 /* Returns TRUE if it was a BootBlock style, but couldn't
147 * be booted, FALSE if not a BootBlock style, and doesn't
148 * return at all on a successful boot.
150 static BOOL
dosboot_BootBlock(struct BootNode
*bn
, struct ExpansionBase
*ExpansionBase
)
152 ULONG bootblock_size
;
153 struct MsgPort
*msgport
;
157 VOID_FUNC init
= NULL
;
160 if (!GetBootNodeDeviceUnit(bn
, &device
, &unit
, &bootblock_size
))
163 D(bug("%s: Probing for boot block on %b.%d\n", __func__
, device
, unit
));
164 /* memf_chip not required but more compatible with old bootblocks */
165 buffer
= AllocMem(bootblock_size
, MEMF_CHIP
);
168 D(bug("[Strap] bootblock address %p\n", buffer
));
169 if ((msgport
= CreateMsgPort()))
171 if ((io
= CreateIORequest(msgport
, sizeof(struct IOStdReq
))))
173 if (!OpenDevice(AROS_BSTR_ADDR(device
), unit
, (struct IORequest
*)io
, 0))
175 /* Read the device's boot block */
176 io
->io_Length
= bootblock_size
;
177 io
->io_Data
= buffer
;
179 io
->io_Command
= CMD_READ
;
180 D(bug("[Strap] %b.%d bootblock read (%d bytes)\n", device
, unit
, bootblock_size
));
181 DoIO((struct IORequest
*)io
);
183 if (io
->io_Error
== 0)
185 D(bug("[Strap] %b.%d bootblock read to %p ok\n", device
, unit
, buffer
));
186 if (BootBlockCheck(buffer
, bootblock_size
))
188 SetBootNodeDosType(bn
, AROS_LONG2BE(*(LONG
*)buffer
));
189 CacheClearE(buffer
, bootblock_size
, CACRF_ClearI
|CACRF_ClearD
);
190 init
= CallBootBlockCode(buffer
+ 12, io
, ExpansionBase
);
194 D(bug("[Strap] Not a valid bootblock\n"));
197 D(bug("[Strap] io_Error %d\n", io
->io_Error
));
199 io
->io_Command
= TD_MOTOR
;
201 DoIO((struct IORequest
*)io
);
202 CloseDevice((struct IORequest
*)io
);
204 DeleteIORequest((struct IORequest
*)io
);
206 DeleteMsgPort(msgport
);
208 FreeMem(buffer
, bootblock_size
);
213 D(bug("calling bootblock loaded code at %p\n", init
));
216 * This is actually rt_Init calling convention for non-autoinit residents.
217 * Workbench floppy bootblocks return a pointer to dos.library init routine,
218 * and it needs SysBase in A6.
219 * We don't close boot screen and libraries here. We will close them after
220 * dos.library is successfully initialized, using a second RTF_AFTERDOS ROMTag.
221 * This is needed because dos.library contains the second part of "bootable"
222 * test, trying to mount a filesystem and read the volume.
223 * We hope it won't do any harm for NDOS game disks.
225 AROS_UFC3NR(void, init
,
226 AROS_UFCA(APTR
, NULL
, D0
),
227 AROS_UFCA(BPTR
, BNULL
, A0
),
228 AROS_UFCA(struct ExecBase
*, SysBase
, A6
));
232 /* Device *was* BootBlock style, but couldn't boot. */
235 /* Device *was* BootBlock style, but couldn't boot.
236 * Non-m68k will try as DOS Boot anyway!
242 /* Attempt to boot via dos.library directly
244 static inline void dosboot_BootDos(void)
246 struct Resident
*DOSResident
;
248 /* Initialize dos.library manually. This is what Workbench floppy bootblocks do. */
249 DOSResident
= FindResident( "dos.library" );
251 if( DOSResident
== NULL
)
253 Alert( AT_DeadEnd
| AG_OpenLib
| AN_BootStrap
| AO_DOSLib
);
256 /* InitResident() of dos.library will not return on success. */
257 InitResident( DOSResident
, BNULL
);
261 /* Attempt to boot, first from the BootNode boot blocks,
262 * then via the DOS handlers
264 LONG
dosboot_BootStrap(LIBBASETYPEPTR LIBBASE
)
266 struct ExpansionBase
*ExpansionBase
= LIBBASE
->bm_ExpansionBase
;
271 * Try to boot from any device in the boot list,
272 * highest priority first.
274 ListLength(&ExpansionBase
->MountList
, nodes
);
275 for (i
= 0; i
< nodes
; i
++)
277 bn
= (struct BootNode
*)GetHead(&ExpansionBase
->MountList
);
279 if (bn
->bn_Node
.ln_Type
!= NT_BOOTNODE
||
280 bn
->bn_Node
.ln_Pri
<= -128 ||
281 bn
->bn_DeviceNode
== NULL
)
283 D(bug("%s: Ignoring %p, not a bootable node\n", __func__
, bn
));
284 ObtainSemaphore(&IntExpBase(ExpansionBase
)->BootSemaphore
);
286 ADDTAIL(&ExpansionBase
->MountList
, bn
);
287 ReleaseSemaphore(&IntExpBase(ExpansionBase
)->BootSemaphore
);
291 /* For each attempt, this node is at the head
292 * of the MountList, so that DOS will try to
293 * use it as SYS: if the strap works
296 /* First try as a BootBlock.
297 * dosboot_BootBlock returns TRUE if it *was*
298 * a BootBlock device, but couldn't be booted.
299 * Returns FALSE if not a bootblock device,
300 * and doesn't return at all if the bootblock
303 D(bug("%s: Attempting %b as BootBlock\n",__func__
, ((struct DeviceNode
*)bn
->bn_DeviceNode
)->dn_Name
));
304 if (!dosboot_BootBlock(bn
, ExpansionBase
)) {
305 /* Then as a BootPoint node */
306 D(bug("%s: Attempting %b as BootPoint\n", __func__
, ((struct DeviceNode
*)bn
->bn_DeviceNode
)->dn_Name
));
307 dosboot_BootPoint(bn
);
309 /* And finally with DOS */
310 D(bug("%s: Attempting %b with DOS\n", __func__
, ((struct DeviceNode
*)bn
->bn_DeviceNode
)->dn_Name
));
314 /* Didn't work. Next! */
315 D(bug("%s: DeviceNode %b (%d) was not bootable\n", __func__
,
316 ((struct DeviceNode
*)bn
->bn_DeviceNode
)->dn_Name
,
317 bn
->bn_Node
.ln_Pri
));
319 ObtainSemaphore(&IntExpBase(ExpansionBase
)->BootSemaphore
);
321 ADDTAIL(&ExpansionBase
->MountList
, bn
);
322 ReleaseSemaphore(&IntExpBase(ExpansionBase
)->BootSemaphore
);
325 D(bug("%s: No BootBlock, BootPoint, or BootDos nodes found\n",__func__
));
327 /* At this point we now know that we were unable to
328 * strap any bootable devices.
331 return ERROR_NO_DISK
;