Deleted Added
full compact
metadata.c (176487) metadata.c (176489)
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * Copyright (C) 2007-2008 Semihalf, Piotr Kruszynski <ppk@semihalf.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 12 unchanged lines hidden (view full) ---

21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * Copyright (C) 2007-2008 Semihalf, Piotr Kruszynski <ppk@semihalf.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 12 unchanged lines hidden (view full) ---

21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: head/sys/boot/powerpc/uboot/metadata.c 176487 2008-02-23 19:08:25Z marcel $");
29__FBSDID("$FreeBSD: head/sys/boot/powerpc/uboot/metadata.c 176489 2008-02-23 19:43:29Z marcel $");
30
31#include <stand.h>
32#include <sys/param.h>
33#include <sys/reboot.h>
34#include <sys/linker.h>
35
36#include <machine/elf.h>
37#include <machine/metadata.h>
38#include <machine/bootinfo.h>
39
40#include "api_public.h"
41#include "bootstrap.h"
42#include "glue.h"
43
44/*
45 * Return a 'boothowto' value corresponding to the kernel arguments in
46 * (kargs) and any relevant environment variables.
47 */
30
31#include <stand.h>
32#include <sys/param.h>
33#include <sys/reboot.h>
34#include <sys/linker.h>
35
36#include <machine/elf.h>
37#include <machine/metadata.h>
38#include <machine/bootinfo.h>
39
40#include "api_public.h"
41#include "bootstrap.h"
42#include "glue.h"
43
44/*
45 * Return a 'boothowto' value corresponding to the kernel arguments in
46 * (kargs) and any relevant environment variables.
47 */
48static struct
48static struct
49{
49{
50 const char *ev;
51 int mask;
50 const char *ev;
51 int mask;
52} howto_names[] = {
52} howto_names[] = {
53 {"boot_askname", RB_ASKNAME},
54 {"boot_cdrom", RB_CDROM},
55 {"boot_ddb", RB_KDB},
56 {"boot_dfltroot", RB_DFLTROOT},
57 {"boot_gdb", RB_GDB},
58 {"boot_multicons", RB_MULTIPLE},
59 {"boot_mute", RB_MUTE},
60 {"boot_pause", RB_PAUSE},
61 {"boot_serial", RB_SERIAL},
62 {"boot_single", RB_SINGLE},
63 {"boot_verbose", RB_VERBOSE},
64 {NULL, 0}
53 {"boot_askname", RB_ASKNAME},
54 {"boot_cdrom", RB_CDROM},
55 {"boot_ddb", RB_KDB},
56 {"boot_dfltroot", RB_DFLTROOT},
57 {"boot_gdb", RB_GDB},
58 {"boot_multicons", RB_MULTIPLE},
59 {"boot_mute", RB_MUTE},
60 {"boot_pause", RB_PAUSE},
61 {"boot_serial", RB_SERIAL},
62 {"boot_single", RB_SINGLE},
63 {"boot_verbose", RB_VERBOSE},
64 {NULL, 0}
65};
66
67static int
68md_getboothowto(char *kargs)
69{
65};
66
67static int
68md_getboothowto(char *kargs)
69{
70 char *cp;
71 int howto;
72 int active;
73 int i;
74
75 /* Parse kargs */
76 howto = 0;
77 if (kargs != NULL) {
78 cp = kargs;
79 active = 0;
80 while (*cp != 0) {
81 if (!active && (*cp == '-')) {
82 active = 1;
83 } else if (active)
84 switch (*cp) {
85 case 'a':
86 howto |= RB_ASKNAME;
87 break;
88 case 'C':
89 howto |= RB_CDROM;
90 break;
91 case 'd':
92 howto |= RB_KDB;
93 break;
94 case 'D':
95 howto |= RB_MULTIPLE;
96 break;
97 case 'm':
98 howto |= RB_MUTE;
99 break;
100 case 'g':
101 howto |= RB_GDB;
102 break;
103 case 'h':
104 howto |= RB_SERIAL;
105 break;
106 case 'p':
107 howto |= RB_PAUSE;
108 break;
109 case 'r':
110 howto |= RB_DFLTROOT;
111 break;
112 case 's':
113 howto |= RB_SINGLE;
114 break;
115 case 'v':
116 howto |= RB_VERBOSE;
117 break;
118 default:
119 active = 0;
120 break;
70 char *cp;
71 int howto;
72 int active;
73 int i;
74
75 /* Parse kargs */
76 howto = 0;
77 if (kargs != NULL) {
78 cp = kargs;
79 active = 0;
80 while (*cp != 0) {
81 if (!active && (*cp == '-'))
82 active = 1;
83 else if (active)
84 switch (*cp) {
85 case 'a':
86 howto |= RB_ASKNAME;
87 break;
88 case 'C':
89 howto |= RB_CDROM;
90 break;
91 case 'd':
92 howto |= RB_KDB;
93 break;
94 case 'D':
95 howto |= RB_MULTIPLE;
96 break;
97 case 'm':
98 howto |= RB_MUTE;
99 break;
100 case 'g':
101 howto |= RB_GDB;
102 break;
103 case 'h':
104 howto |= RB_SERIAL;
105 break;
106 case 'p':
107 howto |= RB_PAUSE;
108 break;
109 case 'r':
110 howto |= RB_DFLTROOT;
111 break;
112 case 's':
113 howto |= RB_SINGLE;
114 break;
115 case 'v':
116 howto |= RB_VERBOSE;
117 break;
118 default:
119 active = 0;
120 break;
121 }
122 cp++;
121 }
123 }
122 cp++;
123 }
124 }
124 }
125 /* get equivalents from the environment */
126 for (i = 0; howto_names[i].ev != NULL; i++)
127 if (getenv(howto_names[i].ev) != NULL)
128 howto |= howto_names[i].mask;
129 if (!strcmp(getenv("console"), "comconsole"))
130 howto |= RB_SERIAL;
131 if (!strcmp(getenv("console"), "nullconsole"))
132 howto |= RB_MUTE;
133 return(howto);
125
126 /* get equivalents from the environment */
127 for (i = 0; howto_names[i].ev != NULL; i++) {
128 if (getenv(howto_names[i].ev) != NULL)
129 howto |= howto_names[i].mask;
130 }
131 if (!strcmp(getenv("console"), "comconsole"))
132 howto |= RB_SERIAL;
133 if (!strcmp(getenv("console"), "nullconsole"))
134 howto |= RB_MUTE;
135
136 return(howto);
134}
135
136/*
137 * Copy the environment into the load area starting at (addr).
138 * Each variable is formatted as <name>=<value>, with a single nul
139 * separating each variable, and a double nul terminating the environment.
140 */
141static vm_offset_t
142md_copyenv(vm_offset_t addr)
143{
137}
138
139/*
140 * Copy the environment into the load area starting at (addr).
141 * Each variable is formatted as <name>=<value>, with a single nul
142 * separating each variable, and a double nul terminating the environment.
143 */
144static vm_offset_t
145md_copyenv(vm_offset_t addr)
146{
144 struct env_var *ep;
145
146 /* traverse the environment */
147 for (ep = environ; ep != NULL; ep = ep->ev_next) {
148 archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name));
149 addr += strlen(ep->ev_name);
150 archsw.arch_copyin("=", addr, 1);
151 addr++;
152 if (ep->ev_value != NULL) {
153 archsw.arch_copyin(ep->ev_value, addr, strlen(ep->ev_value));
154 addr += strlen(ep->ev_value);
147 struct env_var *ep;
148
149 /* traverse the environment */
150 for (ep = environ; ep != NULL; ep = ep->ev_next) {
151 archsw.arch_copyin(ep->ev_name, addr, strlen(ep->ev_name));
152 addr += strlen(ep->ev_name);
153 archsw.arch_copyin("=", addr, 1);
154 addr++;
155 if (ep->ev_value != NULL) {
156 archsw.arch_copyin(ep->ev_value, addr,
157 strlen(ep->ev_value));
158 addr += strlen(ep->ev_value);
159 }
160 archsw.arch_copyin("", addr, 1);
161 addr++;
155 }
156 archsw.arch_copyin("", addr, 1);
157 addr++;
162 }
163 archsw.arch_copyin("", addr, 1);
164 addr++;
158 }
159 archsw.arch_copyin("", addr, 1);
160 addr++;
161 return(addr);
165 return(addr);
162}
163
164/*
165 * Copy module-related data into the load area, where it can be
166 * used as a directory for loaded modules.
167 *
168 * Module data is presented in a self-describing format. Each datum
169 * is preceded by a 32-bit identifier and a 32-bit size field.
170 *
171 * Currently, the following data are saved:
172 *
173 * MOD_NAME (variable) module name (string)
174 * MOD_TYPE (variable) module type (string)
175 * MOD_ARGS (variable) module parameters (string)
176 * MOD_ADDR sizeof(vm_offset_t) module load address
177 * MOD_SIZE sizeof(size_t) module size
178 * MOD_METADATA (variable) type-specific metadata
179 */
166}
167
168/*
169 * Copy module-related data into the load area, where it can be
170 * used as a directory for loaded modules.
171 *
172 * Module data is presented in a self-describing format. Each datum
173 * is preceded by a 32-bit identifier and a 32-bit size field.
174 *
175 * Currently, the following data are saved:
176 *
177 * MOD_NAME (variable) module name (string)
178 * MOD_TYPE (variable) module type (string)
179 * MOD_ARGS (variable) module parameters (string)
180 * MOD_ADDR sizeof(vm_offset_t) module load address
181 * MOD_SIZE sizeof(size_t) module size
182 * MOD_METADATA (variable) type-specific metadata
183 */
180#define COPY32(v, a, c) { \
184#define COPY32(v, a, c) { \
181 u_int32_t x = (v); \
182 if (c) \
185 u_int32_t x = (v); \
186 if (c) \
183 archsw.arch_copyin(&x, a, sizeof(x)); \
187 archsw.arch_copyin(&x, a, sizeof(x)); \
184 a += sizeof(x); \
185}
186
188 a += sizeof(x); \
189}
190
187#define MOD_STR(t, a, s, c) { \
191#define MOD_STR(t, a, s, c) { \
188 COPY32(t, a, c); \
189 COPY32(strlen(s) + 1, a, c) \
190 if (c) \
192 COPY32(t, a, c); \
193 COPY32(strlen(s) + 1, a, c) \
194 if (c) \
191 archsw.arch_copyin(s, a, strlen(s) + 1);\
195 archsw.arch_copyin(s, a, strlen(s) + 1);\
192 a += roundup(strlen(s) + 1, sizeof(u_long));\
193}
194
196 a += roundup(strlen(s) + 1, sizeof(u_long));\
197}
198
195#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c)
196#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c)
197#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c)
199#define MOD_NAME(a, s, c) MOD_STR(MODINFO_NAME, a, s, c)
200#define MOD_TYPE(a, s, c) MOD_STR(MODINFO_TYPE, a, s, c)
201#define MOD_ARGS(a, s, c) MOD_STR(MODINFO_ARGS, a, s, c)
198
202
199#define MOD_VAR(t, a, s, c) { \
203#define MOD_VAR(t, a, s, c) { \
200 COPY32(t, a, c); \
201 COPY32(sizeof(s), a, c); \
202 if (c) \
204 COPY32(t, a, c); \
205 COPY32(sizeof(s), a, c); \
206 if (c) \
203 archsw.arch_copyin(&s, a, sizeof(s)); \
207 archsw.arch_copyin(&s, a, sizeof(s)); \
204 a += roundup(sizeof(s), sizeof(u_long)); \
205}
206
208 a += roundup(sizeof(s), sizeof(u_long)); \
209}
210
207#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c)
208#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c)
211#define MOD_ADDR(a, s, c) MOD_VAR(MODINFO_ADDR, a, s, c)
212#define MOD_SIZE(a, s, c) MOD_VAR(MODINFO_SIZE, a, s, c)
209
213
210#define MOD_METADATA(a, mm, c) { \
214#define MOD_METADATA(a, mm, c) { \
211 COPY32(MODINFO_METADATA | mm->md_type, a, c);\
212 COPY32(mm->md_size, a, c); \
213 if (c) \
215 COPY32(MODINFO_METADATA | mm->md_type, a, c);\
216 COPY32(mm->md_size, a, c); \
217 if (c) \
214 archsw.arch_copyin(mm->md_data, a, mm->md_size);\
218 archsw.arch_copyin(mm->md_data, a, mm->md_size);\
215 a += roundup(mm->md_size, sizeof(u_long)); \
216}
217
219 a += roundup(mm->md_size, sizeof(u_long)); \
220}
221
218#define MOD_END(a, c) { \
222#define MOD_END(a, c) { \
219 COPY32(MODINFO_END, a, c); \
220 COPY32(0, a, c); \
221}
222
223static vm_offset_t
224md_copymodules(vm_offset_t addr)
225{
223 COPY32(MODINFO_END, a, c); \
224 COPY32(0, a, c); \
225}
226
227static vm_offset_t
228md_copymodules(vm_offset_t addr)
229{
226 struct preloaded_file *fp;
227 struct file_metadata *md;
228 int c;
230 struct preloaded_file *fp;
231 struct file_metadata *md;
232 int c;
229
233
230 c = addr != 0;
231 /* start with the first module on the list, should be the kernel */
232 for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
234 c = addr != 0;
235 /* start with the first module on the list, should be the kernel */
236 for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
233
237
234 MOD_NAME(addr, fp->f_name, c); /* this field must come first */
235 MOD_TYPE(addr, fp->f_type, c);
236 if (fp->f_args)
237 MOD_ARGS(addr, fp->f_args, c);
238 MOD_ADDR(addr, fp->f_addr, c);
239 MOD_SIZE(addr, fp->f_size, c);
240 for (md = fp->f_metadata; md != NULL; md = md->md_next) {
241 if (!(md->md_type & MODINFOMD_NOCOPY)) {
242 MOD_METADATA(addr, md, c);
243 }
238 MOD_NAME(addr, fp->f_name, c); /* this field must be first */
239 MOD_TYPE(addr, fp->f_type, c);
240 if (fp->f_args)
241 MOD_ARGS(addr, fp->f_args, c);
242 MOD_ADDR(addr, fp->f_addr, c);
243 MOD_SIZE(addr, fp->f_size, c);
244 for (md = fp->f_metadata; md != NULL; md = md->md_next) {
245 if (!(md->md_type & MODINFOMD_NOCOPY))
246 MOD_METADATA(addr, md, c);
247 }
244 }
248 }
245 }
246 MOD_END(addr, c);
247 return(addr);
249 MOD_END(addr, c);
250 return(addr);
248}
249
250/*
251 * Prepare the bootinfo structure. Put a ptr to the allocated struct in addr,
252 * return size.
253 */
254static int
255md_bootinfo(struct bootinfo **addr)
256{
251}
252
253/*
254 * Prepare the bootinfo structure. Put a ptr to the allocated struct in addr,
255 * return size.
256 */
257static int
258md_bootinfo(struct bootinfo **addr)
259{
257#define TMP_MAX_ETH 8
258#define TMP_MAX_MR 8
260#define TMP_MAX_ETH 8
261#define TMP_MAX_MR 8
259 struct bootinfo *bi;
260 struct bi_mem_region tmp_mr[TMP_MAX_MR];
261 struct bi_eth_addr tmp_eth[TMP_MAX_ETH];
262 struct sys_info *si;
263 char *str, *end;
264 const char *env;
265 void *ptr;
266 u_int8_t tmp_addr[6];

--- 75 unchanged lines hidden (view full) ---

342 * - The 'boothowto' argument is constructed
343 * - The 'bootdev' argument is constructed
344 * - The kernel environment is copied into kernel space.
345 * - Module metadata are formatted and placed in kernel space.
346 */
347int
348md_load(char *args, vm_offset_t *modulep)
349{
262 struct bootinfo *bi;
263 struct bi_mem_region tmp_mr[TMP_MAX_MR];
264 struct bi_eth_addr tmp_eth[TMP_MAX_ETH];
265 struct sys_info *si;
266 char *str, *end;
267 const char *env;
268 void *ptr;
269 u_int8_t tmp_addr[6];

--- 75 unchanged lines hidden (view full) ---

345 * - The 'boothowto' argument is constructed
346 * - The 'bootdev' argument is constructed
347 * - The kernel environment is copied into kernel space.
348 * - Module metadata are formatted and placed in kernel space.
349 */
350int
351md_load(char *args, vm_offset_t *modulep)
352{
350 struct preloaded_file *kfp;
351 struct preloaded_file *xp;
352 struct file_metadata *md;
353 struct bootinfo *bip;
354 vm_offset_t kernend;
355 vm_offset_t addr;
356 vm_offset_t envp;
357 vm_offset_t size;
358 vm_offset_t vaddr;
359 char *rootdevname;
360 int howto;
361 int bisize;
362 int i;
353 struct preloaded_file *kfp;
354 struct preloaded_file *xp;
355 struct file_metadata *md;
356 struct bootinfo *bip;
357 vm_offset_t kernend;
358 vm_offset_t addr;
359 vm_offset_t envp;
360 vm_offset_t size;
361 vm_offset_t vaddr;
362 char *rootdevname;
363 int howto;
364 int bisize;
365 int i;
363
366
364 /* This metadata addreses must be converted for kernel after relocation */
365 uint32_t mdt[] = { MODINFOMD_SSYM, MODINFOMD_ESYM,
366 MODINFOMD_KERNEND, MODINFOMD_ENVP };
367 /*
368 * These metadata addreses must be converted for kernel after
369 * relocation.
370 */
371 uint32_t mdt[] = {
372 MODINFOMD_SSYM, MODINFOMD_ESYM, MODINFOMD_KERNEND, MODINFOMD_ENVP
373 };
367
374
368 howto = md_getboothowto(args);
375 howto = md_getboothowto(args);
369
376
370 /*
371 * Allow the environment variable 'rootdev' to override the supplied device
372 * This should perhaps go to MI code and/or have $rootdev tested/set by
373 * MI code before launching the kernel.
374 */
375 rootdevname = getenv("rootdev");
376 if (rootdevname == NULL)
377 rootdevname = getenv("currdev");
378 /* Try reading the /etc/fstab file to select the root device */
379 getrootmount(rootdevname);
377 /*
378 * Allow the environment variable 'rootdev' to override the supplied
379 * device. This should perhaps go to MI code and/or have $rootdev
380 * tested/set by MI code before launching the kernel.
381 */
382 rootdevname = getenv("rootdev");
383 if (rootdevname == NULL)
384 rootdevname = getenv("currdev");
385 /* Try reading the /etc/fstab file to select the root device */
386 getrootmount(rootdevname);
380
387
381 /* find the last module in the chain */
382 addr = 0;
383 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
384 if (addr < (xp->f_addr + xp->f_size))
385 addr = xp->f_addr + xp->f_size;
386 }
387 /* pad to a page boundary */
388 addr = roundup(addr, PAGE_SIZE);
388 /* find the last module in the chain */
389 addr = 0;
390 for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
391 if (addr < (xp->f_addr + xp->f_size))
392 addr = xp->f_addr + xp->f_size;
393 }
394 /* pad to a page boundary */
395 addr = roundup(addr, PAGE_SIZE);
389
396
390 /* copy our environment */
391 envp = addr;
392 addr = md_copyenv(addr);
397 /* copy our environment */
398 envp = addr;
399 addr = md_copyenv(addr);
393
400
394 /* pad to a page boundary */
395 addr = roundup(addr, PAGE_SIZE);
401 /* pad to a page boundary */
402 addr = roundup(addr, PAGE_SIZE);
396
403
397 /* prepare bootinfo */
398 bisize = md_bootinfo(&bip);
404 /* prepare bootinfo */
405 bisize = md_bootinfo(&bip);
399
406
400 kernend = 0;
401 kfp = file_findfile(NULL, "elf32 kernel");
402 if (kfp == NULL)
403 kfp = file_findfile(NULL, "elf kernel");
404 if (kfp == NULL)
405 panic("can't find kernel file");
406 file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
407 file_addmetadata(kfp, MODINFOMD_BOOTINFO, bisize, bip);
408 file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
409 file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
407 kernend = 0;
408 kfp = file_findfile(NULL, "elf32 kernel");
409 if (kfp == NULL)
410 kfp = file_findfile(NULL, "elf kernel");
411 if (kfp == NULL)
412 panic("can't find kernel file");
413 file_addmetadata(kfp, MODINFOMD_HOWTO, sizeof howto, &howto);
414 file_addmetadata(kfp, MODINFOMD_BOOTINFO, bisize, bip);
415 file_addmetadata(kfp, MODINFOMD_ENVP, sizeof envp, &envp);
416 file_addmetadata(kfp, MODINFOMD_KERNEND, sizeof kernend, &kernend);
410
417
411 *modulep = addr;
412 size = md_copymodules(0);
413 kernend = roundup(addr + size, PAGE_SIZE);
418 *modulep = addr;
419 size = md_copymodules(0);
420 kernend = roundup(addr + size, PAGE_SIZE);
414
421
415 md = file_findmetadata(kfp, MODINFOMD_KERNEND);
416 bcopy(&kernend, md->md_data, sizeof kernend);
422 md = file_findmetadata(kfp, MODINFOMD_KERNEND);
423 bcopy(&kernend, md->md_data, sizeof kernend);
417
424
418 /* Convert addresses to the final VA */
419 *modulep -= __elfN(relocation_offset);
425 /* Convert addresses to the final VA */
426 *modulep -= __elfN(relocation_offset);
420
427
421 for (i = 0; i < sizeof mdt / sizeof mdt[0]; i++) {
422 md = file_findmetadata(kfp, mdt[i]);
423 if (md) {
424 bcopy(md->md_data, &vaddr, sizeof vaddr);
425 vaddr -= __elfN(relocation_offset);
426 bcopy(&vaddr, md->md_data, sizeof vaddr);
427 }
428 }
429 (void)md_copymodules(addr);
428 for (i = 0; i < sizeof mdt / sizeof mdt[0]; i++) {
429 md = file_findmetadata(kfp, mdt[i]);
430 if (md) {
431 bcopy(md->md_data, &vaddr, sizeof vaddr);
432 vaddr -= __elfN(relocation_offset);
433 bcopy(&vaddr, md->md_data, sizeof vaddr);
434 }
435 }
436 (void)md_copymodules(addr);
430
437
431 return(0);
438 return(0);
432}
439}