2 Copyright © 1995-2011, 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"
42 /* These two functions are implemented in arch/m68k/all/dosboot/bootcode.c */
44 extern VOID_FUNC
CallBootBlockCode(APTR bootcode
, struct IOStdReq
*io
, struct ExpansionBase
*ExpansionBase
);
45 extern void dosboot_BootPoint(struct BootNode
*bn
);
49 #define CallBootBlockCode(bootcode, io, ExpansionBase) NULL
50 #define dosboot_BootPoint(bn)
54 static BOOL
GetBootNodeDeviceUnit(struct BootNode
*bn
, BPTR
*device
, IPTR
*unit
, ULONG
*bootblocks
)
56 struct DeviceNode
*dn
;
57 struct FileSysStartupMsg
*fssm
;
63 dn
= bn
->bn_DeviceNode
;
67 fssm
= BADDR(dn
->dn_Startup
);
71 *unit
= fssm
->fssm_Unit
;
72 *device
= fssm
->fssm_Device
;
74 de
= BADDR(fssm
->fssm_Environ
);
75 /* Following check from Guru Book */
76 if (de
== NULL
|| (de
->de_TableSize
& 0xffffff00) != 0 || de
->de_TableSize
< DE_BOOTBLOCKS
)
78 *bootblocks
= de
->de_BootBlocks
* de
->de_SizeBlock
* sizeof(ULONG
);
84 static BOOL
BootBlockCheckSum(UBYTE
*bootblock
, ULONG bootblock_size
)
86 ULONG crc
= 0, crc2
= 0;
89 for (i
= 0; i
< bootblock_size
; i
+= 4) {
90 ULONG v
= AROS_LONG2BE(*(ULONG
*)(bootblock
+ i
));
100 D(bug("[Strap] bootblock %08x checksum %s (%08x %08x)\n",
101 AROS_LONG2BE(*(ULONG
*)bootblock
), crc
== crc2
? "ok" : "error", crc
, crc2
));
105 static BOOL
BootBlockCheck(UBYTE
*bootblock
, ULONG bootblock_size
)
107 struct FileSysResource
*fsr
;
108 struct FileSysEntry
*fse
;
111 if (!BootBlockCheckSum(bootblock
, bootblock_size
))
113 if (!(fsr
= OpenResource("FileSystem.resource")))
115 dostype
= AROS_LONG2BE(*(ULONG
*)bootblock
);
116 ForeachNode(&fsr
->fsr_FileSysEntries
, fse
) {
117 if (fse
->fse_DosType
== dostype
)
120 D(bug("[Strap] unknown bootblock dostype %08x\n", dostype
));
124 static inline void SetBootNodeDosType(struct BootNode
*bn
, ULONG dostype
)
126 struct DeviceNode
*dn
;
127 struct FileSysStartupMsg
*fssm
;
130 dn
= bn
->bn_DeviceNode
;
134 fssm
= BADDR(dn
->dn_Startup
);
138 de
= BADDR(fssm
->fssm_Environ
);
139 if (de
== NULL
|| de
->de_TableSize
< DE_DOSTYPE
)
142 de
->de_DosType
= dostype
;
145 /* Returns TRUE if it was a BootBlock style, but couldn't
146 * be booted, FALSE if not a BootBlock style, and doesn't
147 * return at all on a successful boot.
149 static BOOL
dosboot_BootBlock(struct BootNode
*bn
, struct ExpansionBase
*ExpansionBase
)
151 ULONG bootblock_size
;
152 struct MsgPort
*msgport
;
156 VOID_FUNC init
= NULL
;
159 if (!GetBootNodeDeviceUnit(bn
, &device
, &unit
, &bootblock_size
))
162 D(bug("%s: Probing for boot block on %b.%d\n", __func__
, device
, unit
));
163 /* memf_chip not required but more compatible with old bootblocks */
164 buffer
= AllocMem(bootblock_size
, MEMF_CHIP
);
167 D(bug("[Strap] bootblock address %p\n", buffer
));
168 if ((msgport
= CreateMsgPort()))
170 if ((io
= CreateIORequest(msgport
, sizeof(struct IOStdReq
))))
172 if (!OpenDevice(AROS_BSTR_ADDR(device
), unit
, (struct IORequest
*)io
, 0))
174 /* Read the device's boot block */
175 io
->io_Length
= bootblock_size
;
176 io
->io_Data
= buffer
;
178 io
->io_Command
= CMD_READ
;
179 D(bug("[Strap] %b.%d bootblock read (%d bytes)\n", device
, unit
, bootblock_size
));
180 DoIO((struct IORequest
*)io
);
182 if (io
->io_Error
== 0)
184 D(bug("[Strap] %b.%d bootblock read to %p ok\n", device
, unit
, buffer
));
185 if (BootBlockCheck(buffer
, bootblock_size
))
187 SetBootNodeDosType(bn
, AROS_LONG2BE(*(LONG
*)buffer
));
188 CacheClearE(buffer
, bootblock_size
, CACRF_ClearI
|CACRF_ClearD
);
189 init
= CallBootBlockCode(buffer
+ 12, io
, ExpansionBase
);
193 D(bug("[Strap] Not a valid bootblock\n"));
196 D(bug("[Strap] io_Error %d\n", io
->io_Error
));
198 io
->io_Command
= TD_MOTOR
;
200 DoIO((struct IORequest
*)io
);
201 CloseDevice((struct IORequest
*)io
);
203 DeleteIORequest((struct IORequest
*)io
);
205 DeleteMsgPort(msgport
);
207 FreeMem(buffer
, bootblock_size
);
212 D(bug("calling bootblock loaded code at %p\n", init
));
215 * This is actually rt_Init calling convention for non-autoinit residents.
216 * Workbench floppy bootblocks return a pointer to dos.library init routine,
217 * and it needs SysBase in A6.
218 * We don't close boot screen and libraries here. We will close them after
219 * dos.library is succesfully initialized, using a second RTF_AFTERDOS ROMTag.
220 * This is needed because dos.library contains the second part of "bootable"
221 * test, trying to mount a filesystem and read the volume.
222 * We hope it won't do any harm for NDOS game disks.
224 AROS_UFC3(void, init
,
225 AROS_UFCA(APTR
, NULL
, D0
),
226 AROS_UFCA(BPTR
, BNULL
, A0
),
227 AROS_UFCA(struct ExecBase
*, SysBase
, A6
));
231 /* Device *was* BootBlock style, but couldn't boot. */
234 /* Device *was* BootBlock style, but couldn't boot.
235 * Non-m68k will try as DOS Boot anyway!
241 /* Attempt to boot via dos.library directly
243 static inline void dosboot_BootDos(void)
245 struct Resident
*DOSResident
;
247 /* Initialize dos.library manually. This is what Workbench floppy bootblock do. */
248 DOSResident
= FindResident( "dos.library" );
250 if( DOSResident
== NULL
)
252 Alert( AT_DeadEnd
| AG_OpenLib
| AN_BootStrap
| AO_DOSLib
);
255 /* InitResident() of dos.library will not return on success. */
256 InitResident( DOSResident
, BNULL
);
260 /* Attempt to boot, first from the BootNode boot blocks,
261 * then via the DOS handlers
263 LONG
dosboot_BootStrap(LIBBASETYPEPTR LIBBASE
)
269 * Try to boot from any device in the boot list,
270 * highest priority first.
272 ListLength(&LIBBASE
->bm_ExpansionBase
->MountList
, nodes
);
273 for (i
= 0; i
< nodes
; i
++)
275 bn
= (struct BootNode
*)GetHead(&LIBBASE
->bm_ExpansionBase
->MountList
);
277 if (bn
->bn_Node
.ln_Type
!= NT_BOOTNODE
||
278 bn
->bn_Node
.ln_Pri
<= -128 ||
279 bn
->bn_DeviceNode
== NULL
)
281 D(bug("%s: Ignoring %p, not a bootable node\n", __func__
, bn
));
283 ADDTAIL(&LIBBASE
->bm_ExpansionBase
->MountList
, bn
);
287 /* For each attempt, this node is at the head
288 * of the MountList, so that DOS will try to
289 * use it as SYS: if the strap works
292 /* First try as a BootBlock.
293 * dosboot_BootBlock returns TRUE if it *was*
294 * a BootBlock device, but couldn't be booted.
295 * Returns FALSE if not a bootblock device,
296 * and doesn't return at all if the bootblock
299 D(bug("%s: Attempting %b as BootBlock\n",__func__
, ((struct DeviceNode
*)bn
->bn_DeviceNode
)->dn_Name
));
300 if (!dosboot_BootBlock(bn
, LIBBASE
->bm_ExpansionBase
)) {
301 /* Then as a BootPoint node */
302 D(bug("%s: Attempting %b as BootPoint\n", __func__
, ((struct DeviceNode
*)bn
->bn_DeviceNode
)->dn_Name
));
303 dosboot_BootPoint(bn
);
305 /* And finally with DOS */
306 D(bug("%s: Attempting %b with DOS\n", __func__
, ((struct DeviceNode
*)bn
->bn_DeviceNode
)->dn_Name
));
310 /* Didn't work. Next! */
311 D(bug("%s: DeviceNode %b (%d) was not bootable\n", __func__
,
312 ((struct DeviceNode
*)bn
->bn_DeviceNode
)->dn_Name
,
313 bn
->bn_Node
.ln_Pri
));
316 ADDTAIL(&LIBBASE
->bm_ExpansionBase
->MountList
, bn
);
319 D(bug("%s: No BootBlock, BootPoint, or BootDos nodes found\n",__func__
));
321 /* At this point we now know that we were unable to
322 * strap any bootable devices.
325 return ERROR_NO_DISK
;