Deleted Added
full compact
bootinfo32.c (40107) bootinfo32.c (40146)
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
1/*-
2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id: bootinfo.c,v 1.10 1998/10/07 10:55:46 peter Exp $
26 * $Id: bootinfo.c,v 1.11 1998/10/09 07:11:19 msmith Exp $
27 */
28
29#include <stand.h>
30#include <sys/param.h>
31#include <sys/reboot.h>
27 */
28
29#include <stand.h>
30#include <sys/param.h>
31#include <sys/reboot.h>
32#include <sys/linker.h>
32#include <machine/bootinfo.h>
33#include "bootstrap.h"
34#include "libi386.h"
35#include "btxv86.h"
36
37static struct bootinfo bi;
38
39/*
40 * Return a 'boothowto' value corresponding to the kernel arguments in
41 * (kargs) and any relevant environment variables.
42 */
43static struct
44{
45 char *ev;
46 int mask;
47} howto_names[] = {
48 {"boot_askname", RB_ASKNAME},
49 {"boot_userconfig", RB_CONFIG},
50 {"boot_ddb", RB_KDB},
51 {"boot_gdb", RB_GDB},
52 {"boot_single", RB_SINGLE},
53 {"boot_verbose", RB_VERBOSE},
54 {NULL, 0}
55};
56
57int
58bi_getboothowto(char *kargs)
59{
60 char *cp;
61 int howto;
62 int active;
63 int i;
64
65 /* Parse kargs */
66 howto = 0;
67 if (kargs != NULL) {
68 cp = kargs;
69 active = 0;
70 while (*cp != 0) {
71 if (!active && (*cp == '-')) {
72 active = 1;
73 } else if (active)
74 switch (*cp) {
75 case 'a':
76 howto |= RB_ASKNAME;
77 break;
78 case 'c':
79 howto |= RB_CONFIG;
80 break;
81 case 'd':
82 howto |= RB_KDB;
83 break;
84 case 'g':
85 howto |= RB_GDB;
86 break;
87 case 'h':
88 howto |= RB_SERIAL;
89 break;
90 case 'r':
91 howto |= RB_DFLTROOT;
92 break;
93 case 's':
94 howto |= RB_SINGLE;
95 break;
96 case 'v':
97 howto |= RB_VERBOSE;
98 break;
99 default:
100 active = 0;
101 break;
102 }
103 cp++;
104 }
105 }
106 /* get equivalents from the environment */
107 for (i = 0; howto_names[i].ev != NULL; i++)
108 if (getenv(howto_names[i].ev) != NULL)
109 howto |= howto_names[i].mask;
110 if (!strcmp(getenv("console"), "comconsole"))
111 howto |= RB_SERIAL;
112 return(howto);
113}
114
115/*
116 * Copy the environment into the load area starting at (addr).
117 * Each variable is formatted as <name>=<value>, with a single nul
118 * separating each variable, and a double nul terminating the environment.
119 */
120vm_offset_t
121bi_copyenv(vm_offset_t addr)
122{
123 struct env_var *ep;
124
125 /* traverse the environment */
126 for (ep = environ; ep != NULL; ep = ep->ev_next) {
127 i386_copyin(ep->ev_name, addr, strlen(ep->ev_name));
128 addr += strlen(ep->ev_name);
129 i386_copyin("=", addr, 1);
130 addr++;
131 if (ep->ev_value != NULL) {
132 i386_copyin(ep->ev_value, addr, strlen(ep->ev_value));
133 addr += strlen(ep->ev_value);
134 }
135 i386_copyin("", addr, 1);
136 addr++;
137 }
138 i386_copyin("", addr, 1);
139 addr++;
140 return(addr);
141}
142
143/*
144 * Copy module-related data into the load area, where it can be
145 * used as a directory for loaded modules.
146 *
147 * Module data is presented in a self-describing format. Each datum
148 * is preceeded by a 32-bit identifier and a 32-bit size field.
149 *
150 * Currently, the following data are saved:
151 *
152 * MOD_NAME (variable) module name (string)
153 * MOD_TYPE (variable) module type (string)
154 * MOD_ADDR sizeof(vm_offset_t) module load address
155 * MOD_SIZE sizeof(size_t) module size
156 * MOD_METADATA (variable) type-specific metadata
157 */
158#define COPY32(v, a) { \
159 u_int32_t x = (v); \
160 i386_copyin(&x, a, sizeof(x)); \
161 a += sizeof(x); \
162}
163
164#define MOD_STR(t, a, s) { \
165 COPY32(t, a); \
166 COPY32(strlen(s) + 1, a); \
167 i386_copyin(s, a, strlen(s) + 1); \
33#include <machine/bootinfo.h>
34#include "bootstrap.h"
35#include "libi386.h"
36#include "btxv86.h"
37
38static struct bootinfo bi;
39
40/*
41 * Return a 'boothowto' value corresponding to the kernel arguments in
42 * (kargs) and any relevant environment variables.
43 */
44static struct
45{
46 char *ev;
47 int mask;
48} howto_names[] = {
49 {"boot_askname", RB_ASKNAME},
50 {"boot_userconfig", RB_CONFIG},
51 {"boot_ddb", RB_KDB},
52 {"boot_gdb", RB_GDB},
53 {"boot_single", RB_SINGLE},
54 {"boot_verbose", RB_VERBOSE},
55 {NULL, 0}
56};
57
58int
59bi_getboothowto(char *kargs)
60{
61 char *cp;
62 int howto;
63 int active;
64 int i;
65
66 /* Parse kargs */
67 howto = 0;
68 if (kargs != NULL) {
69 cp = kargs;
70 active = 0;
71 while (*cp != 0) {
72 if (!active && (*cp == '-')) {
73 active = 1;
74 } else if (active)
75 switch (*cp) {
76 case 'a':
77 howto |= RB_ASKNAME;
78 break;
79 case 'c':
80 howto |= RB_CONFIG;
81 break;
82 case 'd':
83 howto |= RB_KDB;
84 break;
85 case 'g':
86 howto |= RB_GDB;
87 break;
88 case 'h':
89 howto |= RB_SERIAL;
90 break;
91 case 'r':
92 howto |= RB_DFLTROOT;
93 break;
94 case 's':
95 howto |= RB_SINGLE;
96 break;
97 case 'v':
98 howto |= RB_VERBOSE;
99 break;
100 default:
101 active = 0;
102 break;
103 }
104 cp++;
105 }
106 }
107 /* get equivalents from the environment */
108 for (i = 0; howto_names[i].ev != NULL; i++)
109 if (getenv(howto_names[i].ev) != NULL)
110 howto |= howto_names[i].mask;
111 if (!strcmp(getenv("console"), "comconsole"))
112 howto |= RB_SERIAL;
113 return(howto);
114}
115
116/*
117 * Copy the environment into the load area starting at (addr).
118 * Each variable is formatted as <name>=<value>, with a single nul
119 * separating each variable, and a double nul terminating the environment.
120 */
121vm_offset_t
122bi_copyenv(vm_offset_t addr)
123{
124 struct env_var *ep;
125
126 /* traverse the environment */
127 for (ep = environ; ep != NULL; ep = ep->ev_next) {
128 i386_copyin(ep->ev_name, addr, strlen(ep->ev_name));
129 addr += strlen(ep->ev_name);
130 i386_copyin("=", addr, 1);
131 addr++;
132 if (ep->ev_value != NULL) {
133 i386_copyin(ep->ev_value, addr, strlen(ep->ev_value));
134 addr += strlen(ep->ev_value);
135 }
136 i386_copyin("", addr, 1);
137 addr++;
138 }
139 i386_copyin("", addr, 1);
140 addr++;
141 return(addr);
142}
143
144/*
145 * Copy module-related data into the load area, where it can be
146 * used as a directory for loaded modules.
147 *
148 * Module data is presented in a self-describing format. Each datum
149 * is preceeded by a 32-bit identifier and a 32-bit size field.
150 *
151 * Currently, the following data are saved:
152 *
153 * MOD_NAME (variable) module name (string)
154 * MOD_TYPE (variable) module type (string)
155 * MOD_ADDR sizeof(vm_offset_t) module load address
156 * MOD_SIZE sizeof(size_t) module size
157 * MOD_METADATA (variable) type-specific metadata
158 */
159#define COPY32(v, a) { \
160 u_int32_t x = (v); \
161 i386_copyin(&x, a, sizeof(x)); \
162 a += sizeof(x); \
163}
164
165#define MOD_STR(t, a, s) { \
166 COPY32(t, a); \
167 COPY32(strlen(s) + 1, a); \
168 i386_copyin(s, a, strlen(s) + 1); \
168 a += strlen(s) + 1; \
169 a += roundup(strlen(s) + 1, sizeof(u_int32_t));\
169}
170
171#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s)
172#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s)
173
174#define MOD_VAR(t, a, s) { \
175 COPY32(t, a); \
176 COPY32(sizeof(s), a); \
177 i386_copyin(&s, a, sizeof(s)); \
170}
171
172#define MOD_NAME(a, s) MOD_STR(MODINFO_NAME, a, s)
173#define MOD_TYPE(a, s) MOD_STR(MODINFO_TYPE, a, s)
174
175#define MOD_VAR(t, a, s) { \
176 COPY32(t, a); \
177 COPY32(sizeof(s), a); \
178 i386_copyin(&s, a, sizeof(s)); \
178 a += sizeof(s); \
179 a += roundup(sizeof(s), sizeof(u_int32_t)); \
179}
180
181#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s)
182#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s)
183
184#define MOD_METADATA(a, mm) { \
185 COPY32(MODINFO_METADATA | mm->md_type, a); \
186 COPY32(mm->md_size, a); \
187 i386_copyin(mm->md_data, a, mm->md_size); \
180}
181
182#define MOD_ADDR(a, s) MOD_VAR(MODINFO_ADDR, a, s)
183#define MOD_SIZE(a, s) MOD_VAR(MODINFO_SIZE, a, s)
184
185#define MOD_METADATA(a, mm) { \
186 COPY32(MODINFO_METADATA | mm->md_type, a); \
187 COPY32(mm->md_size, a); \
188 i386_copyin(mm->md_data, a, mm->md_size); \
188 a += mm->md_size; \
189 a += roundup(mm->md_size, sizeof(u_int32_t));\
189}
190
191#define MOD_END(a) { \
192 COPY32(MODINFO_END, a); \
193 COPY32(0, a); \
194}
195
196vm_offset_t
197bi_copymodules(vm_offset_t addr)
198{
199 struct loaded_module *mp;
200 struct module_metadata *md;
201
202 /* start with the first module on the list, should be the kernel */
203 for (mp = mod_findmodule(NULL, NULL); mp != NULL; mp = mp->m_next) {
190}
191
192#define MOD_END(a) { \
193 COPY32(MODINFO_END, a); \
194 COPY32(0, a); \
195}
196
197vm_offset_t
198bi_copymodules(vm_offset_t addr)
199{
200 struct loaded_module *mp;
201 struct module_metadata *md;
202
203 /* start with the first module on the list, should be the kernel */
204 for (mp = mod_findmodule(NULL, NULL); mp != NULL; mp = mp->m_next) {
204
205
205 MOD_NAME(addr, mp->m_name); /* this field must come first */
206 MOD_TYPE(addr, mp->m_type);
207 MOD_ADDR(addr, mp->m_addr);
208 MOD_SIZE(addr, mp->m_size);
209 for (md = mp->m_metadata; md != NULL; md = md->md_next)
210 if (!(md->md_type & MODINFOMD_NOCOPY))
211 MOD_METADATA(addr, md);
212 }
213 MOD_END(addr);
214 return(addr);
215}
216
217/*
218 * Load the information expected by an i386 kernel.
219 *
220 * - The 'boothowto' argument is constructed
221 * - The 'botdev' argument is constructed
222 * - The 'bootinfo' struct is constructed, and copied into the kernel space.
223 * - The kernel environment is copied into kernel space.
224 * - Module metadata are formatted and placed in kernel space.
225 */
226int
227bi_load(char *args, int *howtop, int *bootdevp, vm_offset_t *bip)
228{
229 struct loaded_module *xp;
230 struct i386_devdesc *rootdev;
231 vm_offset_t addr, bootinfo_addr;
232 char *rootdevname;
233 int bootdevnr;
234 u_int pad;
235 char *kernelname;
236 const char *kernelpath;
237
238 *howtop = bi_getboothowto(args);
239
240 /*
241 * Allow the environment variable 'rootdev' to override the supplied device
242 * This should perhaps go to MI code and/or have $rootdev tested/set by
243 * MI code before launching the kernel.
244 */
245 rootdevname = getenv("rootdev");
246 i386_getdev((void **)(&rootdev), rootdevname, NULL);
247 if (rootdev == NULL) { /* bad $rootdev/$currdev */
248 printf("can't determine root device\n");
249 return(EINVAL);
250 }
251
252 /* Boot from whatever the current device is */
253 i386_getdev((void **)(&rootdev), NULL, NULL);
254 switch(rootdev->d_type) {
255 case DEVT_DISK:
256 /* pass in the BIOS device number of the current disk */
257 bi.bi_bios_dev = bd_unit2bios(rootdev->d_kind.biosdisk.unit);
258 bootdevnr = bd_getdev(rootdev);
259 break;
260
261 default:
262 printf("aout_exec: WARNING - don't know how to boot from device type %d\n", rootdev->d_type);
263 }
264 free(rootdev);
265 *bootdevp = bootdevnr;
266
267 /* legacy bootinfo structure */
268 bi.bi_version = BOOTINFO_VERSION;
269 bi.bi_kernelname = 0; /* XXX char * -> kernel name */
270 bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */
271 bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */
272 /* bi.bi_bios_geom[] */
273 bi.bi_size = sizeof(bi);
274 bi.bi_memsizes_valid = 1;
275 bi.bi_basemem = getbasemem();
276 bi.bi_extmem = getextmem();
277
278 /* find the last module in the chain */
279 for (xp = mod_findmodule(NULL, NULL); xp->m_next != NULL; xp = xp->m_next)
280 ;
281 addr = xp->m_addr + xp->m_size;
282 /* pad to a page boundary */
283 pad = (u_int)addr & PAGE_MASK;
284 if (pad != 0) {
285 pad = PAGE_SIZE - pad;
286 addr += pad;
287 }
288
289 /* copy our environment */
290 bi.bi_envp = addr;
291 addr = bi_copyenv(addr);
292
293 /* pad to a page boundary */
294 pad = (u_int)addr & PAGE_MASK;
295 if (pad != 0) {
296 pad = PAGE_SIZE - pad;
297 addr += pad;
298 }
299 /* copy module list and metadata */
300 bi.bi_modulep = addr;
301 addr = bi_copymodules(addr);
302
303 /* all done copying stuff in, save end of loaded object space */
304 bi.bi_kernend = addr;
305
306 *howtop |= RB_BOOTINFO; /* it's there now */
307
308 /*
309 * Get the kernel name, strip off any device prefix.
310 */
311 kernelname = getenv("kernelname");
312 i386_getdev(NULL, kernelname, &kernelpath);
313 bi.bi_kernelname = VTOP(kernelpath);
314 *bip = VTOP(&bi);
315
316 return(0);
317}
206 MOD_NAME(addr, mp->m_name); /* this field must come first */
207 MOD_TYPE(addr, mp->m_type);
208 MOD_ADDR(addr, mp->m_addr);
209 MOD_SIZE(addr, mp->m_size);
210 for (md = mp->m_metadata; md != NULL; md = md->md_next)
211 if (!(md->md_type & MODINFOMD_NOCOPY))
212 MOD_METADATA(addr, md);
213 }
214 MOD_END(addr);
215 return(addr);
216}
217
218/*
219 * Load the information expected by an i386 kernel.
220 *
221 * - The 'boothowto' argument is constructed
222 * - The 'botdev' argument is constructed
223 * - The 'bootinfo' struct is constructed, and copied into the kernel space.
224 * - The kernel environment is copied into kernel space.
225 * - Module metadata are formatted and placed in kernel space.
226 */
227int
228bi_load(char *args, int *howtop, int *bootdevp, vm_offset_t *bip)
229{
230 struct loaded_module *xp;
231 struct i386_devdesc *rootdev;
232 vm_offset_t addr, bootinfo_addr;
233 char *rootdevname;
234 int bootdevnr;
235 u_int pad;
236 char *kernelname;
237 const char *kernelpath;
238
239 *howtop = bi_getboothowto(args);
240
241 /*
242 * Allow the environment variable 'rootdev' to override the supplied device
243 * This should perhaps go to MI code and/or have $rootdev tested/set by
244 * MI code before launching the kernel.
245 */
246 rootdevname = getenv("rootdev");
247 i386_getdev((void **)(&rootdev), rootdevname, NULL);
248 if (rootdev == NULL) { /* bad $rootdev/$currdev */
249 printf("can't determine root device\n");
250 return(EINVAL);
251 }
252
253 /* Boot from whatever the current device is */
254 i386_getdev((void **)(&rootdev), NULL, NULL);
255 switch(rootdev->d_type) {
256 case DEVT_DISK:
257 /* pass in the BIOS device number of the current disk */
258 bi.bi_bios_dev = bd_unit2bios(rootdev->d_kind.biosdisk.unit);
259 bootdevnr = bd_getdev(rootdev);
260 break;
261
262 default:
263 printf("aout_exec: WARNING - don't know how to boot from device type %d\n", rootdev->d_type);
264 }
265 free(rootdev);
266 *bootdevp = bootdevnr;
267
268 /* legacy bootinfo structure */
269 bi.bi_version = BOOTINFO_VERSION;
270 bi.bi_kernelname = 0; /* XXX char * -> kernel name */
271 bi.bi_nfs_diskless = 0; /* struct nfs_diskless * */
272 bi.bi_n_bios_used = 0; /* XXX would have to hook biosdisk driver for these */
273 /* bi.bi_bios_geom[] */
274 bi.bi_size = sizeof(bi);
275 bi.bi_memsizes_valid = 1;
276 bi.bi_basemem = getbasemem();
277 bi.bi_extmem = getextmem();
278
279 /* find the last module in the chain */
280 for (xp = mod_findmodule(NULL, NULL); xp->m_next != NULL; xp = xp->m_next)
281 ;
282 addr = xp->m_addr + xp->m_size;
283 /* pad to a page boundary */
284 pad = (u_int)addr & PAGE_MASK;
285 if (pad != 0) {
286 pad = PAGE_SIZE - pad;
287 addr += pad;
288 }
289
290 /* copy our environment */
291 bi.bi_envp = addr;
292 addr = bi_copyenv(addr);
293
294 /* pad to a page boundary */
295 pad = (u_int)addr & PAGE_MASK;
296 if (pad != 0) {
297 pad = PAGE_SIZE - pad;
298 addr += pad;
299 }
300 /* copy module list and metadata */
301 bi.bi_modulep = addr;
302 addr = bi_copymodules(addr);
303
304 /* all done copying stuff in, save end of loaded object space */
305 bi.bi_kernend = addr;
306
307 *howtop |= RB_BOOTINFO; /* it's there now */
308
309 /*
310 * Get the kernel name, strip off any device prefix.
311 */
312 kernelname = getenv("kernelname");
313 i386_getdev(NULL, kernelname, &kernelpath);
314 bi.bi_kernelname = VTOP(kernelpath);
315 *bip = VTOP(&bi);
316
317 return(0);
318}