1d3e1307bSJustin Hibbits /*-
2d3e1307bSJustin Hibbits * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3d3e1307bSJustin Hibbits * All rights reserved.
4d3e1307bSJustin Hibbits *
5d3e1307bSJustin Hibbits * Redistribution and use in source and binary forms, with or without
6d3e1307bSJustin Hibbits * modification, are permitted provided that the following conditions
7d3e1307bSJustin Hibbits * are met:
8d3e1307bSJustin Hibbits * 1. Redistributions of source code must retain the above copyright
9d3e1307bSJustin Hibbits * notice, this list of conditions and the following disclaimer.
10d3e1307bSJustin Hibbits * 2. Redistributions in binary form must reproduce the above copyright
11d3e1307bSJustin Hibbits * notice, this list of conditions and the following disclaimer in the
12d3e1307bSJustin Hibbits * documentation and/or other materials provided with the distribution.
13d3e1307bSJustin Hibbits *
14d3e1307bSJustin Hibbits * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15d3e1307bSJustin Hibbits * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16d3e1307bSJustin Hibbits * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17d3e1307bSJustin Hibbits * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18d3e1307bSJustin Hibbits * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19d3e1307bSJustin Hibbits * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20d3e1307bSJustin Hibbits * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21d3e1307bSJustin Hibbits * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22d3e1307bSJustin Hibbits * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23d3e1307bSJustin Hibbits * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24d3e1307bSJustin Hibbits * SUCH DAMAGE.
25d3e1307bSJustin Hibbits *
26d3e1307bSJustin Hibbits * from: FreeBSD: src/sys/boot/sparc64/loader/metadata.c,v 1.6
27d3e1307bSJustin Hibbits */
28d3e1307bSJustin Hibbits
29d3e1307bSJustin Hibbits #include <stand.h>
30d3e1307bSJustin Hibbits #include <sys/param.h>
31d3e1307bSJustin Hibbits #include <sys/linker.h>
324569e913SWarner Losh #include <sys/boot.h>
3328ee318dSKyle Evans #include <sys/reboot.h>
34d3e1307bSJustin Hibbits #if defined(LOADER_FDT_SUPPORT)
35d3e1307bSJustin Hibbits #include <fdt_platform.h>
36d3e1307bSJustin Hibbits #endif
37d3e1307bSJustin Hibbits
384daa199dSKyle Evans #ifdef __arm__
394daa199dSKyle Evans #include <machine/elf.h>
404daa199dSKyle Evans #endif
41d3e1307bSJustin Hibbits #include <machine/metadata.h>
42d3e1307bSJustin Hibbits
43d3e1307bSJustin Hibbits #include "bootstrap.h"
44bca9c87bSWarner Losh #include "modinfo.h"
45d3e1307bSJustin Hibbits
46c1418270SIan Lepore #ifdef LOADER_GELI_SUPPORT
47c1418270SIan Lepore #include "geliboot.h"
48c1418270SIan Lepore #endif
49c1418270SIan Lepore
50dd5dbb31SMarius Strobl static int
md_getboothowto(char * kargs)51d3e1307bSJustin Hibbits md_getboothowto(char *kargs)
52d3e1307bSJustin Hibbits {
53d3e1307bSJustin Hibbits int howto;
54d3e1307bSJustin Hibbits
55d3e1307bSJustin Hibbits /* Parse kargs */
564569e913SWarner Losh howto = boot_parse_cmdline(kargs);
57c96ac12eSWarner Losh howto |= boot_env_to_howto();
58d3e1307bSJustin Hibbits if (!strcmp(getenv("console"), "comconsole"))
59d3e1307bSJustin Hibbits howto |= RB_SERIAL;
60d3e1307bSJustin Hibbits if (!strcmp(getenv("console"), "nullconsole"))
61d3e1307bSJustin Hibbits howto |= RB_MUTE;
62d3e1307bSJustin Hibbits return(howto);
63d3e1307bSJustin Hibbits }
64d3e1307bSJustin Hibbits
65d3e1307bSJustin Hibbits /*
66d3e1307bSJustin Hibbits * Load the information expected by a kernel.
67d3e1307bSJustin Hibbits *
68d3e1307bSJustin Hibbits * - The 'boothowto' argument is constructed
69d3e1307bSJustin Hibbits * - The 'bootdev' argument is constructed
70d3e1307bSJustin Hibbits * - The kernel environment is copied into kernel space.
71d3e1307bSJustin Hibbits * - Module metadata are formatted and placed in kernel space.
72d3e1307bSJustin Hibbits */
73dd5dbb31SMarius Strobl static int
md_load_dual(char * args,vm_offset_t * modulep,vm_offset_t * dtb,int kern64)74d3e1307bSJustin Hibbits md_load_dual(char *args, vm_offset_t *modulep, vm_offset_t *dtb, int kern64)
75d3e1307bSJustin Hibbits {
76d3e1307bSJustin Hibbits struct preloaded_file *kfp;
77d3e1307bSJustin Hibbits struct preloaded_file *xp;
78d3e1307bSJustin Hibbits struct file_metadata *md;
79d3e1307bSJustin Hibbits vm_offset_t kernend;
80d3e1307bSJustin Hibbits vm_offset_t addr;
81d3e1307bSJustin Hibbits vm_offset_t envp;
82d3e1307bSJustin Hibbits #if defined(LOADER_FDT_SUPPORT)
83d3e1307bSJustin Hibbits vm_offset_t fdtp;
84d3e1307bSJustin Hibbits #endif
85d3e1307bSJustin Hibbits vm_offset_t size;
86d3e1307bSJustin Hibbits uint64_t scratch64;
87d3e1307bSJustin Hibbits char *rootdevname;
88d3e1307bSJustin Hibbits int howto;
894daa199dSKyle Evans #ifdef __arm__
904daa199dSKyle Evans vm_offset_t vaddr;
914daa199dSKyle Evans int i;
924daa199dSKyle Evans
934daa199dSKyle Evans /*
944daa199dSKyle Evans * These metadata addreses must be converted for kernel after
954daa199dSKyle Evans * relocation.
964daa199dSKyle Evans */
974daa199dSKyle Evans uint32_t mdt[] = {
984daa199dSKyle Evans MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND,
994daa199dSKyle Evans MODINFOMD_ENVP,
1004daa199dSKyle Evans #if defined(LOADER_FDT_SUPPORT)
1014daa199dSKyle Evans MODINFOMD_DTBP
1024daa199dSKyle Evans #endif
1034daa199dSKyle Evans };
1044daa199dSKyle Evans #endif
105d3e1307bSJustin Hibbits
106d3e1307bSJustin Hibbits howto = md_getboothowto(args);
107d3e1307bSJustin Hibbits
108d3e1307bSJustin Hibbits /*
109d3e1307bSJustin Hibbits * Allow the environment variable 'rootdev' to override the supplied
110d3e1307bSJustin Hibbits * device. This should perhaps go to MI code and/or have $rootdev
111d3e1307bSJustin Hibbits * tested/set by MI code before launching the kernel.
112d3e1307bSJustin Hibbits */
113d3e1307bSJustin Hibbits rootdevname = getenv("rootdev");
114d3e1307bSJustin Hibbits if (rootdevname == NULL)
115d3e1307bSJustin Hibbits rootdevname = getenv("currdev");
116d3e1307bSJustin Hibbits /* Try reading the /etc/fstab file to select the root device */
117d3e1307bSJustin Hibbits getrootmount(rootdevname);
118d3e1307bSJustin Hibbits
119d3e1307bSJustin Hibbits /* Find the last module in the chain */
120d3e1307bSJustin Hibbits addr = 0;
121d3e1307bSJustin Hibbits for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
122d3e1307bSJustin Hibbits if (addr < (xp->f_addr + xp->f_size))
123d3e1307bSJustin Hibbits addr = xp->f_addr + xp->f_size;
124d3e1307bSJustin Hibbits }
125d3e1307bSJustin Hibbits /* Pad to a page boundary */
126d3e1307bSJustin Hibbits addr = roundup(addr, PAGE_SIZE);
127d3e1307bSJustin Hibbits
128d3e1307bSJustin Hibbits /* Copy our environment */
129d3e1307bSJustin Hibbits envp = addr;
130d3e1307bSJustin Hibbits addr = md_copyenv(addr);
131d3e1307bSJustin Hibbits
132d3e1307bSJustin Hibbits /* Pad to a page boundary */
133d3e1307bSJustin Hibbits addr = roundup(addr, PAGE_SIZE);
134d3e1307bSJustin Hibbits
135d3e1307bSJustin Hibbits #if defined(LOADER_FDT_SUPPORT)
136d3e1307bSJustin Hibbits /* Copy out FDT */
137d3e1307bSJustin Hibbits fdtp = 0;
138d3e1307bSJustin Hibbits #if defined(__powerpc__)
139d3e1307bSJustin Hibbits if (getenv("usefdt") != NULL)
140d3e1307bSJustin Hibbits #endif
141d3e1307bSJustin Hibbits {
142d3e1307bSJustin Hibbits size = fdt_copy(addr);
143d3e1307bSJustin Hibbits fdtp = addr;
144d3e1307bSJustin Hibbits addr = roundup(addr + size, PAGE_SIZE);
145d3e1307bSJustin Hibbits }
146d3e1307bSJustin Hibbits #endif
147d3e1307bSJustin Hibbits
148d3e1307bSJustin Hibbits kernend = 0;
149d3e1307bSJustin Hibbits kfp = file_findfile(NULL, kern64 ? "elf64 kernel" : "elf32 kernel");
150d3e1307bSJustin Hibbits if (kfp == NULL)
151d3e1307bSJustin Hibbits kfp = file_findfile(NULL, "elf kernel");
152d3e1307bSJustin Hibbits if (kfp == NULL)
153d3e1307bSJustin Hibbits panic("can't find kernel file");
154d3e1307bSJustin Hibbits file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
155d3e1307bSJustin Hibbits if (kern64) {
156d3e1307bSJustin Hibbits scratch64 = envp;
157d3e1307bSJustin Hibbits file_addmetadata(kfp, MODINFOMD_ENVP, sizeof scratch64, &scratch64);
158d3e1307bSJustin Hibbits #if defined(LOADER_FDT_SUPPORT)
159d3e1307bSJustin Hibbits if (fdtp != 0) {
160d3e1307bSJustin Hibbits scratch64 = fdtp;
161d3e1307bSJustin Hibbits file_addmetadata(kfp, MODINFOMD_DTBP, sizeof scratch64, &scratch64);
162d3e1307bSJustin Hibbits }
163d3e1307bSJustin Hibbits #endif
164d3e1307bSJustin Hibbits scratch64 = kernend;
165d3e1307bSJustin Hibbits file_addmetadata(kfp, MODINFOMD_KERNEND,
166d3e1307bSJustin Hibbits sizeof scratch64, &scratch64);
167d3e1307bSJustin Hibbits } else {
168d3e1307bSJustin Hibbits file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
169d3e1307bSJustin Hibbits #if defined(LOADER_FDT_SUPPORT)
170d3e1307bSJustin Hibbits if (fdtp != 0)
171d3e1307bSJustin Hibbits file_addmetadata(kfp, MODINFOMD_DTBP, sizeof fdtp, &fdtp);
172d3e1307bSJustin Hibbits #endif
173d3e1307bSJustin Hibbits file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
174d3e1307bSJustin Hibbits }
175c1418270SIan Lepore #ifdef LOADER_GELI_SUPPORT
176c1418270SIan Lepore geli_export_key_metadata(kfp);
177c1418270SIan Lepore #endif
178d3e1307bSJustin Hibbits
179d3e1307bSJustin Hibbits *modulep = addr;
180d3e1307bSJustin Hibbits size = md_copymodules(0, kern64);
181d3e1307bSJustin Hibbits kernend = roundup(addr + size, PAGE_SIZE);
182d3e1307bSJustin Hibbits
183d3e1307bSJustin Hibbits md = file_findmetadata(kfp, MODINFOMD_KERNEND);
184d3e1307bSJustin Hibbits if (kern64) {
185d3e1307bSJustin Hibbits scratch64 = kernend;
186d3e1307bSJustin Hibbits bcopy(&scratch64, md->md_data, sizeof scratch64);
187d3e1307bSJustin Hibbits } else {
188d3e1307bSJustin Hibbits bcopy(&kernend, md->md_data, sizeof kernend);
189d3e1307bSJustin Hibbits }
190d3e1307bSJustin Hibbits
1914daa199dSKyle Evans #ifdef __arm__
1924daa199dSKyle Evans /* Convert addresses to the final VA */
1934daa199dSKyle Evans *modulep -= __elfN(relocation_offset);
1944daa199dSKyle Evans
1954daa199dSKyle Evans /* Do relocation fixup on metadata of each module. */
1964daa199dSKyle Evans for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
1974daa199dSKyle Evans for (i = 0; i < nitems(mdt); i++) {
1984daa199dSKyle Evans md = file_findmetadata(xp, mdt[i]);
1994daa199dSKyle Evans if (md) {
2004daa199dSKyle Evans bcopy(md->md_data, &vaddr, sizeof vaddr);
2014daa199dSKyle Evans vaddr -= __elfN(relocation_offset);
2024daa199dSKyle Evans bcopy(&vaddr, md->md_data, sizeof vaddr);
2034daa199dSKyle Evans }
2044daa199dSKyle Evans }
2054daa199dSKyle Evans }
2064daa199dSKyle Evans #endif
2074daa199dSKyle Evans
208d3e1307bSJustin Hibbits (void)md_copymodules(addr, kern64);
209d3e1307bSJustin Hibbits #if defined(LOADER_FDT_SUPPORT)
210d3e1307bSJustin Hibbits if (dtb != NULL)
211d3e1307bSJustin Hibbits *dtb = fdtp;
212d3e1307bSJustin Hibbits #endif
213d3e1307bSJustin Hibbits
214d3e1307bSJustin Hibbits return(0);
215d3e1307bSJustin Hibbits }
216d3e1307bSJustin Hibbits
217d3e1307bSJustin Hibbits int
md_load(char * args,vm_offset_t * modulep,vm_offset_t * dtb)218d3e1307bSJustin Hibbits md_load(char *args, vm_offset_t *modulep, vm_offset_t *dtb)
219d3e1307bSJustin Hibbits {
220d3e1307bSJustin Hibbits return (md_load_dual(args, modulep, dtb, 0));
221d3e1307bSJustin Hibbits }
222d3e1307bSJustin Hibbits
22320b23ae7SWarner Losh #if defined(__powerpc__)
224d3e1307bSJustin Hibbits int
md_load64(char * args,vm_offset_t * modulep,vm_offset_t * dtb)225d3e1307bSJustin Hibbits md_load64(char *args, vm_offset_t *modulep, vm_offset_t *dtb)
226d3e1307bSJustin Hibbits {
227d3e1307bSJustin Hibbits return (md_load_dual(args, modulep, dtb, 1));
228d3e1307bSJustin Hibbits }
229d3e1307bSJustin Hibbits #endif
230