199727Sbenno/*-
299727Sbenno * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
399727Sbenno * All rights reserved.
499727Sbenno *
599727Sbenno * Redistribution and use in source and binary forms, with or without
699727Sbenno * modification, are permitted provided that the following conditions
799727Sbenno * are met:
899727Sbenno * 1. Redistributions of source code must retain the above copyright
999727Sbenno *    notice, this list of conditions and the following disclaimer.
1099727Sbenno * 2. Redistributions in binary form must reproduce the above copyright
1199727Sbenno *    notice, this list of conditions and the following disclaimer in the
1299727Sbenno *    documentation and/or other materials provided with the distribution.
1399727Sbenno *
1499727Sbenno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1599727Sbenno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1699727Sbenno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1799727Sbenno * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1899727Sbenno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1999727Sbenno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2099727Sbenno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2199727Sbenno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2299727Sbenno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2399727Sbenno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2499727Sbenno * SUCH DAMAGE.
2599727Sbenno *
2699727Sbenno *	from: FreeBSD: src/sys/boot/sparc64/loader/metadata.c,v 1.6
2799727Sbenno */
2899727Sbenno
29124139Sobrien#include <sys/cdefs.h>
30124139Sobrien__FBSDID("$FreeBSD$");
31124139Sobrien
3299727Sbenno#include <stand.h>
3399727Sbenno#include <sys/param.h>
3499727Sbenno#include <sys/reboot.h>
3599727Sbenno#include <sys/linker.h>
36271132Semaste#include <sys/boot.h>
3799727Sbenno
3899727Sbenno#include <machine/metadata.h>
3999727Sbenno
4099727Sbenno#include "bootstrap.h"
4199727Sbenno#include "libofw.h"
4299727Sbenno
4399727Sbennoint
4499727Sbennomd_getboothowto(char *kargs)
4599727Sbenno{
4699727Sbenno    char	*cp;
4799727Sbenno    int		howto;
4899727Sbenno    int		active;
4999727Sbenno    int		i;
5099727Sbenno
5199727Sbenno    /* Parse kargs */
5299727Sbenno    howto = 0;
5399727Sbenno    if (kargs != NULL) {
5499727Sbenno	cp = kargs;
5599727Sbenno	active = 0;
5699727Sbenno	while (*cp != 0) {
5799727Sbenno	    if (!active && (*cp == '-')) {
5899727Sbenno		active = 1;
5999727Sbenno	    } else if (active)
6099727Sbenno		switch (*cp) {
6199727Sbenno		case 'a':
6299727Sbenno		    howto |= RB_ASKNAME;
6399727Sbenno		    break;
6499727Sbenno		case 'C':
6599727Sbenno		    howto |= RB_CDROM;
6699727Sbenno		    break;
6799727Sbenno		case 'd':
6899727Sbenno		    howto |= RB_KDB;
6999727Sbenno		    break;
7099727Sbenno		case 'D':
7199727Sbenno		    howto |= RB_MULTIPLE;
7299727Sbenno		    break;
7399727Sbenno		case 'm':
7499727Sbenno		    howto |= RB_MUTE;
7599727Sbenno		    break;
7699727Sbenno		case 'g':
7799727Sbenno		    howto |= RB_GDB;
7899727Sbenno		    break;
7999727Sbenno		case 'h':
8099727Sbenno		    howto |= RB_SERIAL;
8199727Sbenno		    break;
82150469Sru		case 'p':
83150469Sru		    howto |= RB_PAUSE;
84150469Sru		    break;
8599727Sbenno		case 'r':
8699727Sbenno		    howto |= RB_DFLTROOT;
8799727Sbenno		    break;
8899727Sbenno		case 's':
8999727Sbenno		    howto |= RB_SINGLE;
9099727Sbenno		    break;
9199727Sbenno		case 'v':
9299727Sbenno		    howto |= RB_VERBOSE;
9399727Sbenno		    break;
9499727Sbenno		default:
9599727Sbenno		    active = 0;
9699727Sbenno		    break;
9799727Sbenno		}
9899727Sbenno	    cp++;
9999727Sbenno	}
10099727Sbenno    }
10199727Sbenno    /* get equivalents from the environment */
10299727Sbenno    for (i = 0; howto_names[i].ev != NULL; i++)
10399727Sbenno	if (getenv(howto_names[i].ev) != NULL)
10499727Sbenno	    howto |= howto_names[i].mask;
10599727Sbenno    if (!strcmp(getenv("console"), "comconsole"))
10699727Sbenno	howto |= RB_SERIAL;
10799727Sbenno    if (!strcmp(getenv("console"), "nullconsole"))
10899727Sbenno	howto |= RB_MUTE;
10999727Sbenno    return(howto);
11099727Sbenno}
11199727Sbenno
11299727Sbenno/*
11399727Sbenno * Copy the environment into the load area starting at (addr).
11499727Sbenno * Each variable is formatted as <name>=<value>, with a single nul
11599727Sbenno * separating each variable, and a double nul terminating the environment.
11699727Sbenno */
11799727Sbennovm_offset_t
11899727Sbennomd_copyenv(vm_offset_t addr)
11999727Sbenno{
12099727Sbenno    struct env_var	*ep;
12199727Sbenno
12299727Sbenno    /* traverse the environment */
12399727Sbenno    for (ep = environ; ep != NULL; ep = ep->ev_next) {
12499727Sbenno	archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name));
12599727Sbenno	addr += strlen(ep->ev_name);
12699727Sbenno	archsw.arch_copyin("=", addr, 1);
12799727Sbenno	addr++;
12899727Sbenno	if (ep->ev_value != NULL) {
12999727Sbenno	    archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value));
13099727Sbenno	    addr += strlen(ep->ev_value);
13199727Sbenno	}
13299727Sbenno	archsw.arch_copyin("", addr, 1);
13399727Sbenno	addr++;
13499727Sbenno    }
13599727Sbenno    archsw.arch_copyin("", addr, 1);
13699727Sbenno    addr++;
13799727Sbenno    return(addr);
13899727Sbenno}
13999727Sbenno
14099727Sbenno/*
14199727Sbenno * Copy module-related data into the load area, where it can be
14299727Sbenno * used as a directory for loaded modules.
14399727Sbenno *
14499727Sbenno * Module data is presented in a self-describing format.  Each datum
14599727Sbenno * is preceded by a 32-bit identifier and a 32-bit size field.
14699727Sbenno *
14799727Sbenno * Currently, the following data are saved:
14899727Sbenno *
14999727Sbenno * MOD_NAME	(variable)		module name (string)
15099727Sbenno * MOD_TYPE	(variable)		module type (string)
15199727Sbenno * MOD_ARGS	(variable)		module parameters (string)
15299727Sbenno * MOD_ADDR	sizeof(vm_offset_t)	module load address
15399727Sbenno * MOD_SIZE	sizeof(size_t)		module size
15499727Sbenno * MOD_METADATA	(variable)		type-specific metadata
15599727Sbenno */
156209920Snwhitehorn
157209920Snwhitehornstatic int align;
158209920Snwhitehorn
15999727Sbenno#define COPY32(v, a, c) {			\
16099727Sbenno    u_int32_t	x = (v);			\
16199727Sbenno    if (c)					\
16299727Sbenno        archsw.arch_copyin(&x, a, sizeof(x));	\
16399727Sbenno    a += sizeof(x);				\
16499727Sbenno}
16599727Sbenno
16699727Sbenno#define MOD_STR(t, a, s, c) {			\
16799727Sbenno    COPY32(t, a, c);				\
16899727Sbenno    COPY32(strlen(s) + 1, a, c)			\
16999727Sbenno    if (c)					\
17099727Sbenno        archsw.arch_copyin(s, a, strlen(s) + 1);\
171209920Snwhitehorn    a += roundup(strlen(s) + 1, align);		\
17299727Sbenno}
17399727Sbenno
17499727Sbenno#define MOD_NAME(a, s, c)	MOD_STR(MODINFO_NAME, a, s, c)
17599727Sbenno#define MOD_TYPE(a, s, c)	MOD_STR(MODINFO_TYPE, a, s, c)
17699727Sbenno#define MOD_ARGS(a, s, c)	MOD_STR(MODINFO_ARGS, a, s, c)
17799727Sbenno
17899727Sbenno#define MOD_VAR(t, a, s, c) {			\
17999727Sbenno    COPY32(t, a, c);				\
18099727Sbenno    COPY32(sizeof(s), a, c);			\
18199727Sbenno    if (c)					\
18299727Sbenno        archsw.arch_copyin(&s, a, sizeof(s));	\
183209920Snwhitehorn    a += roundup(sizeof(s), align);		\
18499727Sbenno}
18599727Sbenno
18699727Sbenno#define MOD_ADDR(a, s, c)	MOD_VAR(MODINFO_ADDR, a, s, c)
18799727Sbenno#define MOD_SIZE(a, s, c)	MOD_VAR(MODINFO_SIZE, a, s, c)
18899727Sbenno
18999727Sbenno#define MOD_METADATA(a, mm, c) {		\
19099727Sbenno    COPY32(MODINFO_METADATA | mm->md_type, a, c);\
19199727Sbenno    COPY32(mm->md_size, a, c);			\
19299727Sbenno    if (c)					\
19399727Sbenno        archsw.arch_copyin(mm->md_data, a, mm->md_size);\
194209920Snwhitehorn    a += roundup(mm->md_size, align);		\
19599727Sbenno}
19699727Sbenno
19799727Sbenno#define MOD_END(a, c) {				\
19899727Sbenno    COPY32(MODINFO_END, a, c);			\
19999727Sbenno    COPY32(0, a, c);				\
20099727Sbenno}
20199727Sbenno
20299727Sbennovm_offset_t
203209920Snwhitehornmd_copymodules(vm_offset_t addr, int kern64)
20499727Sbenno{
20599727Sbenno    struct preloaded_file	*fp;
20699727Sbenno    struct file_metadata	*md;
207209920Snwhitehorn    uint64_t			scratch64;
20899727Sbenno    int				c;
20999727Sbenno
21099727Sbenno    c = addr != 0;
21199727Sbenno    /* start with the first module on the list, should be the kernel */
21299727Sbenno    for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
21399727Sbenno
21499727Sbenno	MOD_NAME(addr, fp->f_name, c);	/* this field must come first */
21599727Sbenno	MOD_TYPE(addr, fp->f_type, c);
21699727Sbenno	if (fp->f_args)
21799727Sbenno	    MOD_ARGS(addr, fp->f_args, c);
218209920Snwhitehorn	if (kern64) {
219209920Snwhitehorn		scratch64 = fp->f_addr;
220209920Snwhitehorn		MOD_ADDR(addr, scratch64, c);
221209920Snwhitehorn		scratch64 = fp->f_size;
222209920Snwhitehorn		MOD_SIZE(addr, scratch64, c);
223209920Snwhitehorn	} else {
224209920Snwhitehorn		MOD_ADDR(addr, fp->f_addr, c);
225209920Snwhitehorn		MOD_SIZE(addr, fp->f_size, c);
226209920Snwhitehorn	}
22799727Sbenno	for (md = fp->f_metadata; md != NULL; md = md->md_next) {
22899727Sbenno	    if (!(md->md_type & MODINFOMD_NOCOPY)) {
22999727Sbenno		MOD_METADATA(addr, md, c);
23099727Sbenno	    }
23199727Sbenno	}
23299727Sbenno    }
23399727Sbenno    MOD_END(addr, c);
23499727Sbenno    return(addr);
23599727Sbenno}
23699727Sbenno
23799727Sbenno/*
23899727Sbenno * Load the information expected by a powerpc kernel.
23999727Sbenno *
24099727Sbenno * - The 'boothowto' argument is constructed
24199727Sbenno * - The 'bootdev' argument is constructed
24299727Sbenno * - The kernel environment is copied into kernel space.
24399727Sbenno * - Module metadata are formatted and placed in kernel space.
24499727Sbenno */
24599727Sbennoint
246209920Snwhitehornmd_load_dual(char *args, vm_offset_t *modulep, int kern64)
24799727Sbenno{
24899727Sbenno    struct preloaded_file	*kfp;
24999727Sbenno    struct preloaded_file	*xp;
25099727Sbenno    struct file_metadata	*md;
25199727Sbenno    vm_offset_t			kernend;
25299727Sbenno    vm_offset_t			addr;
25399727Sbenno    vm_offset_t			envp;
25499727Sbenno    vm_offset_t			size;
255209920Snwhitehorn    uint64_t			scratch64;
25699727Sbenno    char			*rootdevname;
25799727Sbenno    int				howto;
25899727Sbenno
259209920Snwhitehorn    align = kern64 ? 8 : 4;
26099727Sbenno    howto = md_getboothowto(args);
26199727Sbenno
26299727Sbenno    /*
26399727Sbenno     * Allow the environment variable 'rootdev' to override the supplied device
26499727Sbenno     * This should perhaps go to MI code and/or have $rootdev tested/set by
26599727Sbenno     * MI code before launching the kernel.
26699727Sbenno     */
26799727Sbenno    rootdevname = getenv("rootdev");
268106738Sjake    if (rootdevname == NULL)
269106738Sjake	    rootdevname = getenv("currdev");
27099727Sbenno    /* Try reading the /etc/fstab file to select the root device */
271106738Sjake    getrootmount(rootdevname);
27299727Sbenno
27399727Sbenno    /* find the last module in the chain */
27499727Sbenno    addr = 0;
27599727Sbenno    for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
27699727Sbenno	if (addr < (xp->f_addr + xp->f_size))
27799727Sbenno	    addr = xp->f_addr + xp->f_size;
27899727Sbenno    }
27999727Sbenno    /* pad to a page boundary */
28099727Sbenno    addr = roundup(addr, PAGE_SIZE);
28199727Sbenno
28299727Sbenno    /* copy our environment */
28399727Sbenno    envp = addr;
28499727Sbenno    addr = md_copyenv(addr);
28599727Sbenno
28699727Sbenno    /* pad to a page boundary */
28799727Sbenno    addr = roundup(addr, PAGE_SIZE);
28899727Sbenno
28999727Sbenno    kernend = 0;
290209920Snwhitehorn    kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel");
29199727Sbenno    if (kfp == NULL)
292114338Speter	kfp = file_findfile(NULL, "elf kernel");
293114338Speter    if (kfp == NULL)
29499727Sbenno	panic("can't find kernel file");
29599727Sbenno    file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
296209920Snwhitehorn    if (kern64) {
297209920Snwhitehorn	scratch64 = envp;
298209920Snwhitehorn	file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64);
299209920Snwhitehorn	scratch64 = kernend;
300209920Snwhitehorn	file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof scratch64, &scratch64);
301209920Snwhitehorn    } else {
302209920Snwhitehorn	file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
303209920Snwhitehorn	file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
304209920Snwhitehorn    }
30599727Sbenno
30699727Sbenno    *modulep = addr;
307209920Snwhitehorn    size = md_copymodules(0, kern64);
30899727Sbenno    kernend = roundup(addr + size, PAGE_SIZE);
30999727Sbenno
31099727Sbenno    md = file_findmetadata(kfp, MODINFOMD_KERNEND);
311209920Snwhitehorn    if (kern64) {
312209920Snwhitehorn	scratch64 = kernend;
313209920Snwhitehorn	bcopy(&scratch64, md->md_data, sizeof scratch64);
314209920Snwhitehorn    } else {
315209920Snwhitehorn	bcopy(&kernend, md->md_data, sizeof kernend);
316209920Snwhitehorn    }
317209920Snwhitehorn
318209920Snwhitehorn    (void)md_copymodules(addr, kern64);
31999727Sbenno
32099727Sbenno    return(0);
32199727Sbenno}
322209920Snwhitehorn
323209920Snwhitehornint
324209920Snwhitehornmd_load(char *args, vm_offset_t *modulep)
325209920Snwhitehorn{
326209920Snwhitehorn    return (md_load_dual(args, modulep, 0));
327209920Snwhitehorn}
328209920Snwhitehorn
329209920Snwhitehornint
330209920Snwhitehornmd_load64(char *args, vm_offset_t *modulep)
331209920Snwhitehorn{
332209920Snwhitehorn    return (md_load_dual(args, modulep, 1));
333209920Snwhitehorn}
334209920Snwhitehorn
335