compiler/clib: SAS/C functions clean-up
[AROS.git] / rom / dosboot / bootstrap.c
blob19534bb14c66a5a679b9039ff080bcc9038a5de9
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Boot AROS
6 Lang: english
7 */
9 #include <string.h>
10 #include <stdlib.h>
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"
40 #ifdef __mc68000
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);
47 #else
49 #define CallBootBlockCode(bootcode, io, ExpansionBase) NULL
50 #define dosboot_BootPoint(bn)
52 #endif
54 static BOOL GetBootNodeDeviceUnit(struct BootNode *bn, BPTR *device, IPTR *unit, ULONG *bootblocks)
56 struct DeviceNode *dn;
57 struct FileSysStartupMsg *fssm;
58 struct DosEnvec *de;
60 if (bn == NULL)
61 return FALSE;
63 dn = bn->bn_DeviceNode;
64 if (dn == NULL)
65 return FALSE;
67 fssm = BADDR(dn->dn_Startup);
68 if (fssm == NULL)
69 return FALSE;
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)
77 return FALSE;
78 *bootblocks = de->de_BootBlocks * de->de_SizeBlock * sizeof(ULONG);
79 if (*bootblocks == 0)
80 return FALSE;
81 return TRUE;
84 static BOOL BootBlockCheckSum(UBYTE *bootblock, ULONG bootblock_size)
86 ULONG crc = 0, crc2 = 0;
87 UWORD i;
89 for (i = 0; i < bootblock_size; i += 4) {
90 ULONG v = AROS_LONG2BE(*(ULONG*)(bootblock + i));
91 if (i == 4) {
92 crc2 = v;
93 v = 0;
95 if (crc + v < crc)
96 crc++;
97 crc += v;
99 crc ^= 0xffffffff;
100 D(bug("[Strap] bootblock %08x checksum %s (%08x %08x)\n",
101 AROS_LONG2BE(*(ULONG*)bootblock), crc == crc2 ? "ok" : "error", crc, crc2));
102 return crc == crc2;
105 static BOOL BootBlockCheck(UBYTE *bootblock, ULONG bootblock_size)
107 struct FileSysResource *fsr;
108 struct FileSysEntry *fse;
109 ULONG dostype;
111 if (!BootBlockCheckSum(bootblock, bootblock_size))
112 return FALSE;
113 if (!(fsr = OpenResource("FileSystem.resource")))
114 return FALSE;
115 dostype = AROS_LONG2BE(*(ULONG*)bootblock);
116 ForeachNode(&fsr->fsr_FileSysEntries, fse) {
117 if (fse->fse_DosType == dostype)
118 return TRUE;
120 D(bug("[Strap] unknown bootblock dostype %08x\n", dostype));
121 return FALSE;
124 static inline void SetBootNodeDosType(struct BootNode *bn, ULONG dostype)
126 struct DeviceNode *dn;
127 struct FileSysStartupMsg *fssm;
128 struct DosEnvec *de;
130 dn = bn->bn_DeviceNode;
131 if (dn == NULL)
132 return;
134 fssm = BADDR(dn->dn_Startup);
135 if (fssm == NULL)
136 return;
138 de = BADDR(fssm->fssm_Environ);
139 if (de == NULL || de->de_TableSize < DE_DOSTYPE)
140 return;
142 de->de_DosType = dostype;
145 static void dosboot_BootBlock(struct BootNode *bn, struct ExpansionBase *ExpansionBase)
147 ULONG bootblock_size;
148 struct MsgPort *msgport;
149 struct IOStdReq *io;
150 BPTR device;
151 IPTR unit;
152 VOID_FUNC init = NULL;
153 UBYTE *buffer;
155 if (!GetBootNodeDeviceUnit(bn, &device, &unit, &bootblock_size))
156 return;
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);
161 if (buffer != NULL)
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;
173 io->io_Offset = 0;
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);
187 else
189 D(bug("[Strap] Not a valid bootblock\n"));
191 } else {
192 D(bug("[Strap] io_Error %d\n", io->io_Error));
194 io->io_Command = TD_MOTOR;
195 io->io_Length = 0;
196 DoIO((struct IORequest*)io);
197 CloseDevice((struct IORequest *)io);
199 DeleteIORequest((struct IORequest*)io);
201 DeleteMsgPort(msgport);
203 FreeMem(buffer, bootblock_size);
206 if (init != NULL)
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)
251 struct BootNode *bn;
252 int i, nodes;
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));
268 REMOVE(bn);
269 ADDTAIL(&LIBBASE->bm_ExpansionBase->MountList, bn);
270 continue;
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);
284 #ifdef __mc68000
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
290 * floppy disk.
292 #else
293 /* And finally with DOS */
294 dosboot_BootDos();
295 #endif
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));
302 REMOVE(bn);
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;