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 static void dosboot_BootBlock(struct BootNode
*bn
, struct ExpansionBase
*ExpansionBase
)
147 ULONG bootblock_size
;
148 struct MsgPort
*msgport
;
152 VOID_FUNC init
= NULL
;
155 if (!GetBootNodeDeviceUnit(bn
, &device
, &unit
, &bootblock_size
))
158 D(bug("%s: Probing for boot block on %b.%d\n", __func__
, device
, unit
));
159 /* memf_chip not required but more compatible with old bootblocks */
160 buffer
= AllocMem(bootblock_size
, MEMF_CHIP
);
163 D(bug("[Strap] bootblock address %p\n", buffer
));
164 if ((msgport
= CreateMsgPort()))
166 if ((io
= CreateIORequest(msgport
, sizeof(struct IOStdReq
))))
168 if (!OpenDevice(AROS_BSTR_ADDR(device
), unit
, (struct IORequest
*)io
, 0))
170 /* Read the device's boot block */
171 io
->io_Length
= bootblock_size
;
172 io
->io_Data
= buffer
;
174 io
->io_Command
= CMD_READ
;
175 D(bug("[Strap] %b.%d bootblock read (%d bytes)\n", device
, unit
, bootblock_size
));
176 DoIO((struct IORequest
*)io
);
178 if (io
->io_Error
== 0)
180 D(bug("[Strap] %b.%d bootblock read to %p ok\n", device
, unit
, buffer
));
181 if (BootBlockCheck(buffer
, bootblock_size
))
183 SetBootNodeDosType(bn
, AROS_LONG2BE(*(LONG
*)buffer
));
184 CacheClearE(buffer
, bootblock_size
, CACRF_ClearI
|CACRF_ClearD
);
185 init
= CallBootBlockCode(buffer
+ 12, io
, ExpansionBase
);
189 D(bug("[Strap] Not a valid bootblock\n"));
192 D(bug("[Strap] io_Error %d\n", io
->io_Error
));
194 io
->io_Command
= TD_MOTOR
;
196 DoIO((struct IORequest
*)io
);
197 CloseDevice((struct IORequest
*)io
);
199 DeleteIORequest((struct IORequest
*)io
);
201 DeleteMsgPort(msgport
);
203 FreeMem(buffer
, bootblock_size
);
208 D(bug("calling bootblock loaded code at %p\n", init
));
211 * This is actually rt_Init calling convention for non-autoinit residents.
212 * Workbench floppy bootblocks return a pointer to dos.library init routine,
213 * and it needs SysBase in A6.
214 * We don't close boot screen and libraries here. We will close them after
215 * dos.library is succesfully initialized, using a second RTF_AFTERDOS ROMTag.
216 * This is needed because dos.library contains the second part of "bootable"
217 * test, trying to mount a filesystem and read the volume.
218 * We hope it won't do any harm for NDOS game disks.
220 AROS_UFC3(void, init
,
221 AROS_UFCA(APTR
, NULL
, D0
),
222 AROS_UFCA(BPTR
, BNULL
, A0
),
223 AROS_UFCA(struct ExecBase
*, SysBase
, A6
));
227 /* Attempt to boot via dos.library directly
229 static inline void dosboot_BootDos(void)
231 struct Resident
*DOSResident
;
233 /* Initialize dos.library manually. This is what Workbench floppy bootblock do. */
234 DOSResident
= FindResident( "dos.library" );
236 if( DOSResident
== NULL
)
238 Alert( AT_DeadEnd
| AG_OpenLib
| AN_BootStrap
| AO_DOSLib
);
241 /* InitResident() of dos.library will not return on success. */
242 InitResident( DOSResident
, BNULL
);
246 /* Attempt to boot, first from the BootNode boot blocks,
247 * then via the DOS handlers
249 LONG
dosboot_BootStrap(LIBBASETYPEPTR LIBBASE
)
255 * Try to boot from any device in the boot list,
256 * highest priority first.
258 ListLength(&LIBBASE
->bm_ExpansionBase
->MountList
, nodes
);
259 for (i
= 0; i
< nodes
; i
++)
261 bn
= (struct BootNode
*)GetHead(&LIBBASE
->bm_ExpansionBase
->MountList
);
263 if (bn
->bn_Node
.ln_Type
!= NT_BOOTNODE
||
264 bn
->bn_Node
.ln_Pri
<= -128 ||
265 bn
->bn_DeviceNode
== NULL
)
267 D(bug("%s: Ignoring %p, not a bootable node\n", __func__
, bn
));
269 ADDTAIL(&LIBBASE
->bm_ExpansionBase
->MountList
, bn
);
273 /* For each attempt, this node is at the head
274 * of the MountList, so that DOS will try to
275 * use it as SYS: if the strap works
278 /* First try as a BootPoint node */
279 dosboot_BootPoint(bn
);
281 /* Then as a BootBlock */
282 dosboot_BootBlock(bn
, LIBBASE
->bm_ExpansionBase
);
285 /* Don't try to boot via searching for :AROS.boot
286 * (dosboot_BootDos()), since that is not
287 * required for m68k 'bootability'. Trying to
288 * do so would lead to false positives, such
289 * as attempting to boot off of an empty, formatted
293 /* And finally with DOS */
297 /* Didn't work. Next! */
298 D(bug("%s: DeviceNode %b (%d) was not bootable\n", __func__
,
299 ((struct DeviceNode
*)bn
->bn_DeviceNode
)->dn_Name
,
300 bn
->bn_Node
.ln_Pri
));
303 ADDTAIL(&LIBBASE
->bm_ExpansionBase
->MountList
, bn
);
306 D(bug("%s: No BootBlock, BootPoint, or BootDos nodes found\n",__func__
));
308 /* At this point we now know that we were unable to
309 * strap any bootable devices.
312 return ERROR_NO_DISK
;