Deleted Added
full compact
metadata.c (262694) metadata.c (263005)
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * Copyright (C) 2006 Semihalf, Piotr Kruszynski <ppk@semihalf.com>
4 * Copyright (C) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * Copyright (C) 2006 Semihalf, Piotr Kruszynski <ppk@semihalf.com>
4 * Copyright (C) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/boot/uboot/common/metadata.c 262694 2014-03-02 17:19:19Z ian $");
30__FBSDID("$FreeBSD: head/sys/boot/uboot/common/metadata.c 263005 2014-03-11 10:13:06Z royger $");
31
32#include <stand.h>
33#include <sys/param.h>
34#include <sys/reboot.h>
35#include <sys/linker.h>
31
32#include <stand.h>
33#include <sys/param.h>
34#include <sys/reboot.h>
35#include <sys/linker.h>
36#include <sys/boot.h>
36
37#include <machine/elf.h>
38#include <machine/metadata.h>
39
40#include "api_public.h"
41#include "bootstrap.h"
42#include "glue.h"
43
44#if defined(LOADER_FDT_SUPPORT)
45#include "libuboot.h"
46#endif
47
37
38#include <machine/elf.h>
39#include <machine/metadata.h>
40
41#include "api_public.h"
42#include "bootstrap.h"
43#include "glue.h"
44
45#if defined(LOADER_FDT_SUPPORT)
46#include "libuboot.h"
47#endif
48
48/*
49 * Return a 'boothowto' value corresponding to the kernel arguments in
50 * (kargs) and any relevant environment variables.
51 */
52static struct
53{
54 const char *ev;
55 int mask;
56} howto_names[] = {
57 {"boot_askname", RB_ASKNAME},
58 {"boot_cdrom", RB_CDROM},
59 {"boot_ddb", RB_KDB},
60 {"boot_dfltroot", RB_DFLTROOT},
61 {"boot_gdb", RB_GDB},
62 {"boot_multicons", RB_MULTIPLE},
63 {"boot_mute", RB_MUTE},
64 {"boot_pause", RB_PAUSE},
65 {"boot_serial", RB_SERIAL},
66 {"boot_single", RB_SINGLE},
67 {"boot_verbose", RB_VERBOSE},
68 {NULL, 0}
69};
70
71static int
72md_getboothowto(char *kargs)
73{
74 char *cp;
75 char *p;
76 int howto;
77 int active;
78 int i;
79
80 /* Parse kargs */
81 howto = 0;
82 if (kargs != NULL) {
83 cp = kargs;
84 active = 0;
85 while (*cp != 0) {
86 if (!active && (*cp == '-'))
87 active = 1;
88 else if (active)
89 switch (*cp) {
90 case 'a':
91 howto |= RB_ASKNAME;
92 break;
93 case 'C':
94 howto |= RB_CDROM;
95 break;
96 case 'd':
97 howto |= RB_KDB;
98 break;
99 case 'D':
100 howto |= RB_MULTIPLE;
101 break;
102 case 'm':
103 howto |= RB_MUTE;
104 break;
105 case 'g':
106 howto |= RB_GDB;
107 break;
108 case 'h':
109 howto |= RB_SERIAL;
110 break;
111 case 'p':
112 howto |= RB_PAUSE;
113 break;
114 case 'r':
115 howto |= RB_DFLTROOT;
116 break;
117 case 's':
118 howto |= RB_SINGLE;
119 break;
120 case 'v':
121 howto |= RB_VERBOSE;
122 break;
123 default:
124 active = 0;
125 break;
126 }
127 cp++;
128 }
129 }
130
131 /* get equivalents from the environment */
132 for (i = 0; howto_names[i].ev != NULL; i++) {
133 if (getenv(howto_names[i].ev) != NULL)
134 howto |= howto_names[i].mask;
135 }
136 if ((p = getenv("console"))) {
137 if (!strcmp(p, "comconsole"))
138 howto |= RB_SERIAL;
139 if (!strcmp(p, "nullconsole"))
140 howto |= RB_MUTE;
141 }
142
143 return(howto);
144}
145
146/*
147 * Copy the environment into the load area starting at (addr).
148 * Each variable is formatted as <name>=<value>, with a single nul
149 * separating each variable, and a double nul terminating the environment.
150 */
151static vm_offset_t
152md_copyenv(vm_offset_t addr)
153{
154 struct env_var *ep;
155
156 /* traverse the environment */
157 for (ep = environ; ep != NULL; ep = ep->ev_next) {
158 archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name));
159 addr += strlen(ep->ev_name);
160 archsw.arch_copyin("=", addr, 1);
161 addr++;
162 if (ep->ev_value != NULL) {
163 archsw.arch_copyin(ep->ev_value, addr,
164 strlen(ep->ev_value));
165 addr += strlen(ep->ev_value);
166 }
167 archsw.arch_copyin("", addr, 1);
168 addr++;
169 }
170 archsw.arch_copyin("", addr, 1);
171 addr++;
172 return(addr);
173}
174
175/*
176 * Copy module-related data into the load area, where it can be
177 * used as a directory for loaded modules.
178 *
179 * Module data is presented in a self-describing format. Each datum
180 * is preceded by a 32-bit identifier and a 32-bit size field.
181 *
182 * Currently, the following data are saved:
183 *
184 * MOD_NAME (variable) module name (string)
185 * MOD_TYPE (variable) module type (string)
186 * MOD_ARGS (variable) module parameters (string)
187 * MOD_ADDR sizeof(vm_offset_t) module load address
188 * MOD_SIZE sizeof(size_t) module size
189 * MOD_METADATA (variable) type-specific metadata
190 */
191#define COPY32(v, a, c) { \
192 u_int32_t x = (v); \
193 if (c) \
194 archsw.arch_copyin(&x, a, sizeof(x)); \
195 a += sizeof(x); \
196}
197
198#define MOD_STR(t, a, s, c) { \
199 COPY32(t, a, c); \
200 COPY32(strlen(s) + 1, a, c) \
201 if (c) \
202 archsw.arch_copyin(s, a, strlen(s) + 1);\
203 a += roundup(strlen(s) + 1, sizeof(u_long));\
204}
205
206#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c)
207#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c)
208#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c)
209
210#define MOD_VAR(t, a, s, c) { \
211 COPY32(t, a, c); \
212 COPY32(sizeof(s), a, c); \
213 if (c) \
214 archsw.arch_copyin(&s, a, sizeof(s)); \
215 a += roundup(sizeof(s), sizeof(u_long)); \
216}
217
218#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c)
219#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c)
220
221#define MOD_METADATA(a, mm, c) { \
222 COPY32(MODINFO_METADATA | mm->md_type, a, c);\
223 COPY32(mm->md_size, a, c); \
224 if (c) \
225 archsw.arch_copyin(mm->md_data, a, mm->md_size);\
226 a += roundup(mm->md_size, sizeof(u_long)); \
227}
228
229#define MOD_END(a, c) { \
230 COPY32(MODINFO_END, a, c); \
231 COPY32(0, a, c); \
232}
233
234static vm_offset_t
235md_copymodules(vm_offset_t addr)
236{
237 struct preloaded_file *fp;
238 struct file_metadata *md;
239 int c;
240 vm_offset_t a;
241
242 c = addr != 0;
243 /* start with the first module on the list, should be the kernel */
244 for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
245
246 MOD_NAME(addr, fp->f_name, c); /* this field must be first */
247 MOD_TYPE(addr, fp->f_type, c);
248 if (fp->f_args)
249 MOD_ARGS(addr, fp->f_args, c);
250 a = fp->f_addr - __elfN(relocation_offset);
251 MOD_ADDR(addr, a, c);
252 MOD_SIZE(addr, fp->f_size, c);
253 for (md = fp->f_metadata; md != NULL; md = md->md_next) {
254 if (!(md->md_type & MODINFOMD_NOCOPY))
255 MOD_METADATA(addr, md, c);
256 }
257 }
258 MOD_END(addr, c);
259 return(addr);
260}
261
262/*
263 * Load the information expected by a kernel.
264 *
265 * - The 'boothowto' argument is constructed
266 * - The 'bootdev' argument is constructed
267 * - The kernel environment is copied into kernel space.
268 * - Module metadata are formatted and placed in kernel space.
269 */
270int
271md_load(char *args, vm_offset_t *modulep)
272{
273 struct preloaded_file *kfp, *bfp;
274 struct preloaded_file *xp;
275 struct file_metadata *md;
276 struct bootinfo *bip;
277 vm_offset_t kernend;
278 vm_offset_t addr;
279 vm_offset_t envp;
280 vm_offset_t size;
281 vm_offset_t vaddr;
282#if defined(LOADER_FDT_SUPPORT)
283 vm_offset_t dtbp;
284 int dtb_size;
285#endif
286 char *rootdevname;
287 int howto;
288 int i;
289
290 /*
291 * These metadata addreses must be converted for kernel after
292 * relocation.
293 */
294 uint32_t mdt[] = {
295 MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND,
296 MODINFOMD_ENVP,
297#if defined(LOADER_FDT_SUPPORT)
298 MODINFOMD_DTBP
299#endif
300 };
301
302 howto = md_getboothowto(args);
303
304 /*
305 * Allow the environment variable 'rootdev' to override the supplied
306 * device. This should perhaps go to MI code and/or have $rootdev
307 * tested/set by MI code before launching the kernel.
308 */
309 rootdevname = getenv("rootdev");
310 if (rootdevname == NULL)
311 rootdevname = getenv("currdev");
312 /* Try reading the /etc/fstab file to select the root device */
313 getrootmount(rootdevname);
314
315 /* Find the last module in the chain */
316 addr = 0;
317 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
318 if (addr < (xp->f_addr + xp->f_size))
319 addr = xp->f_addr + xp->f_size;
320 }
321 /* Pad to a page boundary */
322 addr = roundup(addr, PAGE_SIZE);
323
324 /* Copy our environment */
325 envp = addr;
326 addr = md_copyenv(addr);
327
328 /* Pad to a page boundary */
329 addr = roundup(addr, PAGE_SIZE);
330
331#if defined(LOADER_FDT_SUPPORT)
332 /* Handle device tree blob */
333 dtbp = addr;
334 dtb_size = fdt_copy(addr);
335
336 /* Pad to a page boundary */
337 if (dtb_size)
338 addr += roundup(dtb_size, PAGE_SIZE);
339#endif
340
341 kernend = 0;
342 kfp = file_findfile(NULL, "elf32 kernel");
343 if (kfp == NULL)
344 kfp = file_findfile(NULL, "elf kernel");
345 if (kfp == NULL)
346 panic("can't find kernel file");
347 file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
348 file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
349
350#if defined(LOADER_FDT_SUPPORT)
351 if (dtb_size)
352 file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp);
353 else
354 pager_output("WARNING! Trying to fire up the kernel, but no "
355 "device tree blob found!\n");
356#endif
357
358 file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
359
360 /* Figure out the size and location of the metadata */
361 *modulep = addr;
362 size = md_copymodules(0);
363 kernend = roundup(addr + size, PAGE_SIZE);
364
365 /* Provide MODINFOMD_KERNEND */
366 md = file_findmetadata(kfp, MODINFOMD_KERNEND);
367 bcopy(&kernend, md->md_data, sizeof kernend);
368
369 /* Convert addresses to the final VA */
370 *modulep -= __elfN(relocation_offset);
371
372 /* Do relocation fixup on metadata of each module. */
373 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
374 for (i = 0; i < sizeof mdt / sizeof mdt[0]; i++) {
375 md = file_findmetadata(xp, mdt[i]);
376 if (md) {
377 bcopy(md->md_data, &vaddr, sizeof vaddr);
378 vaddr -= __elfN(relocation_offset);
379 bcopy(&vaddr, md->md_data, sizeof vaddr);
380 }
381 }
382 }
383
384 /* Only now copy actual modules and metadata */
385 (void)md_copymodules(addr);
386
387 return (0);
388}
49static int
50md_getboothowto(char *kargs)
51{
52 char *cp;
53 char *p;
54 int howto;
55 int active;
56 int i;
57
58 /* Parse kargs */
59 howto = 0;
60 if (kargs != NULL) {
61 cp = kargs;
62 active = 0;
63 while (*cp != 0) {
64 if (!active && (*cp == '-'))
65 active = 1;
66 else if (active)
67 switch (*cp) {
68 case 'a':
69 howto |= RB_ASKNAME;
70 break;
71 case 'C':
72 howto |= RB_CDROM;
73 break;
74 case 'd':
75 howto |= RB_KDB;
76 break;
77 case 'D':
78 howto |= RB_MULTIPLE;
79 break;
80 case 'm':
81 howto |= RB_MUTE;
82 break;
83 case 'g':
84 howto |= RB_GDB;
85 break;
86 case 'h':
87 howto |= RB_SERIAL;
88 break;
89 case 'p':
90 howto |= RB_PAUSE;
91 break;
92 case 'r':
93 howto |= RB_DFLTROOT;
94 break;
95 case 's':
96 howto |= RB_SINGLE;
97 break;
98 case 'v':
99 howto |= RB_VERBOSE;
100 break;
101 default:
102 active = 0;
103 break;
104 }
105 cp++;
106 }
107 }
108
109 /* get equivalents from the environment */
110 for (i = 0; howto_names[i].ev != NULL; i++) {
111 if (getenv(howto_names[i].ev) != NULL)
112 howto |= howto_names[i].mask;
113 }
114 if ((p = getenv("console"))) {
115 if (!strcmp(p, "comconsole"))
116 howto |= RB_SERIAL;
117 if (!strcmp(p, "nullconsole"))
118 howto |= RB_MUTE;
119 }
120
121 return(howto);
122}
123
124/*
125 * Copy the environment into the load area starting at (addr).
126 * Each variable is formatted as <name>=<value>, with a single nul
127 * separating each variable, and a double nul terminating the environment.
128 */
129static vm_offset_t
130md_copyenv(vm_offset_t addr)
131{
132 struct env_var *ep;
133
134 /* traverse the environment */
135 for (ep = environ; ep != NULL; ep = ep->ev_next) {
136 archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name));
137 addr += strlen(ep->ev_name);
138 archsw.arch_copyin("=", addr, 1);
139 addr++;
140 if (ep->ev_value != NULL) {
141 archsw.arch_copyin(ep->ev_value, addr,
142 strlen(ep->ev_value));
143 addr += strlen(ep->ev_value);
144 }
145 archsw.arch_copyin("", addr, 1);
146 addr++;
147 }
148 archsw.arch_copyin("", addr, 1);
149 addr++;
150 return(addr);
151}
152
153/*
154 * Copy module-related data into the load area, where it can be
155 * used as a directory for loaded modules.
156 *
157 * Module data is presented in a self-describing format. Each datum
158 * is preceded by a 32-bit identifier and a 32-bit size field.
159 *
160 * Currently, the following data are saved:
161 *
162 * MOD_NAME (variable) module name (string)
163 * MOD_TYPE (variable) module type (string)
164 * MOD_ARGS (variable) module parameters (string)
165 * MOD_ADDR sizeof(vm_offset_t) module load address
166 * MOD_SIZE sizeof(size_t) module size
167 * MOD_METADATA (variable) type-specific metadata
168 */
169#define COPY32(v, a, c) { \
170 u_int32_t x = (v); \
171 if (c) \
172 archsw.arch_copyin(&x, a, sizeof(x)); \
173 a += sizeof(x); \
174}
175
176#define MOD_STR(t, a, s, c) { \
177 COPY32(t, a, c); \
178 COPY32(strlen(s) + 1, a, c) \
179 if (c) \
180 archsw.arch_copyin(s, a, strlen(s) + 1);\
181 a += roundup(strlen(s) + 1, sizeof(u_long));\
182}
183
184#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c)
185#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c)
186#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c)
187
188#define MOD_VAR(t, a, s, c) { \
189 COPY32(t, a, c); \
190 COPY32(sizeof(s), a, c); \
191 if (c) \
192 archsw.arch_copyin(&s, a, sizeof(s)); \
193 a += roundup(sizeof(s), sizeof(u_long)); \
194}
195
196#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c)
197#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c)
198
199#define MOD_METADATA(a, mm, c) { \
200 COPY32(MODINFO_METADATA | mm->md_type, a, c);\
201 COPY32(mm->md_size, a, c); \
202 if (c) \
203 archsw.arch_copyin(mm->md_data, a, mm->md_size);\
204 a += roundup(mm->md_size, sizeof(u_long)); \
205}
206
207#define MOD_END(a, c) { \
208 COPY32(MODINFO_END, a, c); \
209 COPY32(0, a, c); \
210}
211
212static vm_offset_t
213md_copymodules(vm_offset_t addr)
214{
215 struct preloaded_file *fp;
216 struct file_metadata *md;
217 int c;
218 vm_offset_t a;
219
220 c = addr != 0;
221 /* start with the first module on the list, should be the kernel */
222 for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
223
224 MOD_NAME(addr, fp->f_name, c); /* this field must be first */
225 MOD_TYPE(addr, fp->f_type, c);
226 if (fp->f_args)
227 MOD_ARGS(addr, fp->f_args, c);
228 a = fp->f_addr - __elfN(relocation_offset);
229 MOD_ADDR(addr, a, c);
230 MOD_SIZE(addr, fp->f_size, c);
231 for (md = fp->f_metadata; md != NULL; md = md->md_next) {
232 if (!(md->md_type & MODINFOMD_NOCOPY))
233 MOD_METADATA(addr, md, c);
234 }
235 }
236 MOD_END(addr, c);
237 return(addr);
238}
239
240/*
241 * Load the information expected by a kernel.
242 *
243 * - The 'boothowto' argument is constructed
244 * - The 'bootdev' argument is constructed
245 * - The kernel environment is copied into kernel space.
246 * - Module metadata are formatted and placed in kernel space.
247 */
248int
249md_load(char *args, vm_offset_t *modulep)
250{
251 struct preloaded_file *kfp, *bfp;
252 struct preloaded_file *xp;
253 struct file_metadata *md;
254 struct bootinfo *bip;
255 vm_offset_t kernend;
256 vm_offset_t addr;
257 vm_offset_t envp;
258 vm_offset_t size;
259 vm_offset_t vaddr;
260#if defined(LOADER_FDT_SUPPORT)
261 vm_offset_t dtbp;
262 int dtb_size;
263#endif
264 char *rootdevname;
265 int howto;
266 int i;
267
268 /*
269 * These metadata addreses must be converted for kernel after
270 * relocation.
271 */
272 uint32_t mdt[] = {
273 MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND,
274 MODINFOMD_ENVP,
275#if defined(LOADER_FDT_SUPPORT)
276 MODINFOMD_DTBP
277#endif
278 };
279
280 howto = md_getboothowto(args);
281
282 /*
283 * Allow the environment variable 'rootdev' to override the supplied
284 * device. This should perhaps go to MI code and/or have $rootdev
285 * tested/set by MI code before launching the kernel.
286 */
287 rootdevname = getenv("rootdev");
288 if (rootdevname == NULL)
289 rootdevname = getenv("currdev");
290 /* Try reading the /etc/fstab file to select the root device */
291 getrootmount(rootdevname);
292
293 /* Find the last module in the chain */
294 addr = 0;
295 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
296 if (addr < (xp->f_addr + xp->f_size))
297 addr = xp->f_addr + xp->f_size;
298 }
299 /* Pad to a page boundary */
300 addr = roundup(addr, PAGE_SIZE);
301
302 /* Copy our environment */
303 envp = addr;
304 addr = md_copyenv(addr);
305
306 /* Pad to a page boundary */
307 addr = roundup(addr, PAGE_SIZE);
308
309#if defined(LOADER_FDT_SUPPORT)
310 /* Handle device tree blob */
311 dtbp = addr;
312 dtb_size = fdt_copy(addr);
313
314 /* Pad to a page boundary */
315 if (dtb_size)
316 addr += roundup(dtb_size, PAGE_SIZE);
317#endif
318
319 kernend = 0;
320 kfp = file_findfile(NULL, "elf32 kernel");
321 if (kfp == NULL)
322 kfp = file_findfile(NULL, "elf kernel");
323 if (kfp == NULL)
324 panic("can't find kernel file");
325 file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
326 file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
327
328#if defined(LOADER_FDT_SUPPORT)
329 if (dtb_size)
330 file_addmetadata(kfp, MODINFOMD_DTBP, sizeof dtbp, &dtbp);
331 else
332 pager_output("WARNING! Trying to fire up the kernel, but no "
333 "device tree blob found!\n");
334#endif
335
336 file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
337
338 /* Figure out the size and location of the metadata */
339 *modulep = addr;
340 size = md_copymodules(0);
341 kernend = roundup(addr + size, PAGE_SIZE);
342
343 /* Provide MODINFOMD_KERNEND */
344 md = file_findmetadata(kfp, MODINFOMD_KERNEND);
345 bcopy(&kernend, md->md_data, sizeof kernend);
346
347 /* Convert addresses to the final VA */
348 *modulep -= __elfN(relocation_offset);
349
350 /* Do relocation fixup on metadata of each module. */
351 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
352 for (i = 0; i < sizeof mdt / sizeof mdt[0]; i++) {
353 md = file_findmetadata(xp, mdt[i]);
354 if (md) {
355 bcopy(md->md_data, &vaddr, sizeof vaddr);
356 vaddr -= __elfN(relocation_offset);
357 bcopy(&vaddr, md->md_data, sizeof vaddr);
358 }
359 }
360 }
361
362 /* Only now copy actual modules and metadata */
363 (void)md_copymodules(addr);
364
365 return (0);
366}