loadbsd.c revision 1.7.8.2 1 1.7.8.2 nathanw /*
2 1.7.8.2 nathanw * Load and boot NetBSD kernel on Human68k
3 1.7.8.2 nathanw *
4 1.7.8.2 nathanw * written by Yasha (ITOH Yasufumi)
5 1.7.8.2 nathanw * public domain
6 1.7.8.2 nathanw *
7 1.7.8.2 nathanw * loadbsd [-hvV] [-abDs] [-r root_device] netbsd
8 1.7.8.2 nathanw *
9 1.7.8.2 nathanw * loadbsd options:
10 1.7.8.2 nathanw * -h help
11 1.7.8.2 nathanw * -V print version and exit
12 1.7.8.2 nathanw *
13 1.7.8.2 nathanw * kernel options:
14 1.7.8.2 nathanw * -a auto boot, opposite of -s
15 1.7.8.2 nathanw * -s single user boot (default)
16 1.7.8.2 nathanw * -D enter kernel debugger
17 1.7.8.2 nathanw * -b ask root device
18 1.7.8.2 nathanw * -r specify root device
19 1.7.8.2 nathanw * -q quiet boot
20 1.7.8.2 nathanw * -v verbose boot (also turn on verbosity of loadbsd)
21 1.7.8.2 nathanw *
22 1.7.8.2 nathanw * $NetBSD: loadbsd.c,v 1.7.8.2 2002/06/20 03:42:36 nathanw Exp $
23 1.7.8.2 nathanw */
24 1.7.8.2 nathanw
25 1.7.8.2 nathanw #include <sys/cdefs.h>
26 1.7.8.2 nathanw
27 1.7.8.2 nathanw __RCSID("$NetBSD: loadbsd.c,v 1.7.8.2 2002/06/20 03:42:36 nathanw Exp $");
28 1.7.8.2 nathanw #define VERSION "$Revision: 1.7.8.2 $ $Date: 2002/06/20 03:42:36 $"
29 1.7.8.2 nathanw
30 1.7.8.2 nathanw #include <sys/types.h> /* ntohl */
31 1.7.8.2 nathanw #include <sys/reboot.h>
32 1.7.8.2 nathanw #include <sys/param.h> /* ALIGN, ALIGNBYTES */
33 1.7.8.2 nathanw #include <a.out.h>
34 1.7.8.2 nathanw #include <sys/exec_elf.h>
35 1.7.8.2 nathanw #include <string.h>
36 1.7.8.2 nathanw #include <machine/bootinfo.h>
37 1.7.8.2 nathanw
38 1.7.8.2 nathanw #include <dos.h>
39 1.7.8.2 nathanw #include <iocs.h>
40 1.7.8.2 nathanw #include "../common/xprintf.h"
41 1.7.8.2 nathanw #include "trampoline.h"
42 1.7.8.2 nathanw
43 1.7.8.2 nathanw #define DEFAULT_ROOTDEVNAME "sd@0,0:a"
44 1.7.8.2 nathanw
45 1.7.8.2 nathanw #define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
46 1.7.8.2 nathanw
47 1.7.8.2 nathanw #define GETDECIMAL(var, str) \
48 1.7.8.2 nathanw do { var *= 10; var += *str++ - '0'; } while (ISDIGIT(*str))
49 1.7.8.2 nathanw
50 1.7.8.2 nathanw static const char *lookupif __P((const char *name,
51 1.7.8.2 nathanw unsigned *pif, unsigned *punit));
52 1.7.8.2 nathanw static void get_current_scsi_interface __P((unsigned *pif, unsigned *punit));
53 1.7.8.2 nathanw static int bootdev __P((const char *devstr));
54 1.7.8.2 nathanw static struct tramparg *read_kernel __P((const char *fn));
55 1.7.8.2 nathanw static int chkmpu __P((void));
56 1.7.8.2 nathanw static __dead void usage __P((int status, const char *msg))
57 1.7.8.2 nathanw __attribute__((noreturn));
58 1.7.8.2 nathanw
59 1.7.8.2 nathanw int main __P((int argc, char *argv[]));
60 1.7.8.2 nathanw
61 1.7.8.2 nathanw int opt_v;
62 1.7.8.2 nathanw int opt_N;
63 1.7.8.2 nathanw const char *kernel_fn;
64 1.7.8.2 nathanw
65 1.7.8.2 nathanw const struct hatbl {
66 1.7.8.2 nathanw char name[4];
67 1.7.8.2 nathanw unsigned short id;
68 1.7.8.2 nathanw } hatable[] = {
69 1.7.8.2 nathanw X68K_BOOT_SCSIIF_LIST
70 1.7.8.2 nathanw };
71 1.7.8.2 nathanw
72 1.7.8.2 nathanw /*
73 1.7.8.2 nathanw * parse interface name
74 1.7.8.2 nathanw * return the next position
75 1.7.8.2 nathanw */
76 1.7.8.2 nathanw static const char *
77 1.7.8.2 nathanw lookupif(name, pif, punit)
78 1.7.8.2 nathanw const char *name;
79 1.7.8.2 nathanw unsigned *pif, *punit;
80 1.7.8.2 nathanw {
81 1.7.8.2 nathanw unsigned u, unit;
82 1.7.8.2 nathanw const char *p;
83 1.7.8.2 nathanw
84 1.7.8.2 nathanw for (u = 0; u < sizeof hatable / sizeof hatable[0]; u++) {
85 1.7.8.2 nathanw const char *n;
86 1.7.8.2 nathanw
87 1.7.8.2 nathanw for (n = hatable[u].name, p = name; *n && *n == *p; n++, p++)
88 1.7.8.2 nathanw ;
89 1.7.8.2 nathanw if (!*n)
90 1.7.8.2 nathanw goto found;
91 1.7.8.2 nathanw }
92 1.7.8.2 nathanw /* not found */
93 1.7.8.2 nathanw return (char *) 0;
94 1.7.8.2 nathanw
95 1.7.8.2 nathanw found:
96 1.7.8.2 nathanw if (*p == '@')
97 1.7.8.2 nathanw p++;
98 1.7.8.2 nathanw
99 1.7.8.2 nathanw /* get unit # */
100 1.7.8.2 nathanw if (!ISDIGIT(*p))
101 1.7.8.2 nathanw return (char *) 0;
102 1.7.8.2 nathanw
103 1.7.8.2 nathanw unit = 0;
104 1.7.8.2 nathanw GETDECIMAL(unit, p);
105 1.7.8.2 nathanw
106 1.7.8.2 nathanw *pif = hatable[u].id;
107 1.7.8.2 nathanw *punit = unit;
108 1.7.8.2 nathanw
109 1.7.8.2 nathanw return p;
110 1.7.8.2 nathanw }
111 1.7.8.2 nathanw
112 1.7.8.2 nathanw /*
113 1.7.8.2 nathanw * if the SCSI interface is not specified, use the current one
114 1.7.8.2 nathanw */
115 1.7.8.2 nathanw static void
116 1.7.8.2 nathanw get_current_scsi_interface(pif, punit)
117 1.7.8.2 nathanw unsigned *pif, *punit;
118 1.7.8.2 nathanw {
119 1.7.8.2 nathanw unsigned binf;
120 1.7.8.2 nathanw char *bootrom;
121 1.7.8.2 nathanw int bus_err_buf;
122 1.7.8.2 nathanw
123 1.7.8.2 nathanw binf = (unsigned) IOCS_BOOTINF();
124 1.7.8.2 nathanw if (binf < 0x00fc0000)
125 1.7.8.2 nathanw return; /* not booted from SCSI */
126 1.7.8.2 nathanw
127 1.7.8.2 nathanw bootrom = (char *) (binf & 0x00ffffe0);
128 1.7.8.2 nathanw if (IOCS_B_LPEEK(bootrom + 0x24) == 0x53435349 && /* 'SCSI' */
129 1.7.8.2 nathanw IOCS_B_WPEEK(bootrom + 0x28) == 0x494E) { /* 'IN' */
130 1.7.8.2 nathanw /* spc0 */
131 1.7.8.2 nathanw *pif = X68K_BOOT_SCSIIF_SPC;
132 1.7.8.2 nathanw *punit = 0;
133 1.7.8.2 nathanw } else if (DOS_BUS_ERR(&bus_err_buf, (void *)EXSPC_BDID, 1)) {
134 1.7.8.2 nathanw /* mha0 */
135 1.7.8.2 nathanw *pif = X68K_BOOT_SCSIIF_MHA;
136 1.7.8.2 nathanw *punit = 0;
137 1.7.8.2 nathanw } else {
138 1.7.8.2 nathanw /* spc1 */
139 1.7.8.2 nathanw *pif = X68K_BOOT_SCSIIF_SPC;
140 1.7.8.2 nathanw *punit = 1;
141 1.7.8.2 nathanw }
142 1.7.8.2 nathanw }
143 1.7.8.2 nathanw
144 1.7.8.2 nathanw /*
145 1.7.8.2 nathanw * parse device name
146 1.7.8.2 nathanw *
147 1.7.8.2 nathanw * [/<controller>@<unit>/]<device>@<unit>[,<lun>][:<partition>]
148 1.7.8.2 nathanw *
149 1.7.8.2 nathanw * <unit> must be target SCSI ID if <device> is a SCSI device
150 1.7.8.2 nathanw *
151 1.7.8.2 nathanw * full form:
152 1.7.8.2 nathanw * /spc@0/sd@1,2:e
153 1.7.8.2 nathanw *
154 1.7.8.2 nathanw * partial form:
155 1.7.8.2 nathanw * /mha@0/sd@1 = /mha@0/sd@1,0:a
156 1.7.8.2 nathanw * sd@1:e = /current_device/sd@1,0e
157 1.7.8.2 nathanw * sd@1,2:e = /current_device/sd@1,2:e
158 1.7.8.2 nathanw */
159 1.7.8.2 nathanw
160 1.7.8.2 nathanw const struct devtbl {
161 1.7.8.2 nathanw char name[3];
162 1.7.8.2 nathanw u_char major;
163 1.7.8.2 nathanw } devtable[] = {
164 1.7.8.2 nathanw X68K_BOOT_DEV_LIST,
165 1.7.8.2 nathanw X68K_BOOT_NETIF_LIST
166 1.7.8.2 nathanw };
167 1.7.8.2 nathanw
168 1.7.8.2 nathanw static int
169 1.7.8.2 nathanw bootdev(devstr)
170 1.7.8.2 nathanw const char *devstr;
171 1.7.8.2 nathanw {
172 1.7.8.2 nathanw unsigned u;
173 1.7.8.2 nathanw unsigned major, unit, lun, partition;
174 1.7.8.2 nathanw int dev;
175 1.7.8.2 nathanw const char *s = devstr;
176 1.7.8.2 nathanw unsigned interface = 0, unit_if = 0;
177 1.7.8.2 nathanw
178 1.7.8.2 nathanw if (*s == '/') {
179 1.7.8.2 nathanw /*
180 1.7.8.2 nathanw * /<interface>/<device>"
181 1.7.8.2 nathanw * "/spc@1/sd@2,3:e"
182 1.7.8.2 nathanw */
183 1.7.8.2 nathanw while (*++s == '/') /* skip slashes */
184 1.7.8.2 nathanw ;
185 1.7.8.2 nathanw if (!strchr(s, '/'))
186 1.7.8.2 nathanw xerrx(1, "%s: bad format", devstr);
187 1.7.8.2 nathanw
188 1.7.8.2 nathanw if (!(s = lookupif(s, &interface, &unit_if)))
189 1.7.8.2 nathanw xerrx(1, "%s: unknown interface", devstr);
190 1.7.8.2 nathanw
191 1.7.8.2 nathanw while (*s == '/') /* skip slashes */
192 1.7.8.2 nathanw s++;
193 1.7.8.2 nathanw } else {
194 1.7.8.2 nathanw /* make lint happy */
195 1.7.8.2 nathanw interface = 0;
196 1.7.8.2 nathanw unit_if = 0;
197 1.7.8.2 nathanw }
198 1.7.8.2 nathanw
199 1.7.8.2 nathanw /* allow r at the top */
200 1.7.8.2 nathanw if (*s == 'r')
201 1.7.8.2 nathanw s++;
202 1.7.8.2 nathanw
203 1.7.8.2 nathanw for (u = 0; u < sizeof devtable / sizeof devtable[0]; u++)
204 1.7.8.2 nathanw if (s[0] == devtable[u].name[0] && s[1] == devtable[u].name[1])
205 1.7.8.2 nathanw goto found;
206 1.7.8.2 nathanw
207 1.7.8.2 nathanw /* not found */
208 1.7.8.2 nathanw xerrx(1, "%s: unknown device", devstr);
209 1.7.8.2 nathanw
210 1.7.8.2 nathanw found: major = devtable[u].major;
211 1.7.8.2 nathanw
212 1.7.8.2 nathanw /*
213 1.7.8.2 nathanw * <type>@unit[,lun][:part]
214 1.7.8.2 nathanw * "sd@1,3:a"
215 1.7.8.2 nathanw */
216 1.7.8.2 nathanw
217 1.7.8.2 nathanw /* get device unit # */
218 1.7.8.2 nathanw s += 2;
219 1.7.8.2 nathanw if (*s == '@')
220 1.7.8.2 nathanw s++;
221 1.7.8.2 nathanw if (!*s)
222 1.7.8.2 nathanw xerrx(1, "%s: missing unit number", devstr);
223 1.7.8.2 nathanw if (!ISDIGIT(*s))
224 1.7.8.2 nathanw xerrx(1, "%s: wrong device", devstr);
225 1.7.8.2 nathanw
226 1.7.8.2 nathanw unit = 0;
227 1.7.8.2 nathanw GETDECIMAL(unit, s);
228 1.7.8.2 nathanw
229 1.7.8.2 nathanw lun = 0;
230 1.7.8.2 nathanw if (*s == ',') {
231 1.7.8.2 nathanw s++;
232 1.7.8.2 nathanw if (!ISDIGIT(*s))
233 1.7.8.2 nathanw xerrx(1, "%s: wrong device", devstr);
234 1.7.8.2 nathanw GETDECIMAL(lun, s);
235 1.7.8.2 nathanw }
236 1.7.8.2 nathanw
237 1.7.8.2 nathanw /* get device partition */
238 1.7.8.2 nathanw if (*s == ':')
239 1.7.8.2 nathanw s++;
240 1.7.8.2 nathanw if (!*s)
241 1.7.8.2 nathanw partition = 0; /* no partition letter -- assuming 'a' */
242 1.7.8.2 nathanw else if (!s[1])
243 1.7.8.2 nathanw partition = *s - 'a';
244 1.7.8.2 nathanw else
245 1.7.8.2 nathanw xerrx(1, "%s: wrong partition letter", devstr);
246 1.7.8.2 nathanw
247 1.7.8.2 nathanw /*
248 1.7.8.2 nathanw * sanity check
249 1.7.8.2 nathanw */
250 1.7.8.2 nathanw if (unit_if >= 16)
251 1.7.8.2 nathanw xerrx(1, "%s: interface unit # too large", devstr);
252 1.7.8.2 nathanw if (unit >= 16)
253 1.7.8.2 nathanw xerrx(1, "%s: device unit # too large", devstr);
254 1.7.8.2 nathanw if (lun >= 8)
255 1.7.8.2 nathanw xerrx(1, "%s: SCSI LUN >= 8 is not supported yet", devstr);
256 1.7.8.2 nathanw if (partition >= 16)
257 1.7.8.2 nathanw xerrx(1, "%s: unsupported partition", devstr);
258 1.7.8.2 nathanw
259 1.7.8.2 nathanw /*
260 1.7.8.2 nathanw * encode device to be passed to kernel
261 1.7.8.2 nathanw */
262 1.7.8.2 nathanw if (X68K_BOOT_DEV_IS_SCSI(major)) {
263 1.7.8.2 nathanw /*
264 1.7.8.2 nathanw * encode SCSI device
265 1.7.8.2 nathanw */
266 1.7.8.2 nathanw if (interface == 0)
267 1.7.8.2 nathanw get_current_scsi_interface(&interface, &unit_if);
268 1.7.8.2 nathanw
269 1.7.8.2 nathanw dev = X68K_MAKESCSIBOOTDEV(major, interface, unit_if,
270 1.7.8.2 nathanw unit, lun, partition);
271 1.7.8.2 nathanw } else {
272 1.7.8.2 nathanw /* encode non-SCSI device */
273 1.7.8.2 nathanw dev = X68K_MAKEBOOTDEV(major, unit, partition);
274 1.7.8.2 nathanw }
275 1.7.8.2 nathanw
276 1.7.8.2 nathanw if (opt_v)
277 1.7.8.2 nathanw xwarnx("%s: major %u, if %u, un_if %u, unit %u, lun %u, partition %u; bootdev 0x%x",
278 1.7.8.2 nathanw devstr, major, interface, unit_if, unit, lun, partition, dev);
279 1.7.8.2 nathanw
280 1.7.8.2 nathanw return dev;
281 1.7.8.2 nathanw }
282 1.7.8.2 nathanw
283 1.7.8.2 nathanw #define LOADBSD
284 1.7.8.2 nathanw #include "../common/exec_sub.c"
285 1.7.8.2 nathanw
286 1.7.8.2 nathanw /*
287 1.7.8.2 nathanw * read kernel and create trampoline
288 1.7.8.2 nathanw *
289 1.7.8.2 nathanw * |----------------------| <- allocated buf addr
290 1.7.8.2 nathanw * | kernel image |
291 1.7.8.2 nathanw * ~ (exec file contents) ~
292 1.7.8.2 nathanw * | |
293 1.7.8.2 nathanw * |----------------------| <- return value (entry addr of trampoline)
294 1.7.8.2 nathanw * | struct tramparg |
295 1.7.8.2 nathanw * | (trampoline args) |
296 1.7.8.2 nathanw * |----------------------|
297 1.7.8.2 nathanw * | trampoline code |
298 1.7.8.2 nathanw * | (in assembly) |
299 1.7.8.2 nathanw * |----------------------|
300 1.7.8.2 nathanw */
301 1.7.8.2 nathanw static struct tramparg *
302 1.7.8.2 nathanw read_kernel(fn)
303 1.7.8.2 nathanw const char *fn;
304 1.7.8.2 nathanw {
305 1.7.8.2 nathanw int fd;
306 1.7.8.2 nathanw union dos_fcb *fcb;
307 1.7.8.2 nathanw size_t filesize, nread;
308 1.7.8.2 nathanw void *buf;
309 1.7.8.2 nathanw struct tramparg *arg;
310 1.7.8.2 nathanw size_t size_tramp = end_trampoline - trampoline;
311 1.7.8.2 nathanw
312 1.7.8.2 nathanw kernel_fn = fn;
313 1.7.8.2 nathanw
314 1.7.8.2 nathanw if ((fd = DOS_OPEN(fn, 0x00)) < 0) /* read only */
315 1.7.8.2 nathanw xerr(1, "%s: open", fn);
316 1.7.8.2 nathanw
317 1.7.8.2 nathanw if ((int)(fcb = DOS_GET_FCB_ADR(fd)) < 0)
318 1.7.8.2 nathanw xerr(1, "%s: get_fcb_adr", fn);
319 1.7.8.2 nathanw
320 1.7.8.2 nathanw /*
321 1.7.8.2 nathanw * XXX FCB is in supervisor area
322 1.7.8.2 nathanw */
323 1.7.8.2 nathanw /*if (fcb->blk.mode != 0)*/
324 1.7.8.2 nathanw if (IOCS_B_BPEEK((char *)fcb + 1) & 0x80)
325 1.7.8.2 nathanw xerrx(1, "%s: Not a regular file", fn);
326 1.7.8.2 nathanw
327 1.7.8.2 nathanw /*filesize = fcb->blk.size;*/
328 1.7.8.2 nathanw filesize = IOCS_B_LPEEK(&fcb->blk.size);
329 1.7.8.2 nathanw
330 1.7.8.2 nathanw if (filesize < sizeof(Elf32_Ehdr))
331 1.7.8.2 nathanw xerrx(1, "%s: Unknown format", fn);
332 1.7.8.2 nathanw
333 1.7.8.2 nathanw /*
334 1.7.8.2 nathanw * read entire file
335 1.7.8.2 nathanw */
336 1.7.8.2 nathanw if ((int)(buf = DOS_MALLOC(filesize + ALIGNBYTES
337 1.7.8.2 nathanw + sizeof(struct tramparg)
338 1.7.8.2 nathanw + size_tramp + SIZE_TMPSTACK)) < 0)
339 1.7.8.2 nathanw xerr(1, "read_kernel");
340 1.7.8.2 nathanw
341 1.7.8.2 nathanw if ((nread = DOS_READ(fd, buf, filesize)) != filesize) {
342 1.7.8.2 nathanw if ((int)nread < 0)
343 1.7.8.2 nathanw xerr(1, "%s: read", fn);
344 1.7.8.2 nathanw else
345 1.7.8.2 nathanw xerrx(1, "%s: short read", fn);
346 1.7.8.2 nathanw }
347 1.7.8.2 nathanw
348 1.7.8.2 nathanw if (DOS_CLOSE(fd) < 0)
349 1.7.8.2 nathanw xerr(1, "%s: close", fn);
350 1.7.8.2 nathanw
351 1.7.8.2 nathanw /*
352 1.7.8.2 nathanw * address for argument for trampoline code
353 1.7.8.2 nathanw */
354 1.7.8.2 nathanw arg = (struct tramparg *) ALIGN((char *) buf + nread);
355 1.7.8.2 nathanw
356 1.7.8.2 nathanw if (opt_v)
357 1.7.8.2 nathanw xwarnx("trampoline arg at %p", arg);
358 1.7.8.2 nathanw
359 1.7.8.2 nathanw xk_load(&arg->xk, buf, 0 /* XXX load addr should not be fixed */);
360 1.7.8.2 nathanw
361 1.7.8.2 nathanw /*
362 1.7.8.2 nathanw * create argument for trampoline code
363 1.7.8.2 nathanw */
364 1.7.8.2 nathanw arg->bsr_inst = TRAMP_BSR + sizeof(struct tramparg) - 2;
365 1.7.8.2 nathanw arg->tmp_stack = (char *) arg + sizeof(struct tramparg)
366 1.7.8.2 nathanw + size_tramp + SIZE_TMPSTACK;
367 1.7.8.2 nathanw arg->mpu_type = IOCS_MPU_STAT() & 0xff;
368 1.7.8.2 nathanw
369 1.7.8.2 nathanw arg->xk.d5 = IOCS_BOOTINF(); /* unused for now */
370 1.7.8.2 nathanw #if 0
371 1.7.8.2 nathanw /* filled afterwards */
372 1.7.8.2 nathanw arg->xk.rootdev =
373 1.7.8.2 nathanw arg->xk.boothowto =
374 1.7.8.2 nathanw #endif
375 1.7.8.2 nathanw
376 1.7.8.2 nathanw if (opt_v)
377 1.7.8.2 nathanw xwarnx("args: mpu %d, image %p, load 0x%x, entry 0x%x",
378 1.7.8.2 nathanw arg->mpu_type, arg->xk.sec[0].sec_image,
379 1.7.8.2 nathanw arg->xk.load_addr, arg->xk.entry_addr);
380 1.7.8.2 nathanw
381 1.7.8.2 nathanw /*
382 1.7.8.2 nathanw * copy trampoline code
383 1.7.8.2 nathanw */
384 1.7.8.2 nathanw if (opt_v)
385 1.7.8.2 nathanw xwarnx("trampoline code at %p (%u bytes)",
386 1.7.8.2 nathanw (char *) arg + sizeof(struct tramparg), size_tramp);
387 1.7.8.2 nathanw
388 1.7.8.2 nathanw memcpy((char *) arg + sizeof(struct tramparg), trampoline, size_tramp);
389 1.7.8.2 nathanw
390 1.7.8.2 nathanw return arg;
391 1.7.8.2 nathanw }
392 1.7.8.2 nathanw
393 1.7.8.2 nathanw /*
394 1.7.8.2 nathanw * MC68000/010 -> return zero
395 1.7.8.2 nathanw * MC68020 and later -> return nonzero
396 1.7.8.2 nathanw */
397 1.7.8.2 nathanw static int
398 1.7.8.2 nathanw chkmpu()
399 1.7.8.2 nathanw {
400 1.7.8.2 nathanw register int ret asm("%d0");
401 1.7.8.2 nathanw
402 1.7.8.2 nathanw asm("| %0 <- this must be %%d0\n\
403 1.7.8.2 nathanw moveq #1,%%d0\n\
404 1.7.8.2 nathanw .long 0x103B02FF | foo: moveb %%pc@((foo+1)-foo-2:B,d0:W:2),%%d0\n\
405 1.7.8.2 nathanw | ^ ^\n\
406 1.7.8.2 nathanw | %%d0.b = 0x02 (68000/010)\n\
407 1.7.8.2 nathanw | = 0xff (68020 and later)\n\
408 1.7.8.2 nathanw bmis 1f\n\
409 1.7.8.2 nathanw moveq #0,%%d0 | 68000/010\n\
410 1.7.8.2 nathanw 1:" : "=d" (ret));
411 1.7.8.2 nathanw
412 1.7.8.2 nathanw return ret;
413 1.7.8.2 nathanw }
414 1.7.8.2 nathanw
415 1.7.8.2 nathanw static __dead void
416 1.7.8.2 nathanw usage(status, msg)
417 1.7.8.2 nathanw int status;
418 1.7.8.2 nathanw const char *msg;
419 1.7.8.2 nathanw {
420 1.7.8.2 nathanw extern const char *const __progname;
421 1.7.8.2 nathanw
422 1.7.8.2 nathanw if (msg)
423 1.7.8.2 nathanw xwarnx("%s", msg);
424 1.7.8.2 nathanw
425 1.7.8.2 nathanw xerrprintf("\
426 1.7.8.2 nathanw %s [-hvV] [-abDs] [-r root_device] netbsd\n\
427 1.7.8.2 nathanw \n\
428 1.7.8.2 nathanw loadbsd options:\n\
429 1.7.8.2 nathanw \t-h help\n\
430 1.7.8.2 nathanw \t-v verbose\n\
431 1.7.8.2 nathanw \t-V print version and exit\n\
432 1.7.8.2 nathanw \n\
433 1.7.8.2 nathanw kernel options:\n\
434 1.7.8.2 nathanw \t-a auto boot, opposite of -s\n\
435 1.7.8.2 nathanw \t-s single user boot (default)\n\
436 1.7.8.2 nathanw \t-D enter kernel debugger\n\
437 1.7.8.2 nathanw \t-b ask root device\n\
438 1.7.8.2 nathanw \t-r specify root device (default %s)\n\
439 1.7.8.2 nathanw \t format: [/interface/]device@unit[,lun][:partition]\n\
440 1.7.8.2 nathanw \t interface: one of spc@0, spc@1, mha@0\n\
441 1.7.8.2 nathanw \t (current boot interface if omitted)\n\
442 1.7.8.2 nathanw \t device: one of fd, sd, cd, md, ne\n\
443 1.7.8.2 nathanw \t unit: device unit number (SCSI ID for SCSI device)\n\
444 1.7.8.2 nathanw \t lun: SCSI LUN # (0 if omitted)\n\
445 1.7.8.2 nathanw \t partition: partition letter ('a' if omitted)\n\
446 1.7.8.2 nathanw ", __progname, DEFAULT_ROOTDEVNAME);
447 1.7.8.2 nathanw
448 1.7.8.2 nathanw DOS_EXIT2(status);
449 1.7.8.2 nathanw }
450 1.7.8.2 nathanw
451 1.7.8.2 nathanw int
452 1.7.8.2 nathanw main(argc, argv)
453 1.7.8.2 nathanw int argc;
454 1.7.8.2 nathanw char *argv[];
455 1.7.8.2 nathanw {
456 1.7.8.2 nathanw char *rootdevname = 0;
457 1.7.8.2 nathanw int rootdev;
458 1.7.8.2 nathanw u_long boothowto = RB_SINGLE;
459 1.7.8.2 nathanw const char *kernel;
460 1.7.8.2 nathanw char *p, **flg, **arg;
461 1.7.8.2 nathanw struct tramparg *tramp;
462 1.7.8.2 nathanw struct dos_dregs regs; /* unused... */
463 1.7.8.2 nathanw int i;
464 1.7.8.2 nathanw
465 1.7.8.2 nathanw /* parse options */
466 1.7.8.2 nathanw for (arg = flg = argv + 1; (p = *flg) && *p == '-'; ) {
467 1.7.8.2 nathanw int c;
468 1.7.8.2 nathanw
469 1.7.8.2 nathanw while ((c = *++p))
470 1.7.8.2 nathanw switch (c) {
471 1.7.8.2 nathanw case 'h':
472 1.7.8.2 nathanw usage(0, (char *) 0);
473 1.7.8.2 nathanw /* NOTREACHED */
474 1.7.8.2 nathanw break;
475 1.7.8.2 nathanw case 'N': /* don't actually execute kernel */
476 1.7.8.2 nathanw opt_N = 1;
477 1.7.8.2 nathanw break;
478 1.7.8.2 nathanw case 'v':
479 1.7.8.2 nathanw opt_v = 1;
480 1.7.8.2 nathanw boothowto |= AB_VERBOSE; /* XXX */
481 1.7.8.2 nathanw break;
482 1.7.8.2 nathanw case 'V':
483 1.7.8.2 nathanw xprintf("loadbsd %s\n", VERSION);
484 1.7.8.2 nathanw return 0;
485 1.7.8.2 nathanw
486 1.7.8.2 nathanw /*
487 1.7.8.2 nathanw * kernel boot flags
488 1.7.8.2 nathanw */
489 1.7.8.2 nathanw case 'r':
490 1.7.8.2 nathanw if (rootdevname)
491 1.7.8.2 nathanw usage(1, "multiple -r flags");
492 1.7.8.2 nathanw else if (!*++arg)
493 1.7.8.2 nathanw usage(1, "-r requires device name");
494 1.7.8.2 nathanw else
495 1.7.8.2 nathanw rootdevname = *arg;
496 1.7.8.2 nathanw break;
497 1.7.8.2 nathanw case 'b':
498 1.7.8.2 nathanw boothowto |= RB_ASKNAME;
499 1.7.8.2 nathanw break;
500 1.7.8.2 nathanw case 'a':
501 1.7.8.2 nathanw boothowto &= ~RB_SINGLE;
502 1.7.8.2 nathanw break;
503 1.7.8.2 nathanw case 's':
504 1.7.8.2 nathanw boothowto |= RB_SINGLE;
505 1.7.8.2 nathanw break;
506 1.7.8.2 nathanw case 'D':
507 1.7.8.2 nathanw boothowto |= RB_KDB;
508 1.7.8.2 nathanw break;
509 1.7.8.2 nathanw case 'q':
510 1.7.8.2 nathanw boothowto |= AB_QUIET;
511 1.7.8.2 nathanw break;
512 1.7.8.2 nathanw
513 1.7.8.2 nathanw default:
514 1.7.8.2 nathanw usage(1, (char *) 0);
515 1.7.8.2 nathanw /* NOTREACHED */
516 1.7.8.2 nathanw break;
517 1.7.8.2 nathanw }
518 1.7.8.2 nathanw flg = ++arg;
519 1.7.8.2 nathanw }
520 1.7.8.2 nathanw
521 1.7.8.2 nathanw /* check MPU */
522 1.7.8.2 nathanw if (chkmpu() == 0)
523 1.7.8.2 nathanw xerrx(1, "Can't boot NetBSD on 68000/010");
524 1.7.8.2 nathanw
525 1.7.8.2 nathanw argc -= arg - argv;
526 1.7.8.2 nathanw argv = arg;
527 1.7.8.2 nathanw
528 1.7.8.2 nathanw if (argc != 1)
529 1.7.8.2 nathanw usage(1, (char *) 0);
530 1.7.8.2 nathanw
531 1.7.8.2 nathanw kernel = *argv;
532 1.7.8.2 nathanw
533 1.7.8.2 nathanw rootdev = bootdev(rootdevname ? rootdevname : DEFAULT_ROOTDEVNAME);
534 1.7.8.2 nathanw
535 1.7.8.2 nathanw if (opt_v)
536 1.7.8.2 nathanw xwarnx("boothowto 0x%x", boothowto);
537 1.7.8.2 nathanw
538 1.7.8.2 nathanw tramp = read_kernel(kernel);
539 1.7.8.2 nathanw
540 1.7.8.2 nathanw tramp->xk.rootdev = rootdev;
541 1.7.8.2 nathanw tramp->xk.boothowto = boothowto;
542 1.7.8.2 nathanw
543 1.7.8.2 nathanw /*
544 1.7.8.2 nathanw * we never return, and make sure the disk cache
545 1.7.8.2 nathanw * be flushed (if write-back cache is enabled)
546 1.7.8.2 nathanw */
547 1.7.8.2 nathanw if (opt_v)
548 1.7.8.2 nathanw xwarnx("flush disk cache...");
549 1.7.8.2 nathanw
550 1.7.8.2 nathanw i = DOS_FFLUSH_SET(1); /* enable fflush */
551 1.7.8.2 nathanw DOS_FFLUSH(); /* then, issue fflush */
552 1.7.8.2 nathanw (void) DOS_FFLUSH_SET(i); /* restore old mode just in case */
553 1.7.8.2 nathanw
554 1.7.8.2 nathanw /*
555 1.7.8.2 nathanw * the program assumes the MPU caches off
556 1.7.8.2 nathanw */
557 1.7.8.2 nathanw if (opt_v)
558 1.7.8.2 nathanw xwarnx("flush and disable MPU caches...");
559 1.7.8.2 nathanw
560 1.7.8.2 nathanw IOCS_CACHE_MD(-1); /* flush */
561 1.7.8.2 nathanw if (!opt_N)
562 1.7.8.2 nathanw IOCS_CACHE_MD(0); /* disable both caches */
563 1.7.8.2 nathanw
564 1.7.8.2 nathanw if (opt_v)
565 1.7.8.2 nathanw xwarnx("Jumping to the kernel. Good Luck!");
566 1.7.8.2 nathanw
567 1.7.8.2 nathanw if (opt_N)
568 1.7.8.2 nathanw xerrx(0, "But don't actually do it.");
569 1.7.8.2 nathanw
570 1.7.8.2 nathanw DOS_SUPER_JSR((void (*) __P((void))) tramp, ®s, ®s);
571 1.7.8.2 nathanw
572 1.7.8.2 nathanw /* NOTREACHED */
573 1.7.8.2 nathanw
574 1.7.8.2 nathanw xwarnx("??? return from kernel");
575 1.7.8.2 nathanw
576 1.7.8.2 nathanw return 1;
577 1.7.8.2 nathanw }
578