1ca987d46SWarner Losh /*-
2ca987d46SWarner Losh * Copyright (c) 1998 Robert Nordier
3ca987d46SWarner Losh * All rights reserved.
4ca987d46SWarner Losh * Copyright (c) 2001 Robert Drehmel
5ca987d46SWarner Losh * All rights reserved.
6ca987d46SWarner Losh *
7ca987d46SWarner Losh * Redistribution and use in source and binary forms are freely
8ca987d46SWarner Losh * permitted provided that the above copyright notice and this
9ca987d46SWarner Losh * paragraph and the following disclaimer are duplicated in all
10ca987d46SWarner Losh * such forms.
11ca987d46SWarner Losh *
12ca987d46SWarner Losh * This software is provided "AS IS" and without any express or
13ca987d46SWarner Losh * implied warranties, including, without limitation, the implied
14ca987d46SWarner Losh * warranties of merchantability and fitness for a particular
15ca987d46SWarner Losh * purpose.
16ca987d46SWarner Losh */
17ca987d46SWarner Losh
18ca987d46SWarner Losh #include <sys/param.h>
19ca987d46SWarner Losh #include <sys/dirent.h>
20f8328864SLeandro Lupori #include <sys/endian.h>
21ca987d46SWarner Losh #include <machine/elf.h>
22ca987d46SWarner Losh #include <machine/stdarg.h>
23a76b2d3dSWarner Losh #include <machine/md_var.h>
24ff7449d6SLeandro Lupori #include <ufs/ffs/fs.h>
25ca987d46SWarner Losh
26ca987d46SWarner Losh #include "paths.h"
27ca987d46SWarner Losh
28ca987d46SWarner Losh #define BSIZEMAX 16384
29ca987d46SWarner Losh
30ca987d46SWarner Losh typedef int putc_func_t(char c, void *arg);
31ca987d46SWarner Losh typedef int32_t ofwh_t;
32ca987d46SWarner Losh
33ca987d46SWarner Losh struct sp_data {
34ca987d46SWarner Losh char *sp_buf;
35ca987d46SWarner Losh u_int sp_len;
36ca987d46SWarner Losh u_int sp_size;
37ca987d46SWarner Losh };
38ca987d46SWarner Losh
39ca987d46SWarner Losh static const char digits[] = "0123456789abcdef";
40ca987d46SWarner Losh
41ca987d46SWarner Losh static char bootpath[128];
42ca987d46SWarner Losh static char bootargs[128];
43ca987d46SWarner Losh
44ca987d46SWarner Losh static ofwh_t bootdev;
45ca987d46SWarner Losh
46ca987d46SWarner Losh static struct fs fs;
47ca987d46SWarner Losh static char blkbuf[BSIZEMAX];
48ca987d46SWarner Losh static unsigned int fsblks;
49ca987d46SWarner Losh
50ca987d46SWarner Losh static uint32_t fs_off;
51ca987d46SWarner Losh
52ca987d46SWarner Losh int main(int ac, char **av);
53ca987d46SWarner Losh
54ca987d46SWarner Losh static void exit(int) __dead2;
55ca987d46SWarner Losh static void load(const char *);
5656e53cb8SWarner Losh static int dskread(void *, uint64_t, int);
57ca987d46SWarner Losh
58*5762de72SAlfonso Gregory static void usage(void) __dead2;
59ca987d46SWarner Losh
60ca987d46SWarner Losh static void bcopy(const void *src, void *dst, size_t len);
61ca987d46SWarner Losh static void bzero(void *b, size_t len);
62ca987d46SWarner Losh
63ca987d46SWarner Losh static int domount(const char *device, int quiet);
64ca987d46SWarner Losh
65ca987d46SWarner Losh static void panic(const char *fmt, ...) __dead2;
66ca987d46SWarner Losh static int printf(const char *fmt, ...);
67ca987d46SWarner Losh static int putchar(char c, void *arg);
68ca987d46SWarner Losh static int vprintf(const char *fmt, va_list ap);
69ca987d46SWarner Losh static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
70ca987d46SWarner Losh
71ca987d46SWarner Losh static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
72ca987d46SWarner Losh static int __putc(char c, void *arg);
73ca987d46SWarner Losh static int __puts(const char *s, putc_func_t *putc, void *arg);
74ca987d46SWarner Losh static int __sputc(char c, void *arg);
75ca987d46SWarner Losh static char *__uitoa(char *buf, u_int val, int base);
76ca987d46SWarner Losh static char *__ultoa(char *buf, u_long val, int base);
77ca987d46SWarner Losh
78ca987d46SWarner Losh /*
79ca987d46SWarner Losh * Open Firmware interface functions
80ca987d46SWarner Losh */
8156e53cb8SWarner Losh typedef uint32_t ofwcell_t;
8256e53cb8SWarner Losh typedef uint32_t u_ofwh_t;
83f8328864SLeandro Lupori typedef int (*ofwfp_t)(ofwcell_t *);
84ca987d46SWarner Losh ofwfp_t ofw; /* the prom Open Firmware entry */
85ca987d46SWarner Losh ofwh_t chosenh;
86ca987d46SWarner Losh
87f8328864SLeandro Lupori void ofw_init(void *, int, ofwfp_t, char *, int);
88ca987d46SWarner Losh static ofwh_t ofw_finddevice(const char *);
89ca987d46SWarner Losh static ofwh_t ofw_open(const char *);
90ca987d46SWarner Losh static int ofw_close(ofwh_t);
91ca987d46SWarner Losh static int ofw_getprop(ofwh_t, const char *, void *, size_t);
92ca987d46SWarner Losh static int ofw_setprop(ofwh_t, const char *, void *, size_t);
93ca987d46SWarner Losh static int ofw_read(ofwh_t, void *, size_t);
94ca987d46SWarner Losh static int ofw_write(ofwh_t, const void *, size_t);
95ca987d46SWarner Losh static int ofw_claim(void *virt, size_t len, u_int align);
9656e53cb8SWarner Losh static int ofw_seek(ofwh_t, uint64_t);
97ca987d46SWarner Losh static void ofw_exit(void) __dead2;
98ca987d46SWarner Losh
99ca987d46SWarner Losh ofwh_t bootdevh;
100ca987d46SWarner Losh ofwh_t stdinh, stdouth;
101ca987d46SWarner Losh
102f8328864SLeandro Lupori /*
103f8328864SLeandro Lupori * Note about the entry point:
104f8328864SLeandro Lupori *
105f8328864SLeandro Lupori * For some odd reason, the first page of the load appears to have trouble
106f8328864SLeandro Lupori * when entering in LE. The first five instructions decode weirdly.
107f8328864SLeandro Lupori * I suspect it is some cache weirdness between the ELF headers and .text.
108f8328864SLeandro Lupori *
109f8328864SLeandro Lupori * Ensure we have a gap between the start of .text and the entry as a
110f8328864SLeandro Lupori * workaround.
111f8328864SLeandro Lupori */
112ca987d46SWarner Losh __asm(" \n\
113ca987d46SWarner Losh .data \n\
114ca987d46SWarner Losh .align 4 \n\
115ca987d46SWarner Losh stack: \n\
116ca987d46SWarner Losh .space 16384 \n\
117ca987d46SWarner Losh \n\
118ca987d46SWarner Losh .text \n\
119f8328864SLeandro Lupori /* SLOF cache hack */ \n\
120f8328864SLeandro Lupori .space 4096 \n\
121ca987d46SWarner Losh .globl _start \n\
122ca987d46SWarner Losh _start: \n\
123ca987d46SWarner Losh lis %r1,stack@ha \n\
124ca987d46SWarner Losh addi %r1,%r1,stack@l \n\
125ca987d46SWarner Losh addi %r1,%r1,8192 \n\
126ca987d46SWarner Losh \n\
127ca987d46SWarner Losh b ofw_init \n\
128ca987d46SWarner Losh ");
129ca987d46SWarner Losh
130f8328864SLeandro Lupori ofwfp_t realofw;
131f8328864SLeandro Lupori
132f8328864SLeandro Lupori #if BYTE_ORDER == LITTLE_ENDIAN
133f8328864SLeandro Lupori /*
134f8328864SLeandro Lupori * Minimal endianness-swap trampoline for LE.
135f8328864SLeandro Lupori */
136f8328864SLeandro Lupori __attribute__((naked)) int
ofwtramp(void * buf,ofwfp_t cb)137f8328864SLeandro Lupori ofwtramp(void *buf, ofwfp_t cb)
138f8328864SLeandro Lupori {
139f8328864SLeandro Lupori __asm(" \n\
140f8328864SLeandro Lupori mflr %r0 \n\
141f8328864SLeandro Lupori stw %r0, 4(%r1) \n\
142f8328864SLeandro Lupori stwu %r1, -16(%r1) \n\
143f8328864SLeandro Lupori stw %r30, 8(%r1) \n\
144f8328864SLeandro Lupori /* Save current MSR for restoration post-call. */ \n\
145f8328864SLeandro Lupori mfmsr %r30 \n\
146f8328864SLeandro Lupori mr %r5, %r30 \n\
147f8328864SLeandro Lupori /* Remove LE bit from MSR. */ \n\
148f8328864SLeandro Lupori clrrwi %r5, %r5, 1 \n\
149f8328864SLeandro Lupori mtsrr0 %r4 \n\
150f8328864SLeandro Lupori mtsrr1 %r5 \n\
151f8328864SLeandro Lupori bcl 20, 31, .+4 /* LOAD_LR_NIA */ \n\
152f8328864SLeandro Lupori 1: \n\
153f8328864SLeandro Lupori mflr %r4 \n\
154f8328864SLeandro Lupori addi %r4, %r4, (2f - 1b) \n\
155f8328864SLeandro Lupori mtlr %r4 \n\
156f8328864SLeandro Lupori /* Switch to BE and transfer control to OF entry */ \n\
157f8328864SLeandro Lupori rfid \n\
158f8328864SLeandro Lupori 2: \n\
159f8328864SLeandro Lupori /* Control is returned here, but in BE. */ \n\
160f8328864SLeandro Lupori .long 0x05009f42 /* LOAD_LR_NIA */\n\
161f8328864SLeandro Lupori /* 0: */\n\
162f8328864SLeandro Lupori .long 0xa603db7f /* mtsrr1 %r30 */\n\
163f8328864SLeandro Lupori .long 0xa602c87f /* mflr %r30 */\n\
164f8328864SLeandro Lupori .long 0x1400de3b /* addi %r30, %r30, (1f - 0b) */\n\
165f8328864SLeandro Lupori .long 0xa603da7f /* mtsrr0 %r30 */\n\
166f8328864SLeandro Lupori .long 0x2400004c /* rfid */\n\
167f8328864SLeandro Lupori /* 1: */\n\
168f8328864SLeandro Lupori 1: \n\
169f8328864SLeandro Lupori /* Back to normal. Tidy up for return. */ \n\
170f8328864SLeandro Lupori lwz %r30, 8(%r1) \n\
171f8328864SLeandro Lupori lwz %r0, 20(%r1) \n\
172f8328864SLeandro Lupori addi %r1, %r1, 16 \n\
173f8328864SLeandro Lupori mtlr %r0 \n\
174f8328864SLeandro Lupori blr \n\
175f8328864SLeandro Lupori ");
176f8328864SLeandro Lupori }
177f8328864SLeandro Lupori
178f8328864SLeandro Lupori /*
179f8328864SLeandro Lupori * Little-endian OFW entrypoint replacement.
180f8328864SLeandro Lupori *
181f8328864SLeandro Lupori * We are doing all the byteswapping in one place here to save space.
182f8328864SLeandro Lupori * This means instance handles will be byteswapped as well.
183f8328864SLeandro Lupori */
184f8328864SLeandro Lupori int
call_ofw(ofwcell_t * buf)185f8328864SLeandro Lupori call_ofw(ofwcell_t* buf)
186f8328864SLeandro Lupori {
187f8328864SLeandro Lupori int ret, i, ncells;
188f8328864SLeandro Lupori
189f8328864SLeandro Lupori ncells = 3 + buf[1] + buf[2];
190f8328864SLeandro Lupori for (i = 0; i < ncells; i++)
191f8328864SLeandro Lupori buf[i] = htobe32(buf[i]);
192f8328864SLeandro Lupori
193f8328864SLeandro Lupori ret = (ofwtramp(buf, realofw));
194f8328864SLeandro Lupori for (i = 0; i < ncells; i++)
195f8328864SLeandro Lupori buf[i] = be32toh(buf[i]);
196f8328864SLeandro Lupori return (ret);
197f8328864SLeandro Lupori }
198f8328864SLeandro Lupori #endif
199f8328864SLeandro Lupori
200ca987d46SWarner Losh void
ofw_init(void * vpd,int res,ofwfp_t openfirm,char * arg,int argl)201f8328864SLeandro Lupori ofw_init(void *vpd, int res, ofwfp_t openfirm, char *arg, int argl)
202ca987d46SWarner Losh {
203ca987d46SWarner Losh char *av[16];
204ca987d46SWarner Losh char *p;
205ca987d46SWarner Losh int ac;
206ca987d46SWarner Losh
207f8328864SLeandro Lupori #if BYTE_ORDER == LITTLE_ENDIAN
208f8328864SLeandro Lupori realofw = openfirm;
209f8328864SLeandro Lupori ofw = call_ofw;
210f8328864SLeandro Lupori #else
211f8328864SLeandro Lupori realofw = ofw = openfirm;
212f8328864SLeandro Lupori #endif
213ca987d46SWarner Losh
214ca987d46SWarner Losh chosenh = ofw_finddevice("/chosen");
215ca987d46SWarner Losh ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
216f8328864SLeandro Lupori stdinh = be32toh(stdinh);
217ca987d46SWarner Losh ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
218f8328864SLeandro Lupori stdouth = be32toh(stdouth);
219ca987d46SWarner Losh ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
220ca987d46SWarner Losh ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
221ca987d46SWarner Losh
222ca987d46SWarner Losh bootargs[sizeof(bootargs) - 1] = '\0';
223ca987d46SWarner Losh bootpath[sizeof(bootpath) - 1] = '\0';
224ca987d46SWarner Losh
225ca987d46SWarner Losh p = bootpath;
226ca987d46SWarner Losh while (*p != '\0') {
227ca987d46SWarner Losh /* Truncate partition ID */
228ca987d46SWarner Losh if (*p == ':') {
229ca987d46SWarner Losh ofw_close(bootdev);
230ca987d46SWarner Losh *(++p) = '\0';
231ca987d46SWarner Losh break;
232ca987d46SWarner Losh }
233ca987d46SWarner Losh p++;
234ca987d46SWarner Losh }
235ca987d46SWarner Losh
236ca987d46SWarner Losh ac = 0;
237ca987d46SWarner Losh p = bootargs;
238ca987d46SWarner Losh for (;;) {
239ca987d46SWarner Losh while (*p == ' ' && *p != '\0')
240ca987d46SWarner Losh p++;
241ca987d46SWarner Losh if (*p == '\0' || ac >= 16)
242ca987d46SWarner Losh break;
243ca987d46SWarner Losh av[ac++] = p;
244ca987d46SWarner Losh while (*p != ' ' && *p != '\0')
245ca987d46SWarner Losh p++;
246ca987d46SWarner Losh if (*p != '\0')
247ca987d46SWarner Losh *p++ = '\0';
248ca987d46SWarner Losh }
249ca987d46SWarner Losh
250ca987d46SWarner Losh exit(main(ac, av));
251ca987d46SWarner Losh }
252ca987d46SWarner Losh
253ca987d46SWarner Losh static ofwh_t
ofw_finddevice(const char * name)254ca987d46SWarner Losh ofw_finddevice(const char *name)
255ca987d46SWarner Losh {
256ca987d46SWarner Losh ofwcell_t args[] = {
257ca987d46SWarner Losh (ofwcell_t)"finddevice",
258ca987d46SWarner Losh 1,
259ca987d46SWarner Losh 1,
260ca987d46SWarner Losh (ofwcell_t)name,
261ca987d46SWarner Losh 0
262ca987d46SWarner Losh };
263ca987d46SWarner Losh
264ca987d46SWarner Losh if ((*ofw)(args)) {
265ca987d46SWarner Losh printf("ofw_finddevice: name=\"%s\"\n", name);
266ca987d46SWarner Losh return (1);
267ca987d46SWarner Losh }
268ca987d46SWarner Losh return (args[4]);
269ca987d46SWarner Losh }
270ca987d46SWarner Losh
271ca987d46SWarner Losh static int
ofw_getprop(ofwh_t ofwh,const char * name,void * buf,size_t len)272ca987d46SWarner Losh ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
273ca987d46SWarner Losh {
274ca987d46SWarner Losh ofwcell_t args[] = {
275ca987d46SWarner Losh (ofwcell_t)"getprop",
276ca987d46SWarner Losh 4,
277ca987d46SWarner Losh 1,
278ca987d46SWarner Losh (u_ofwh_t)ofwh,
279ca987d46SWarner Losh (ofwcell_t)name,
280ca987d46SWarner Losh (ofwcell_t)buf,
281ca987d46SWarner Losh len,
282ca987d46SWarner Losh 0
283ca987d46SWarner Losh };
284ca987d46SWarner Losh
285ca987d46SWarner Losh if ((*ofw)(args)) {
286ca987d46SWarner Losh printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
287ca987d46SWarner Losh ofwh, buf, len);
288ca987d46SWarner Losh return (1);
289ca987d46SWarner Losh }
290ca987d46SWarner Losh return (0);
291ca987d46SWarner Losh }
292ca987d46SWarner Losh
293ca987d46SWarner Losh static int
ofw_setprop(ofwh_t ofwh,const char * name,void * buf,size_t len)294ca987d46SWarner Losh ofw_setprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
295ca987d46SWarner Losh {
296ca987d46SWarner Losh ofwcell_t args[] = {
297ca987d46SWarner Losh (ofwcell_t)"setprop",
298ca987d46SWarner Losh 4,
299ca987d46SWarner Losh 1,
300ca987d46SWarner Losh (u_ofwh_t)ofwh,
301ca987d46SWarner Losh (ofwcell_t)name,
302ca987d46SWarner Losh (ofwcell_t)buf,
303ca987d46SWarner Losh len,
304ca987d46SWarner Losh 0
305ca987d46SWarner Losh };
306ca987d46SWarner Losh
307ca987d46SWarner Losh if ((*ofw)(args)) {
308ca987d46SWarner Losh printf("ofw_setprop: ofwh=0x%x buf=%p len=%u\n",
309ca987d46SWarner Losh ofwh, buf, len);
310ca987d46SWarner Losh return (1);
311ca987d46SWarner Losh }
312ca987d46SWarner Losh return (0);
313ca987d46SWarner Losh }
314ca987d46SWarner Losh
315ca987d46SWarner Losh static ofwh_t
ofw_open(const char * path)316ca987d46SWarner Losh ofw_open(const char *path)
317ca987d46SWarner Losh {
318ca987d46SWarner Losh ofwcell_t args[] = {
319ca987d46SWarner Losh (ofwcell_t)"open",
320ca987d46SWarner Losh 1,
321ca987d46SWarner Losh 1,
322ca987d46SWarner Losh (ofwcell_t)path,
323ca987d46SWarner Losh 0
324ca987d46SWarner Losh };
325ca987d46SWarner Losh
326ca987d46SWarner Losh if ((*ofw)(args)) {
327ca987d46SWarner Losh printf("ofw_open: path=\"%s\"\n", path);
328ca987d46SWarner Losh return (-1);
329ca987d46SWarner Losh }
330ca987d46SWarner Losh return (args[4]);
331ca987d46SWarner Losh }
332ca987d46SWarner Losh
333ca987d46SWarner Losh static int
ofw_close(ofwh_t devh)334ca987d46SWarner Losh ofw_close(ofwh_t devh)
335ca987d46SWarner Losh {
336ca987d46SWarner Losh ofwcell_t args[] = {
337ca987d46SWarner Losh (ofwcell_t)"close",
338ca987d46SWarner Losh 1,
339ca987d46SWarner Losh 0,
340ca987d46SWarner Losh (u_ofwh_t)devh
341ca987d46SWarner Losh };
342ca987d46SWarner Losh
343ca987d46SWarner Losh if ((*ofw)(args)) {
344ca987d46SWarner Losh printf("ofw_close: devh=0x%x\n", devh);
345ca987d46SWarner Losh return (1);
346ca987d46SWarner Losh }
347ca987d46SWarner Losh return (0);
348ca987d46SWarner Losh }
349ca987d46SWarner Losh
350ca987d46SWarner Losh static int
ofw_claim(void * virt,size_t len,u_int align)351ca987d46SWarner Losh ofw_claim(void *virt, size_t len, u_int align)
352ca987d46SWarner Losh {
353ca987d46SWarner Losh ofwcell_t args[] = {
354ca987d46SWarner Losh (ofwcell_t)"claim",
355ca987d46SWarner Losh 3,
356ca987d46SWarner Losh 1,
357ca987d46SWarner Losh (ofwcell_t)virt,
358ca987d46SWarner Losh len,
359ca987d46SWarner Losh align,
360ca987d46SWarner Losh 0,
361ca987d46SWarner Losh 0
362ca987d46SWarner Losh };
363ca987d46SWarner Losh
364ca987d46SWarner Losh if ((*ofw)(args)) {
365ca987d46SWarner Losh printf("ofw_claim: virt=%p len=%u\n", virt, len);
366ca987d46SWarner Losh return (1);
367ca987d46SWarner Losh }
368ca987d46SWarner Losh
369ca987d46SWarner Losh return (0);
370ca987d46SWarner Losh }
371ca987d46SWarner Losh
372ca987d46SWarner Losh static int
ofw_read(ofwh_t devh,void * buf,size_t len)373ca987d46SWarner Losh ofw_read(ofwh_t devh, void *buf, size_t len)
374ca987d46SWarner Losh {
375ca987d46SWarner Losh ofwcell_t args[] = {
376ca987d46SWarner Losh (ofwcell_t)"read",
377ca987d46SWarner Losh 3,
378ca987d46SWarner Losh 1,
379ca987d46SWarner Losh (u_ofwh_t)devh,
380ca987d46SWarner Losh (ofwcell_t)buf,
381ca987d46SWarner Losh len,
382ca987d46SWarner Losh 0
383ca987d46SWarner Losh };
384ca987d46SWarner Losh
385ca987d46SWarner Losh if ((*ofw)(args)) {
386ca987d46SWarner Losh printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
387ca987d46SWarner Losh return (1);
388ca987d46SWarner Losh }
389ca987d46SWarner Losh return (0);
390ca987d46SWarner Losh }
391ca987d46SWarner Losh
392ca987d46SWarner Losh static int
ofw_write(ofwh_t devh,const void * buf,size_t len)393ca987d46SWarner Losh ofw_write(ofwh_t devh, const void *buf, size_t len)
394ca987d46SWarner Losh {
395ca987d46SWarner Losh ofwcell_t args[] = {
396ca987d46SWarner Losh (ofwcell_t)"write",
397ca987d46SWarner Losh 3,
398ca987d46SWarner Losh 1,
399ca987d46SWarner Losh (u_ofwh_t)devh,
400ca987d46SWarner Losh (ofwcell_t)buf,
401ca987d46SWarner Losh len,
402ca987d46SWarner Losh 0
403ca987d46SWarner Losh };
404ca987d46SWarner Losh
405ca987d46SWarner Losh if ((*ofw)(args)) {
406ca987d46SWarner Losh printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
407ca987d46SWarner Losh return (1);
408ca987d46SWarner Losh }
409ca987d46SWarner Losh return (0);
410ca987d46SWarner Losh }
411ca987d46SWarner Losh
412ca987d46SWarner Losh static int
ofw_seek(ofwh_t devh,uint64_t off)41356e53cb8SWarner Losh ofw_seek(ofwh_t devh, uint64_t off)
414ca987d46SWarner Losh {
415ca987d46SWarner Losh ofwcell_t args[] = {
416ca987d46SWarner Losh (ofwcell_t)"seek",
417ca987d46SWarner Losh 3,
418ca987d46SWarner Losh 1,
419ca987d46SWarner Losh (u_ofwh_t)devh,
420ca987d46SWarner Losh off >> 32,
421ca987d46SWarner Losh off,
422ca987d46SWarner Losh 0
423ca987d46SWarner Losh };
424ca987d46SWarner Losh
425ca987d46SWarner Losh if ((*ofw)(args)) {
426ca987d46SWarner Losh printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
427ca987d46SWarner Losh return (1);
428ca987d46SWarner Losh }
429ca987d46SWarner Losh return (0);
430ca987d46SWarner Losh }
431ca987d46SWarner Losh
432ca987d46SWarner Losh static void
ofw_exit(void)433ca987d46SWarner Losh ofw_exit(void)
434ca987d46SWarner Losh {
435ca987d46SWarner Losh ofwcell_t args[3];
436ca987d46SWarner Losh
437ca987d46SWarner Losh args[0] = (ofwcell_t)"exit";
438ca987d46SWarner Losh args[1] = 0;
439ca987d46SWarner Losh args[2] = 0;
440ca987d46SWarner Losh
441ca987d46SWarner Losh for (;;)
442ca987d46SWarner Losh (*ofw)(args);
443ca987d46SWarner Losh }
444ca987d46SWarner Losh
445ca987d46SWarner Losh static void
bcopy(const void * src,void * dst,size_t len)446ca987d46SWarner Losh bcopy(const void *src, void *dst, size_t len)
447ca987d46SWarner Losh {
448ca987d46SWarner Losh const char *s = src;
449ca987d46SWarner Losh char *d = dst;
450ca987d46SWarner Losh
451ca987d46SWarner Losh while (len-- != 0)
452ca987d46SWarner Losh *d++ = *s++;
453ca987d46SWarner Losh }
454ca987d46SWarner Losh
455ca987d46SWarner Losh static void
memcpy(void * dst,const void * src,size_t len)456ca987d46SWarner Losh memcpy(void *dst, const void *src, size_t len)
457ca987d46SWarner Losh {
458ca987d46SWarner Losh bcopy(src, dst, len);
459ca987d46SWarner Losh }
460ca987d46SWarner Losh
461ca987d46SWarner Losh static void
bzero(void * b,size_t len)462ca987d46SWarner Losh bzero(void *b, size_t len)
463ca987d46SWarner Losh {
464ca987d46SWarner Losh char *p = b;
465ca987d46SWarner Losh
466ca987d46SWarner Losh while (len-- != 0)
467ca987d46SWarner Losh *p++ = 0;
468ca987d46SWarner Losh }
469ca987d46SWarner Losh
470ca987d46SWarner Losh static int
strcmp(const char * s1,const char * s2)471ca987d46SWarner Losh strcmp(const char *s1, const char *s2)
472ca987d46SWarner Losh {
473ca987d46SWarner Losh for (; *s1 == *s2 && *s1; s1++, s2++)
474ca987d46SWarner Losh ;
475ca987d46SWarner Losh return ((u_char)*s1 - (u_char)*s2);
476ca987d46SWarner Losh }
477ca987d46SWarner Losh
478ca987d46SWarner Losh #include "ufsread.c"
479ca987d46SWarner Losh
480ca987d46SWarner Losh int
main(int ac,char ** av)481ca987d46SWarner Losh main(int ac, char **av)
482ca987d46SWarner Losh {
483ca987d46SWarner Losh const char *path;
484ca987d46SWarner Losh char bootpath_full[255];
485ca987d46SWarner Losh int i, len;
486ca987d46SWarner Losh
487ca987d46SWarner Losh path = PATH_LOADER;
488ca987d46SWarner Losh for (i = 0; i < ac; i++) {
489ca987d46SWarner Losh switch (av[i][0]) {
490ca987d46SWarner Losh case '-':
491ca987d46SWarner Losh switch (av[i][1]) {
492ca987d46SWarner Losh default:
493ca987d46SWarner Losh usage();
494ca987d46SWarner Losh }
495ca987d46SWarner Losh break;
496ca987d46SWarner Losh default:
497ca987d46SWarner Losh path = av[i];
498ca987d46SWarner Losh break;
499ca987d46SWarner Losh }
500ca987d46SWarner Losh }
501ca987d46SWarner Losh
502ca987d46SWarner Losh printf(" \n>> FreeBSD/powerpc Open Firmware boot block\n"
503ca987d46SWarner Losh " Boot path: %s\n"
504ca987d46SWarner Losh " Boot loader: %s\n", bootpath, path);
505ca987d46SWarner Losh
506ca987d46SWarner Losh len = 0;
507ca987d46SWarner Losh while (bootpath[len] != '\0') len++;
508ca987d46SWarner Losh
509ca987d46SWarner Losh memcpy(bootpath_full,bootpath,len+1);
510ca987d46SWarner Losh
511ca987d46SWarner Losh if (bootpath_full[len-1] != ':') {
512ca987d46SWarner Losh /* First try full volume */
513ca987d46SWarner Losh if (domount(bootpath_full,1) == 0)
514ca987d46SWarner Losh goto out;
515ca987d46SWarner Losh
516ca987d46SWarner Losh /* Add a : so that we try partitions if that fails */
517ca987d46SWarner Losh if (bootdev > 0)
518ca987d46SWarner Losh ofw_close(bootdev);
519ca987d46SWarner Losh bootpath_full[len] = ':';
520ca987d46SWarner Losh len += 1;
521ca987d46SWarner Losh }
522ca987d46SWarner Losh
523ca987d46SWarner Losh /* Loop through first 16 partitions to find a UFS one */
524ca987d46SWarner Losh for (i = 0; i < 16; i++) {
525ca987d46SWarner Losh if (i < 10) {
526ca987d46SWarner Losh bootpath_full[len] = i + '0';
527ca987d46SWarner Losh bootpath_full[len+1] = '\0';
528ca987d46SWarner Losh } else {
529ca987d46SWarner Losh bootpath_full[len] = '1';
530ca987d46SWarner Losh bootpath_full[len+1] = i - 10 + '0';
531ca987d46SWarner Losh bootpath_full[len+2] = '\0';
532ca987d46SWarner Losh }
533ca987d46SWarner Losh
534ca987d46SWarner Losh if (domount(bootpath_full,1) >= 0)
535ca987d46SWarner Losh break;
536ca987d46SWarner Losh
537ca987d46SWarner Losh if (bootdev > 0)
538ca987d46SWarner Losh ofw_close(bootdev);
539ca987d46SWarner Losh }
540ca987d46SWarner Losh
541ca987d46SWarner Losh if (i >= 16)
542ca987d46SWarner Losh panic("domount");
543ca987d46SWarner Losh
544ca987d46SWarner Losh out:
545ca987d46SWarner Losh printf(" Boot volume: %s\n",bootpath_full);
546ca987d46SWarner Losh ofw_setprop(chosenh, "bootargs", bootpath_full, len+2);
547ca987d46SWarner Losh load(path);
548ca987d46SWarner Losh return (1);
549ca987d46SWarner Losh }
550ca987d46SWarner Losh
551ca987d46SWarner Losh static void
usage(void)552ca987d46SWarner Losh usage(void)
553ca987d46SWarner Losh {
554ca987d46SWarner Losh
555ca987d46SWarner Losh printf("usage: boot device [/path/to/loader]\n");
556ca987d46SWarner Losh exit(1);
557ca987d46SWarner Losh }
558ca987d46SWarner Losh
559ca987d46SWarner Losh static void
exit(int code)560ca987d46SWarner Losh exit(int code)
561ca987d46SWarner Losh {
562ca987d46SWarner Losh
563ca987d46SWarner Losh ofw_exit();
564ca987d46SWarner Losh }
565ca987d46SWarner Losh
566ca987d46SWarner Losh static struct dmadat __dmadat;
567ca987d46SWarner Losh
568ca987d46SWarner Losh static int
domount(const char * device,int quiet)569ca987d46SWarner Losh domount(const char *device, int quiet)
570ca987d46SWarner Losh {
571ca987d46SWarner Losh
572ca987d46SWarner Losh dmadat = &__dmadat;
573ca987d46SWarner Losh if ((bootdev = ofw_open(device)) == -1) {
574ca987d46SWarner Losh printf("domount: can't open device\n");
575ca987d46SWarner Losh return (-1);
576ca987d46SWarner Losh }
577ca987d46SWarner Losh if (fsread(0, NULL, 0)) {
578ca987d46SWarner Losh if (!quiet)
579ca987d46SWarner Losh printf("domount: can't read superblock\n");
580ca987d46SWarner Losh return (-1);
581ca987d46SWarner Losh }
582ca987d46SWarner Losh return (0);
583ca987d46SWarner Losh }
584ca987d46SWarner Losh
585ca987d46SWarner Losh static void
load(const char * fname)586ca987d46SWarner Losh load(const char *fname)
587ca987d46SWarner Losh {
588ca987d46SWarner Losh Elf32_Ehdr eh;
589ca987d46SWarner Losh Elf32_Phdr ph;
590ca987d46SWarner Losh caddr_t p;
591ca987d46SWarner Losh ufs_ino_t ino;
592ca987d46SWarner Losh int i;
593ca987d46SWarner Losh
594ca987d46SWarner Losh if ((ino = lookup(fname)) == 0) {
595ca987d46SWarner Losh printf("File %s not found\n", fname);
596ca987d46SWarner Losh return;
597ca987d46SWarner Losh }
598ca987d46SWarner Losh if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
599ca987d46SWarner Losh printf("Can't read elf header\n");
600ca987d46SWarner Losh return;
601ca987d46SWarner Losh }
602ca987d46SWarner Losh if (!IS_ELF(eh)) {
603ca987d46SWarner Losh printf("Not an ELF file\n");
604ca987d46SWarner Losh return;
605ca987d46SWarner Losh }
606ca987d46SWarner Losh for (i = 0; i < eh.e_phnum; i++) {
607ca987d46SWarner Losh fs_off = eh.e_phoff + i * eh.e_phentsize;
608ca987d46SWarner Losh if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
609ca987d46SWarner Losh printf("Can't read program header %d\n", i);
610ca987d46SWarner Losh return;
611ca987d46SWarner Losh }
612ca987d46SWarner Losh if (ph.p_type != PT_LOAD)
613ca987d46SWarner Losh continue;
614ca987d46SWarner Losh fs_off = ph.p_offset;
615ca987d46SWarner Losh p = (caddr_t)ph.p_vaddr;
616ca987d46SWarner Losh ofw_claim(p,(ph.p_filesz > ph.p_memsz) ?
617ca987d46SWarner Losh ph.p_filesz : ph.p_memsz,0);
618ca987d46SWarner Losh if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
619ca987d46SWarner Losh printf("Can't read content of section %d\n", i);
620ca987d46SWarner Losh return;
621ca987d46SWarner Losh }
622ca987d46SWarner Losh if (ph.p_filesz != ph.p_memsz)
623ca987d46SWarner Losh bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
624ca987d46SWarner Losh __syncicache(p, ph.p_memsz);
625ca987d46SWarner Losh }
626ca987d46SWarner Losh ofw_close(bootdev);
627ca987d46SWarner Losh (*(void (*)(void *, int, ofwfp_t, char *, int))eh.e_entry)(NULL, 0,
628f8328864SLeandro Lupori realofw, NULL, 0);
629ca987d46SWarner Losh }
630ca987d46SWarner Losh
631ca987d46SWarner Losh static int
dskread(void * buf,uint64_t lba,int nblk)63256e53cb8SWarner Losh dskread(void *buf, uint64_t lba, int nblk)
633ca987d46SWarner Losh {
634ca987d46SWarner Losh /*
635ca987d46SWarner Losh * The Open Firmware should open the correct partition for us.
636ca987d46SWarner Losh * That means, if we read from offset zero on an open instance handle,
637ca987d46SWarner Losh * we should read from offset zero of that partition.
638ca987d46SWarner Losh */
639ca987d46SWarner Losh ofw_seek(bootdev, lba * DEV_BSIZE);
640ca987d46SWarner Losh ofw_read(bootdev, buf, nblk * DEV_BSIZE);
641ca987d46SWarner Losh return (0);
642ca987d46SWarner Losh }
643ca987d46SWarner Losh
644ca987d46SWarner Losh static void
panic(const char * fmt,...)645ca987d46SWarner Losh panic(const char *fmt, ...)
646ca987d46SWarner Losh {
647ca987d46SWarner Losh char buf[128];
648ca987d46SWarner Losh va_list ap;
649ca987d46SWarner Losh
650ca987d46SWarner Losh va_start(ap, fmt);
651ca987d46SWarner Losh vsnprintf(buf, sizeof buf, fmt, ap);
652ca987d46SWarner Losh printf("panic: %s\n", buf);
653ca987d46SWarner Losh va_end(ap);
654ca987d46SWarner Losh
655ca987d46SWarner Losh exit(1);
656ca987d46SWarner Losh }
657ca987d46SWarner Losh
658ca987d46SWarner Losh static int
printf(const char * fmt,...)659ca987d46SWarner Losh printf(const char *fmt, ...)
660ca987d46SWarner Losh {
661ca987d46SWarner Losh va_list ap;
662ca987d46SWarner Losh int ret;
663ca987d46SWarner Losh
664ca987d46SWarner Losh va_start(ap, fmt);
665ca987d46SWarner Losh ret = vprintf(fmt, ap);
666ca987d46SWarner Losh va_end(ap);
667ca987d46SWarner Losh return (ret);
668ca987d46SWarner Losh }
669ca987d46SWarner Losh
670ca987d46SWarner Losh static int
putchar(char c,void * arg)671ca987d46SWarner Losh putchar(char c, void *arg)
672ca987d46SWarner Losh {
673ca987d46SWarner Losh char buf;
674ca987d46SWarner Losh
675ca987d46SWarner Losh if (c == '\n') {
676ca987d46SWarner Losh buf = '\r';
677ca987d46SWarner Losh ofw_write(stdouth, &buf, 1);
678ca987d46SWarner Losh }
679ca987d46SWarner Losh buf = c;
680ca987d46SWarner Losh ofw_write(stdouth, &buf, 1);
681ca987d46SWarner Losh return (1);
682ca987d46SWarner Losh }
683ca987d46SWarner Losh
684ca987d46SWarner Losh static int
vprintf(const char * fmt,va_list ap)685ca987d46SWarner Losh vprintf(const char *fmt, va_list ap)
686ca987d46SWarner Losh {
687ca987d46SWarner Losh int ret;
688ca987d46SWarner Losh
689ca987d46SWarner Losh ret = __printf(fmt, putchar, 0, ap);
690ca987d46SWarner Losh return (ret);
691ca987d46SWarner Losh }
692ca987d46SWarner Losh
693ca987d46SWarner Losh static int
vsnprintf(char * str,size_t sz,const char * fmt,va_list ap)694ca987d46SWarner Losh vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
695ca987d46SWarner Losh {
696ca987d46SWarner Losh struct sp_data sp;
697ca987d46SWarner Losh int ret;
698ca987d46SWarner Losh
699ca987d46SWarner Losh sp.sp_buf = str;
700ca987d46SWarner Losh sp.sp_len = 0;
701ca987d46SWarner Losh sp.sp_size = sz;
702ca987d46SWarner Losh ret = __printf(fmt, __sputc, &sp, ap);
703ca987d46SWarner Losh return (ret);
704ca987d46SWarner Losh }
705ca987d46SWarner Losh
706ca987d46SWarner Losh static int
__printf(const char * fmt,putc_func_t * putc,void * arg,va_list ap)707ca987d46SWarner Losh __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
708ca987d46SWarner Losh {
709ca987d46SWarner Losh char buf[(sizeof(long) * 8) + 1];
710ca987d46SWarner Losh char *nbuf;
711ca987d46SWarner Losh u_long ul;
712ca987d46SWarner Losh u_int ui;
713ca987d46SWarner Losh int lflag;
714ca987d46SWarner Losh int sflag;
715ca987d46SWarner Losh char *s;
716ca987d46SWarner Losh int pad;
717ca987d46SWarner Losh int ret;
718ca987d46SWarner Losh int c;
719ca987d46SWarner Losh
720ca987d46SWarner Losh nbuf = &buf[sizeof buf - 1];
721ca987d46SWarner Losh ret = 0;
722ca987d46SWarner Losh while ((c = *fmt++) != 0) {
723ca987d46SWarner Losh if (c != '%') {
724ca987d46SWarner Losh ret += putc(c, arg);
725ca987d46SWarner Losh continue;
726ca987d46SWarner Losh }
727ca987d46SWarner Losh lflag = 0;
728ca987d46SWarner Losh sflag = 0;
729ca987d46SWarner Losh pad = 0;
730ca987d46SWarner Losh reswitch: c = *fmt++;
731ca987d46SWarner Losh switch (c) {
732ca987d46SWarner Losh case '#':
733ca987d46SWarner Losh sflag = 1;
734ca987d46SWarner Losh goto reswitch;
735ca987d46SWarner Losh case '%':
736ca987d46SWarner Losh ret += putc('%', arg);
737ca987d46SWarner Losh break;
738ca987d46SWarner Losh case 'c':
739ca987d46SWarner Losh c = va_arg(ap, int);
740ca987d46SWarner Losh ret += putc(c, arg);
741ca987d46SWarner Losh break;
742ca987d46SWarner Losh case 'd':
743ca987d46SWarner Losh if (lflag == 0) {
744ca987d46SWarner Losh ui = (u_int)va_arg(ap, int);
745ca987d46SWarner Losh if (ui < (int)ui) {
746ca987d46SWarner Losh ui = -ui;
747ca987d46SWarner Losh ret += putc('-', arg);
748ca987d46SWarner Losh }
749ca987d46SWarner Losh s = __uitoa(nbuf, ui, 10);
750ca987d46SWarner Losh } else {
751ca987d46SWarner Losh ul = (u_long)va_arg(ap, long);
752ca987d46SWarner Losh if (ul < (long)ul) {
753ca987d46SWarner Losh ul = -ul;
754ca987d46SWarner Losh ret += putc('-', arg);
755ca987d46SWarner Losh }
756ca987d46SWarner Losh s = __ultoa(nbuf, ul, 10);
757ca987d46SWarner Losh }
758ca987d46SWarner Losh ret += __puts(s, putc, arg);
759ca987d46SWarner Losh break;
760ca987d46SWarner Losh case 'l':
761ca987d46SWarner Losh lflag = 1;
762ca987d46SWarner Losh goto reswitch;
763ca987d46SWarner Losh case 'o':
764ca987d46SWarner Losh if (lflag == 0) {
765ca987d46SWarner Losh ui = (u_int)va_arg(ap, u_int);
766ca987d46SWarner Losh s = __uitoa(nbuf, ui, 8);
767ca987d46SWarner Losh } else {
768ca987d46SWarner Losh ul = (u_long)va_arg(ap, u_long);
769ca987d46SWarner Losh s = __ultoa(nbuf, ul, 8);
770ca987d46SWarner Losh }
771ca987d46SWarner Losh ret += __puts(s, putc, arg);
772ca987d46SWarner Losh break;
773ca987d46SWarner Losh case 'p':
774ca987d46SWarner Losh ul = (u_long)va_arg(ap, void *);
775ca987d46SWarner Losh s = __ultoa(nbuf, ul, 16);
776ca987d46SWarner Losh ret += __puts("0x", putc, arg);
777ca987d46SWarner Losh ret += __puts(s, putc, arg);
778ca987d46SWarner Losh break;
779ca987d46SWarner Losh case 's':
780ca987d46SWarner Losh s = va_arg(ap, char *);
781ca987d46SWarner Losh ret += __puts(s, putc, arg);
782ca987d46SWarner Losh break;
783ca987d46SWarner Losh case 'u':
784ca987d46SWarner Losh if (lflag == 0) {
785ca987d46SWarner Losh ui = va_arg(ap, u_int);
786ca987d46SWarner Losh s = __uitoa(nbuf, ui, 10);
787ca987d46SWarner Losh } else {
788ca987d46SWarner Losh ul = va_arg(ap, u_long);
789ca987d46SWarner Losh s = __ultoa(nbuf, ul, 10);
790ca987d46SWarner Losh }
791ca987d46SWarner Losh ret += __puts(s, putc, arg);
792ca987d46SWarner Losh break;
793ca987d46SWarner Losh case 'x':
794ca987d46SWarner Losh if (lflag == 0) {
795ca987d46SWarner Losh ui = va_arg(ap, u_int);
796ca987d46SWarner Losh s = __uitoa(nbuf, ui, 16);
797ca987d46SWarner Losh } else {
798ca987d46SWarner Losh ul = va_arg(ap, u_long);
799ca987d46SWarner Losh s = __ultoa(nbuf, ul, 16);
800ca987d46SWarner Losh }
801ca987d46SWarner Losh if (sflag)
802ca987d46SWarner Losh ret += __puts("0x", putc, arg);
803ca987d46SWarner Losh ret += __puts(s, putc, arg);
804ca987d46SWarner Losh break;
805ca987d46SWarner Losh case '0': case '1': case '2': case '3': case '4':
806ca987d46SWarner Losh case '5': case '6': case '7': case '8': case '9':
807ca987d46SWarner Losh pad = pad * 10 + c - '0';
808ca987d46SWarner Losh goto reswitch;
809ca987d46SWarner Losh default:
810ca987d46SWarner Losh break;
811ca987d46SWarner Losh }
812ca987d46SWarner Losh }
813ca987d46SWarner Losh return (ret);
814ca987d46SWarner Losh }
815ca987d46SWarner Losh
816ca987d46SWarner Losh static int
__sputc(char c,void * arg)817ca987d46SWarner Losh __sputc(char c, void *arg)
818ca987d46SWarner Losh {
819ca987d46SWarner Losh struct sp_data *sp;
820ca987d46SWarner Losh
821ca987d46SWarner Losh sp = arg;
822ca987d46SWarner Losh if (sp->sp_len < sp->sp_size)
823ca987d46SWarner Losh sp->sp_buf[sp->sp_len++] = c;
824ca987d46SWarner Losh sp->sp_buf[sp->sp_len] = '\0';
825ca987d46SWarner Losh return (1);
826ca987d46SWarner Losh }
827ca987d46SWarner Losh
828ca987d46SWarner Losh static int
__puts(const char * s,putc_func_t * putc,void * arg)829ca987d46SWarner Losh __puts(const char *s, putc_func_t *putc, void *arg)
830ca987d46SWarner Losh {
831ca987d46SWarner Losh const char *p;
832ca987d46SWarner Losh int ret;
833ca987d46SWarner Losh
834ca987d46SWarner Losh ret = 0;
835ca987d46SWarner Losh for (p = s; *p != '\0'; p++)
836ca987d46SWarner Losh ret += putc(*p, arg);
837ca987d46SWarner Losh return (ret);
838ca987d46SWarner Losh }
839ca987d46SWarner Losh
840ca987d46SWarner Losh static char *
__uitoa(char * buf,u_int ui,int base)841ca987d46SWarner Losh __uitoa(char *buf, u_int ui, int base)
842ca987d46SWarner Losh {
843ca987d46SWarner Losh char *p;
844ca987d46SWarner Losh
845ca987d46SWarner Losh p = buf;
846ca987d46SWarner Losh *p = '\0';
847ca987d46SWarner Losh do
848ca987d46SWarner Losh *--p = digits[ui % base];
849ca987d46SWarner Losh while ((ui /= base) != 0);
850ca987d46SWarner Losh return (p);
851ca987d46SWarner Losh }
852ca987d46SWarner Losh
853ca987d46SWarner Losh static char *
__ultoa(char * buf,u_long ul,int base)854ca987d46SWarner Losh __ultoa(char *buf, u_long ul, int base)
855ca987d46SWarner Losh {
856ca987d46SWarner Losh char *p;
857ca987d46SWarner Losh
858ca987d46SWarner Losh p = buf;
859ca987d46SWarner Losh *p = '\0';
860ca987d46SWarner Losh do
861ca987d46SWarner Losh *--p = digits[ul % base];
862ca987d46SWarner Losh while ((ul /= base) != 0);
863ca987d46SWarner Losh return (p);
864ca987d46SWarner Losh }
865