1276331Snwhitehorn/*-
2276331Snwhitehorn * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3276331Snwhitehorn * All rights reserved.
4276331Snwhitehorn *
5276331Snwhitehorn * Redistribution and use in source and binary forms, with or without
6276331Snwhitehorn * modification, are permitted provided that the following conditions
7276331Snwhitehorn * are met:
8276331Snwhitehorn * 1. Redistributions of source code must retain the above copyright
9276331Snwhitehorn *    notice, this list of conditions and the following disclaimer.
10276331Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
11276331Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
12276331Snwhitehorn *    documentation and/or other materials provided with the distribution.
13276331Snwhitehorn *
14276331Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15276331Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16276331Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17276331Snwhitehorn * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18276331Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19276331Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20276331Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21276331Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22276331Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23276331Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24276331Snwhitehorn * SUCH DAMAGE.
25276331Snwhitehorn *
26276331Snwhitehorn *	from: FreeBSD: src/sys/boot/sparc64/loader/metadata.c,v 1.6
27276331Snwhitehorn */
28276331Snwhitehorn
29276331Snwhitehorn#include <sys/cdefs.h>
30276331Snwhitehorn__FBSDID("$FreeBSD: releng/11.0/sys/boot/powerpc/kboot/metadata.c 276507 2015-01-01 18:12:02Z nwhitehorn $");
31276331Snwhitehorn
32276331Snwhitehorn#include <stand.h>
33276331Snwhitehorn#include <sys/param.h>
34276331Snwhitehorn#include <sys/reboot.h>
35276331Snwhitehorn#include <sys/linker.h>
36276331Snwhitehorn#include <sys/boot.h>
37276507Snwhitehorn#include <fdt_platform.h>
38276331Snwhitehorn
39276331Snwhitehorn#include <machine/metadata.h>
40276331Snwhitehorn
41276331Snwhitehorn#include "bootstrap.h"
42276331Snwhitehorn
43276331Snwhitehornint
44276331Snwhitehornmd_getboothowto(char *kargs)
45276331Snwhitehorn{
46276331Snwhitehorn    char	*cp;
47276331Snwhitehorn    int		howto;
48276331Snwhitehorn    int		active;
49276331Snwhitehorn    int		i;
50276331Snwhitehorn
51276331Snwhitehorn    /* Parse kargs */
52276331Snwhitehorn    howto = 0;
53276331Snwhitehorn    if (kargs != NULL) {
54276331Snwhitehorn	cp = kargs;
55276331Snwhitehorn	active = 0;
56276331Snwhitehorn	while (*cp != 0) {
57276331Snwhitehorn	    if (!active && (*cp == '-')) {
58276331Snwhitehorn		active = 1;
59276331Snwhitehorn	    } else if (active)
60276331Snwhitehorn		switch (*cp) {
61276331Snwhitehorn		case 'a':
62276331Snwhitehorn		    howto |= RB_ASKNAME;
63276331Snwhitehorn		    break;
64276331Snwhitehorn		case 'C':
65276331Snwhitehorn		    howto |= RB_CDROM;
66276331Snwhitehorn		    break;
67276331Snwhitehorn		case 'd':
68276331Snwhitehorn		    howto |= RB_KDB;
69276331Snwhitehorn		    break;
70276331Snwhitehorn		case 'D':
71276331Snwhitehorn		    howto |= RB_MULTIPLE;
72276331Snwhitehorn		    break;
73276331Snwhitehorn		case 'm':
74276331Snwhitehorn		    howto |= RB_MUTE;
75276331Snwhitehorn		    break;
76276331Snwhitehorn		case 'g':
77276331Snwhitehorn		    howto |= RB_GDB;
78276331Snwhitehorn		    break;
79276331Snwhitehorn		case 'h':
80276331Snwhitehorn		    howto |= RB_SERIAL;
81276331Snwhitehorn		    break;
82276331Snwhitehorn		case 'p':
83276331Snwhitehorn		    howto |= RB_PAUSE;
84276331Snwhitehorn		    break;
85276331Snwhitehorn		case 'r':
86276331Snwhitehorn		    howto |= RB_DFLTROOT;
87276331Snwhitehorn		    break;
88276331Snwhitehorn		case 's':
89276331Snwhitehorn		    howto |= RB_SINGLE;
90276331Snwhitehorn		    break;
91276331Snwhitehorn		case 'v':
92276331Snwhitehorn		    howto |= RB_VERBOSE;
93276331Snwhitehorn		    break;
94276331Snwhitehorn		default:
95276331Snwhitehorn		    active = 0;
96276331Snwhitehorn		    break;
97276331Snwhitehorn		}
98276331Snwhitehorn	    cp++;
99276331Snwhitehorn	}
100276331Snwhitehorn    }
101276331Snwhitehorn    /* get equivalents from the environment */
102276331Snwhitehorn    for (i = 0; howto_names[i].ev != NULL; i++)
103276331Snwhitehorn	if (getenv(howto_names[i].ev) != NULL)
104276331Snwhitehorn	    howto |= howto_names[i].mask;
105276331Snwhitehorn    if (!strcmp(getenv("console"), "comconsole"))
106276331Snwhitehorn	howto |= RB_SERIAL;
107276331Snwhitehorn    if (!strcmp(getenv("console"), "nullconsole"))
108276331Snwhitehorn	howto |= RB_MUTE;
109276331Snwhitehorn    return(howto);
110276331Snwhitehorn}
111276331Snwhitehorn
112276331Snwhitehorn/*
113276331Snwhitehorn * Copy the environment into the load area starting at (addr).
114276331Snwhitehorn * Each variable is formatted as <name>=<value>, with a single nul
115276331Snwhitehorn * separating each variable, and a double nul terminating the environment.
116276331Snwhitehorn */
117276331Snwhitehornvm_offset_t
118276331Snwhitehornmd_copyenv(vm_offset_t addr)
119276331Snwhitehorn{
120276331Snwhitehorn    struct env_var	*ep;
121276331Snwhitehorn
122276331Snwhitehorn    /* traverse the environment */
123276331Snwhitehorn    for (ep = environ; ep != NULL; ep = ep->ev_next) {
124276331Snwhitehorn	archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name));
125276331Snwhitehorn	addr += strlen(ep->ev_name);
126276331Snwhitehorn	archsw.arch_copyin("=", addr, 1);
127276331Snwhitehorn	addr++;
128276331Snwhitehorn	if (ep->ev_value != NULL) {
129276331Snwhitehorn	    archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value));
130276331Snwhitehorn	    addr += strlen(ep->ev_value);
131276331Snwhitehorn	}
132276331Snwhitehorn	archsw.arch_copyin("", addr, 1);
133276331Snwhitehorn	addr++;
134276331Snwhitehorn    }
135276331Snwhitehorn    archsw.arch_copyin("", addr, 1);
136276331Snwhitehorn    addr++;
137276331Snwhitehorn    return(addr);
138276331Snwhitehorn}
139276331Snwhitehorn
140276331Snwhitehorn/*
141276331Snwhitehorn * Copy module-related data into the load area, where it can be
142276331Snwhitehorn * used as a directory for loaded modules.
143276331Snwhitehorn *
144276331Snwhitehorn * Module data is presented in a self-describing format.  Each datum
145276331Snwhitehorn * is preceded by a 32-bit identifier and a 32-bit size field.
146276331Snwhitehorn *
147276331Snwhitehorn * Currently, the following data are saved:
148276331Snwhitehorn *
149276331Snwhitehorn * MOD_NAME	(variable)		module name (string)
150276331Snwhitehorn * MOD_TYPE	(variable)		module type (string)
151276331Snwhitehorn * MOD_ARGS	(variable)		module parameters (string)
152276331Snwhitehorn * MOD_ADDR	sizeof(vm_offset_t)	module load address
153276331Snwhitehorn * MOD_SIZE	sizeof(size_t)		module size
154276331Snwhitehorn * MOD_METADATA	(variable)		type-specific metadata
155276331Snwhitehorn */
156276331Snwhitehorn
157276331Snwhitehornstatic int align;
158276331Snwhitehorn
159276331Snwhitehorn#define COPY32(v, a, c) {			\
160276331Snwhitehorn    u_int32_t	x = (v);			\
161276331Snwhitehorn    if (c)					\
162276331Snwhitehorn        archsw.arch_copyin(&x, a, sizeof(x));	\
163276331Snwhitehorn    a += sizeof(x);				\
164276331Snwhitehorn}
165276331Snwhitehorn
166276331Snwhitehorn#define MOD_STR(t, a, s, c) {			\
167276331Snwhitehorn    COPY32(t, a, c);				\
168276331Snwhitehorn    COPY32(strlen(s) + 1, a, c)			\
169276331Snwhitehorn    if (c)					\
170276331Snwhitehorn        archsw.arch_copyin(s, a, strlen(s) + 1);\
171276331Snwhitehorn    a += roundup(strlen(s) + 1, align);		\
172276331Snwhitehorn}
173276331Snwhitehorn
174276331Snwhitehorn#define MOD_NAME(a, s, c)	MOD_STR(MODINFO_NAME, a, s, c)
175276331Snwhitehorn#define MOD_TYPE(a, s, c)	MOD_STR(MODINFO_TYPE, a, s, c)
176276331Snwhitehorn#define MOD_ARGS(a, s, c)	MOD_STR(MODINFO_ARGS, a, s, c)
177276331Snwhitehorn
178276331Snwhitehorn#define MOD_VAR(t, a, s, c) {			\
179276331Snwhitehorn    COPY32(t, a, c);				\
180276331Snwhitehorn    COPY32(sizeof(s), a, c);			\
181276331Snwhitehorn    if (c)					\
182276331Snwhitehorn        archsw.arch_copyin(&s, a, sizeof(s));	\
183276331Snwhitehorn    a += roundup(sizeof(s), align);		\
184276331Snwhitehorn}
185276331Snwhitehorn
186276331Snwhitehorn#define MOD_ADDR(a, s, c)	MOD_VAR(MODINFO_ADDR, a, s, c)
187276331Snwhitehorn#define MOD_SIZE(a, s, c)	MOD_VAR(MODINFO_SIZE, a, s, c)
188276331Snwhitehorn
189276331Snwhitehorn#define MOD_METADATA(a, mm, c) {		\
190276331Snwhitehorn    COPY32(MODINFO_METADATA | mm->md_type, a, c);\
191276331Snwhitehorn    COPY32(mm->md_size, a, c);			\
192276331Snwhitehorn    if (c)					\
193276331Snwhitehorn        archsw.arch_copyin(mm->md_data, a, mm->md_size);\
194276331Snwhitehorn    a += roundup(mm->md_size, align);		\
195276331Snwhitehorn}
196276331Snwhitehorn
197276331Snwhitehorn#define MOD_END(a, c) {				\
198276331Snwhitehorn    COPY32(MODINFO_END, a, c);			\
199276331Snwhitehorn    COPY32(0, a, c);				\
200276331Snwhitehorn}
201276331Snwhitehorn
202276331Snwhitehornvm_offset_t
203276331Snwhitehornmd_copymodules(vm_offset_t addr, int kern64)
204276331Snwhitehorn{
205276331Snwhitehorn    struct preloaded_file	*fp;
206276331Snwhitehorn    struct file_metadata	*md;
207276331Snwhitehorn    uint64_t			scratch64;
208276331Snwhitehorn    int				c;
209276331Snwhitehorn
210276331Snwhitehorn    c = addr != 0;
211276331Snwhitehorn    /* start with the first module on the list, should be the kernel */
212276331Snwhitehorn    for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
213276331Snwhitehorn
214276331Snwhitehorn	MOD_NAME(addr, fp->f_name, c);	/* this field must come first */
215276331Snwhitehorn	MOD_TYPE(addr, fp->f_type, c);
216276331Snwhitehorn	if (fp->f_args)
217276331Snwhitehorn	    MOD_ARGS(addr, fp->f_args, c);
218276331Snwhitehorn	if (kern64) {
219276331Snwhitehorn		scratch64 = fp->f_addr;
220276331Snwhitehorn		MOD_ADDR(addr, scratch64, c);
221276331Snwhitehorn		scratch64 = fp->f_size;
222276331Snwhitehorn		MOD_SIZE(addr, scratch64, c);
223276331Snwhitehorn	} else {
224276331Snwhitehorn		MOD_ADDR(addr, fp->f_addr, c);
225276331Snwhitehorn		MOD_SIZE(addr, fp->f_size, c);
226276331Snwhitehorn	}
227276331Snwhitehorn	for (md = fp->f_metadata; md != NULL; md = md->md_next) {
228276331Snwhitehorn	    if (!(md->md_type & MODINFOMD_NOCOPY)) {
229276331Snwhitehorn		MOD_METADATA(addr, md, c);
230276331Snwhitehorn	    }
231276331Snwhitehorn	}
232276331Snwhitehorn    }
233276331Snwhitehorn    MOD_END(addr, c);
234276331Snwhitehorn    return(addr);
235276331Snwhitehorn}
236276331Snwhitehorn
237276331Snwhitehorn/*
238276331Snwhitehorn * Load the information expected by a powerpc kernel.
239276331Snwhitehorn *
240276331Snwhitehorn * - The 'boothowto' argument is constructed
241276331Snwhitehorn * - The 'bootdev' argument is constructed
242276331Snwhitehorn * - The kernel environment is copied into kernel space.
243276331Snwhitehorn * - Module metadata are formatted and placed in kernel space.
244276331Snwhitehorn */
245276331Snwhitehornint
246276506Snwhitehornmd_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64)
247276331Snwhitehorn{
248276331Snwhitehorn    struct preloaded_file	*kfp;
249276331Snwhitehorn    struct preloaded_file	*xp;
250276331Snwhitehorn    struct file_metadata	*md;
251276331Snwhitehorn    vm_offset_t			kernend;
252276331Snwhitehorn    vm_offset_t			addr;
253276331Snwhitehorn    vm_offset_t			envp;
254276506Snwhitehorn    vm_offset_t			fdtp;
255276331Snwhitehorn    vm_offset_t			size;
256276331Snwhitehorn    uint64_t			scratch64;
257276331Snwhitehorn    char			*rootdevname;
258276331Snwhitehorn    int				howto;
259276331Snwhitehorn
260276331Snwhitehorn    align = kern64 ? 8 : 4;
261276331Snwhitehorn    howto = md_getboothowto(args);
262276331Snwhitehorn
263276331Snwhitehorn    /*
264276331Snwhitehorn     * Allow the environment variable 'rootdev' to override the supplied device
265276331Snwhitehorn     * This should perhaps go to MI code and/or have $rootdev tested/set by
266276331Snwhitehorn     * MI code before launching the kernel.
267276331Snwhitehorn     */
268276331Snwhitehorn    rootdevname = getenv("rootdev");
269276331Snwhitehorn    if (rootdevname == NULL)
270276331Snwhitehorn	    rootdevname = getenv("currdev");
271276331Snwhitehorn    /* Try reading the /etc/fstab file to select the root device */
272276331Snwhitehorn    getrootmount(rootdevname);
273276331Snwhitehorn
274276331Snwhitehorn    /* find the last module in the chain */
275276331Snwhitehorn    addr = 0;
276276331Snwhitehorn    for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
277276331Snwhitehorn	if (addr < (xp->f_addr + xp->f_size))
278276331Snwhitehorn	    addr = xp->f_addr + xp->f_size;
279276331Snwhitehorn    }
280276331Snwhitehorn    /* pad to a page boundary */
281276331Snwhitehorn    addr = roundup(addr, PAGE_SIZE);
282276331Snwhitehorn
283276331Snwhitehorn    /* copy our environment */
284276331Snwhitehorn    envp = addr;
285276331Snwhitehorn    addr = md_copyenv(addr);
286276331Snwhitehorn
287276331Snwhitehorn    /* pad to a page boundary */
288276331Snwhitehorn    addr = roundup(addr, PAGE_SIZE);
289276331Snwhitehorn
290276506Snwhitehorn    /* Copy out FDT */
291276506Snwhitehorn    size = fdt_copy(addr);
292276506Snwhitehorn    *dtb = fdtp = addr;
293276506Snwhitehorn    addr = roundup(addr + size, PAGE_SIZE);
294276506Snwhitehorn
295276331Snwhitehorn    kernend = 0;
296276331Snwhitehorn    kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel");
297276331Snwhitehorn    if (kfp == NULL)
298276331Snwhitehorn	kfp = file_findfile(NULL, "elf kernel");
299276331Snwhitehorn    if (kfp == NULL)
300276331Snwhitehorn	panic("can't find kernel file");
301276331Snwhitehorn    file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
302276331Snwhitehorn    if (kern64) {
303276331Snwhitehorn	scratch64 = envp;
304276331Snwhitehorn	file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64);
305276506Snwhitehorn	scratch64 = fdtp;
306276506Snwhitehorn	file_addmetadata(kfp, MODINFOMD_DTBP, sizeof scratch64, &scratch64);
307276331Snwhitehorn	scratch64 = kernend;
308276331Snwhitehorn	file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof scratch64, &scratch64);
309276331Snwhitehorn    } else {
310276331Snwhitehorn	file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
311276506Snwhitehorn	file_addmetadata(kfp, MODINFOMD_DTBP, sizeof fdtp, &fdtp);
312276331Snwhitehorn	file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
313276331Snwhitehorn    }
314276331Snwhitehorn
315276331Snwhitehorn    *modulep = addr;
316276331Snwhitehorn    size = md_copymodules(0, kern64);
317276331Snwhitehorn    kernend = roundup(addr + size, PAGE_SIZE);
318276331Snwhitehorn
319276331Snwhitehorn    md = file_findmetadata(kfp, MODINFOMD_KERNEND);
320276331Snwhitehorn    if (kern64) {
321276331Snwhitehorn	scratch64 = kernend;
322276331Snwhitehorn	bcopy(&scratch64, md->md_data, sizeof scratch64);
323276331Snwhitehorn    } else {
324276331Snwhitehorn	bcopy(&kernend, md->md_data, sizeof kernend);
325276331Snwhitehorn    }
326276331Snwhitehorn
327276331Snwhitehorn    (void)md_copymodules(addr, kern64);
328276331Snwhitehorn
329276331Snwhitehorn    return(0);
330276331Snwhitehorn}
331276331Snwhitehorn
332276331Snwhitehornint
333276506Snwhitehornmd_load(char *args, vm_offset_t *modulep, vm_offset_t *dtb)
334276331Snwhitehorn{
335276506Snwhitehorn    return (md_load_dual(args, modulep, dtb, 0));
336276331Snwhitehorn}
337276331Snwhitehorn
338276331Snwhitehornint
339276506Snwhitehornmd_load64(char *args, vm_offset_t *modulep, vm_offset_t *dtb)
340276331Snwhitehorn{
341276506Snwhitehorn    return (md_load_dual(args, modulep, dtb, 1));
342276331Snwhitehorn}
343276331Snwhitehorn
344