metadata.c revision 276506
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: user/nwhitehorn/kboot/powerpc/kboot/metadata.c 276506 2015-01-01 18:07:56Z 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>
37276331Snwhitehorn
38276331Snwhitehorn#include <machine/metadata.h>
39276331Snwhitehorn
40276331Snwhitehorn#include "bootstrap.h"
41276331Snwhitehorn
42276331Snwhitehornint
43276331Snwhitehornmd_getboothowto(char *kargs)
44276331Snwhitehorn{
45276331Snwhitehorn    char	*cp;
46276331Snwhitehorn    int		howto;
47276331Snwhitehorn    int		active;
48276331Snwhitehorn    int		i;
49276331Snwhitehorn
50276331Snwhitehorn    /* Parse kargs */
51276331Snwhitehorn    howto = 0;
52276331Snwhitehorn    if (kargs != NULL) {
53276331Snwhitehorn	cp = kargs;
54276331Snwhitehorn	active = 0;
55276331Snwhitehorn	while (*cp != 0) {
56276331Snwhitehorn	    if (!active && (*cp == '-')) {
57276331Snwhitehorn		active = 1;
58276331Snwhitehorn	    } else if (active)
59276331Snwhitehorn		switch (*cp) {
60276331Snwhitehorn		case 'a':
61276331Snwhitehorn		    howto |= RB_ASKNAME;
62276331Snwhitehorn		    break;
63276331Snwhitehorn		case 'C':
64276331Snwhitehorn		    howto |= RB_CDROM;
65276331Snwhitehorn		    break;
66276331Snwhitehorn		case 'd':
67276331Snwhitehorn		    howto |= RB_KDB;
68276331Snwhitehorn		    break;
69276331Snwhitehorn		case 'D':
70276331Snwhitehorn		    howto |= RB_MULTIPLE;
71276331Snwhitehorn		    break;
72276331Snwhitehorn		case 'm':
73276331Snwhitehorn		    howto |= RB_MUTE;
74276331Snwhitehorn		    break;
75276331Snwhitehorn		case 'g':
76276331Snwhitehorn		    howto |= RB_GDB;
77276331Snwhitehorn		    break;
78276331Snwhitehorn		case 'h':
79276331Snwhitehorn		    howto |= RB_SERIAL;
80276331Snwhitehorn		    break;
81276331Snwhitehorn		case 'p':
82276331Snwhitehorn		    howto |= RB_PAUSE;
83276331Snwhitehorn		    break;
84276331Snwhitehorn		case 'r':
85276331Snwhitehorn		    howto |= RB_DFLTROOT;
86276331Snwhitehorn		    break;
87276331Snwhitehorn		case 's':
88276331Snwhitehorn		    howto |= RB_SINGLE;
89276331Snwhitehorn		    break;
90276331Snwhitehorn		case 'v':
91276331Snwhitehorn		    howto |= RB_VERBOSE;
92276331Snwhitehorn		    break;
93276331Snwhitehorn		default:
94276331Snwhitehorn		    active = 0;
95276331Snwhitehorn		    break;
96276331Snwhitehorn		}
97276331Snwhitehorn	    cp++;
98276331Snwhitehorn	}
99276331Snwhitehorn    }
100276331Snwhitehorn    /* get equivalents from the environment */
101276331Snwhitehorn    for (i = 0; howto_names[i].ev != NULL; i++)
102276331Snwhitehorn	if (getenv(howto_names[i].ev) != NULL)
103276331Snwhitehorn	    howto |= howto_names[i].mask;
104276331Snwhitehorn    if (!strcmp(getenv("console"), "comconsole"))
105276331Snwhitehorn	howto |= RB_SERIAL;
106276331Snwhitehorn    if (!strcmp(getenv("console"), "nullconsole"))
107276331Snwhitehorn	howto |= RB_MUTE;
108276331Snwhitehorn    return(howto);
109276331Snwhitehorn}
110276331Snwhitehorn
111276331Snwhitehorn/*
112276331Snwhitehorn * Copy the environment into the load area starting at (addr).
113276331Snwhitehorn * Each variable is formatted as <name>=<value>, with a single nul
114276331Snwhitehorn * separating each variable, and a double nul terminating the environment.
115276331Snwhitehorn */
116276331Snwhitehornvm_offset_t
117276331Snwhitehornmd_copyenv(vm_offset_t addr)
118276331Snwhitehorn{
119276331Snwhitehorn    struct env_var	*ep;
120276331Snwhitehorn
121276331Snwhitehorn    /* traverse the environment */
122276331Snwhitehorn    for (ep = environ; ep != NULL; ep = ep->ev_next) {
123276331Snwhitehorn	archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name));
124276331Snwhitehorn	addr += strlen(ep->ev_name);
125276331Snwhitehorn	archsw.arch_copyin("=", addr, 1);
126276331Snwhitehorn	addr++;
127276331Snwhitehorn	if (ep->ev_value != NULL) {
128276331Snwhitehorn	    archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value));
129276331Snwhitehorn	    addr += strlen(ep->ev_value);
130276331Snwhitehorn	}
131276331Snwhitehorn	archsw.arch_copyin("", addr, 1);
132276331Snwhitehorn	addr++;
133276331Snwhitehorn    }
134276331Snwhitehorn    archsw.arch_copyin("", addr, 1);
135276331Snwhitehorn    addr++;
136276331Snwhitehorn    return(addr);
137276331Snwhitehorn}
138276331Snwhitehorn
139276331Snwhitehorn/*
140276331Snwhitehorn * Copy module-related data into the load area, where it can be
141276331Snwhitehorn * used as a directory for loaded modules.
142276331Snwhitehorn *
143276331Snwhitehorn * Module data is presented in a self-describing format.  Each datum
144276331Snwhitehorn * is preceded by a 32-bit identifier and a 32-bit size field.
145276331Snwhitehorn *
146276331Snwhitehorn * Currently, the following data are saved:
147276331Snwhitehorn *
148276331Snwhitehorn * MOD_NAME	(variable)		module name (string)
149276331Snwhitehorn * MOD_TYPE	(variable)		module type (string)
150276331Snwhitehorn * MOD_ARGS	(variable)		module parameters (string)
151276331Snwhitehorn * MOD_ADDR	sizeof(vm_offset_t)	module load address
152276331Snwhitehorn * MOD_SIZE	sizeof(size_t)		module size
153276331Snwhitehorn * MOD_METADATA	(variable)		type-specific metadata
154276331Snwhitehorn */
155276331Snwhitehorn
156276331Snwhitehornstatic int align;
157276331Snwhitehorn
158276331Snwhitehorn#define COPY32(v, a, c) {			\
159276331Snwhitehorn    u_int32_t	x = (v);			\
160276331Snwhitehorn    if (c)					\
161276331Snwhitehorn        archsw.arch_copyin(&x, a, sizeof(x));	\
162276331Snwhitehorn    a += sizeof(x);				\
163276331Snwhitehorn}
164276331Snwhitehorn
165276331Snwhitehorn#define MOD_STR(t, a, s, c) {			\
166276331Snwhitehorn    COPY32(t, a, c);				\
167276331Snwhitehorn    COPY32(strlen(s) + 1, a, c)			\
168276331Snwhitehorn    if (c)					\
169276331Snwhitehorn        archsw.arch_copyin(s, a, strlen(s) + 1);\
170276331Snwhitehorn    a += roundup(strlen(s) + 1, align);		\
171276331Snwhitehorn}
172276331Snwhitehorn
173276331Snwhitehorn#define MOD_NAME(a, s, c)	MOD_STR(MODINFO_NAME, a, s, c)
174276331Snwhitehorn#define MOD_TYPE(a, s, c)	MOD_STR(MODINFO_TYPE, a, s, c)
175276331Snwhitehorn#define MOD_ARGS(a, s, c)	MOD_STR(MODINFO_ARGS, a, s, c)
176276331Snwhitehorn
177276331Snwhitehorn#define MOD_VAR(t, a, s, c) {			\
178276331Snwhitehorn    COPY32(t, a, c);				\
179276331Snwhitehorn    COPY32(sizeof(s), a, c);			\
180276331Snwhitehorn    if (c)					\
181276331Snwhitehorn        archsw.arch_copyin(&s, a, sizeof(s));	\
182276331Snwhitehorn    a += roundup(sizeof(s), align);		\
183276331Snwhitehorn}
184276331Snwhitehorn
185276331Snwhitehorn#define MOD_ADDR(a, s, c)	MOD_VAR(MODINFO_ADDR, a, s, c)
186276331Snwhitehorn#define MOD_SIZE(a, s, c)	MOD_VAR(MODINFO_SIZE, a, s, c)
187276331Snwhitehorn
188276331Snwhitehorn#define MOD_METADATA(a, mm, c) {		\
189276331Snwhitehorn    COPY32(MODINFO_METADATA | mm->md_type, a, c);\
190276331Snwhitehorn    COPY32(mm->md_size, a, c);			\
191276331Snwhitehorn    if (c)					\
192276331Snwhitehorn        archsw.arch_copyin(mm->md_data, a, mm->md_size);\
193276331Snwhitehorn    a += roundup(mm->md_size, align);		\
194276331Snwhitehorn}
195276331Snwhitehorn
196276331Snwhitehorn#define MOD_END(a, c) {				\
197276331Snwhitehorn    COPY32(MODINFO_END, a, c);			\
198276331Snwhitehorn    COPY32(0, a, c);				\
199276331Snwhitehorn}
200276331Snwhitehorn
201276331Snwhitehornvm_offset_t
202276331Snwhitehornmd_copymodules(vm_offset_t addr, int kern64)
203276331Snwhitehorn{
204276331Snwhitehorn    struct preloaded_file	*fp;
205276331Snwhitehorn    struct file_metadata	*md;
206276331Snwhitehorn    uint64_t			scratch64;
207276331Snwhitehorn    int				c;
208276331Snwhitehorn
209276331Snwhitehorn    c = addr != 0;
210276331Snwhitehorn    /* start with the first module on the list, should be the kernel */
211276331Snwhitehorn    for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
212276331Snwhitehorn
213276331Snwhitehorn	MOD_NAME(addr, fp->f_name, c);	/* this field must come first */
214276331Snwhitehorn	MOD_TYPE(addr, fp->f_type, c);
215276331Snwhitehorn	if (fp->f_args)
216276331Snwhitehorn	    MOD_ARGS(addr, fp->f_args, c);
217276331Snwhitehorn	if (kern64) {
218276331Snwhitehorn		scratch64 = fp->f_addr;
219276331Snwhitehorn		MOD_ADDR(addr, scratch64, c);
220276331Snwhitehorn		scratch64 = fp->f_size;
221276331Snwhitehorn		MOD_SIZE(addr, scratch64, c);
222276331Snwhitehorn	} else {
223276331Snwhitehorn		MOD_ADDR(addr, fp->f_addr, c);
224276331Snwhitehorn		MOD_SIZE(addr, fp->f_size, c);
225276331Snwhitehorn	}
226276331Snwhitehorn	for (md = fp->f_metadata; md != NULL; md = md->md_next) {
227276331Snwhitehorn	    if (!(md->md_type & MODINFOMD_NOCOPY)) {
228276331Snwhitehorn		MOD_METADATA(addr, md, c);
229276331Snwhitehorn	    }
230276331Snwhitehorn	}
231276331Snwhitehorn    }
232276331Snwhitehorn    MOD_END(addr, c);
233276331Snwhitehorn    return(addr);
234276331Snwhitehorn}
235276331Snwhitehorn
236276331Snwhitehorn/*
237276331Snwhitehorn * Load the information expected by a powerpc kernel.
238276331Snwhitehorn *
239276331Snwhitehorn * - The 'boothowto' argument is constructed
240276331Snwhitehorn * - The 'bootdev' argument is constructed
241276331Snwhitehorn * - The kernel environment is copied into kernel space.
242276331Snwhitehorn * - Module metadata are formatted and placed in kernel space.
243276331Snwhitehorn */
244276331Snwhitehornint
245276506Snwhitehornmd_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64)
246276331Snwhitehorn{
247276331Snwhitehorn    struct preloaded_file	*kfp;
248276331Snwhitehorn    struct preloaded_file	*xp;
249276331Snwhitehorn    struct file_metadata	*md;
250276331Snwhitehorn    vm_offset_t			kernend;
251276331Snwhitehorn    vm_offset_t			addr;
252276331Snwhitehorn    vm_offset_t			envp;
253276506Snwhitehorn    vm_offset_t			fdtp;
254276331Snwhitehorn    vm_offset_t			size;
255276331Snwhitehorn    uint64_t			scratch64;
256276331Snwhitehorn    char			*rootdevname;
257276331Snwhitehorn    int				howto;
258276331Snwhitehorn
259276331Snwhitehorn    align = kern64 ? 8 : 4;
260276331Snwhitehorn    howto = md_getboothowto(args);
261276331Snwhitehorn
262276331Snwhitehorn    /*
263276331Snwhitehorn     * Allow the environment variable 'rootdev' to override the supplied device
264276331Snwhitehorn     * This should perhaps go to MI code and/or have $rootdev tested/set by
265276331Snwhitehorn     * MI code before launching the kernel.
266276331Snwhitehorn     */
267276331Snwhitehorn    rootdevname = getenv("rootdev");
268276331Snwhitehorn    if (rootdevname == NULL)
269276331Snwhitehorn	    rootdevname = getenv("currdev");
270276331Snwhitehorn    /* Try reading the /etc/fstab file to select the root device */
271276331Snwhitehorn    getrootmount(rootdevname);
272276331Snwhitehorn
273276331Snwhitehorn    /* find the last module in the chain */
274276331Snwhitehorn    addr = 0;
275276331Snwhitehorn    for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
276276331Snwhitehorn	if (addr < (xp->f_addr + xp->f_size))
277276331Snwhitehorn	    addr = xp->f_addr + xp->f_size;
278276331Snwhitehorn    }
279276331Snwhitehorn    /* pad to a page boundary */
280276331Snwhitehorn    addr = roundup(addr, PAGE_SIZE);
281276331Snwhitehorn
282276331Snwhitehorn    /* copy our environment */
283276331Snwhitehorn    envp = addr;
284276331Snwhitehorn    addr = md_copyenv(addr);
285276331Snwhitehorn
286276331Snwhitehorn    /* pad to a page boundary */
287276331Snwhitehorn    addr = roundup(addr, PAGE_SIZE);
288276331Snwhitehorn
289276506Snwhitehorn    /* Copy out FDT */
290276506Snwhitehorn    size = fdt_copy(addr);
291276506Snwhitehorn    *dtb = fdtp = addr;
292276506Snwhitehorn    addr = roundup(addr + size, PAGE_SIZE);
293276506Snwhitehorn
294276331Snwhitehorn    kernend = 0;
295276331Snwhitehorn    kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel");
296276331Snwhitehorn    if (kfp == NULL)
297276331Snwhitehorn	kfp = file_findfile(NULL, "elf kernel");
298276331Snwhitehorn    if (kfp == NULL)
299276331Snwhitehorn	panic("can't find kernel file");
300276331Snwhitehorn    file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
301276331Snwhitehorn    if (kern64) {
302276331Snwhitehorn	scratch64 = envp;
303276331Snwhitehorn	file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64);
304276506Snwhitehorn	scratch64 = fdtp;
305276506Snwhitehorn	file_addmetadata(kfp, MODINFOMD_DTBP, sizeof scratch64, &scratch64);
306276331Snwhitehorn	scratch64 = kernend;
307276331Snwhitehorn	file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof scratch64, &scratch64);
308276331Snwhitehorn    } else {
309276331Snwhitehorn	file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
310276506Snwhitehorn	file_addmetadata(kfp, MODINFOMD_DTBP, sizeof fdtp, &fdtp);
311276331Snwhitehorn	file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
312276331Snwhitehorn    }
313276331Snwhitehorn
314276331Snwhitehorn    *modulep = addr;
315276331Snwhitehorn    size = md_copymodules(0, kern64);
316276331Snwhitehorn    kernend = roundup(addr + size, PAGE_SIZE);
317276331Snwhitehorn
318276331Snwhitehorn    md = file_findmetadata(kfp, MODINFOMD_KERNEND);
319276331Snwhitehorn    if (kern64) {
320276331Snwhitehorn	scratch64 = kernend;
321276331Snwhitehorn	bcopy(&scratch64, md->md_data, sizeof scratch64);
322276331Snwhitehorn    } else {
323276331Snwhitehorn	bcopy(&kernend, md->md_data, sizeof kernend);
324276331Snwhitehorn    }
325276331Snwhitehorn
326276331Snwhitehorn    (void)md_copymodules(addr, kern64);
327276331Snwhitehorn
328276331Snwhitehorn    return(0);
329276331Snwhitehorn}
330276331Snwhitehorn
331276331Snwhitehornint
332276506Snwhitehornmd_load(char *args, vm_offset_t *modulep, vm_offset_t *dtb)
333276331Snwhitehorn{
334276506Snwhitehorn    return (md_load_dual(args, modulep, dtb, 0));
335276331Snwhitehorn}
336276331Snwhitehorn
337276331Snwhitehornint
338276506Snwhitehornmd_load64(char *args, vm_offset_t *modulep, vm_offset_t *dtb)
339276331Snwhitehorn{
340276506Snwhitehorn    return (md_load_dual(args, modulep, dtb, 1));
341276331Snwhitehorn}
342276331Snwhitehorn
343