]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/boot/ia64/common/bootinfo.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / boot / ia64 / common / bootinfo.c
1 /*-
2  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3  * Copyright (c) 2006 Marcel Moolenaar
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:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
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$");
30
31 #include <stand.h>
32 #include <string.h>
33 #include <sys/param.h>
34 #include <sys/reboot.h>
35 #include <sys/linker.h>
36
37 #include <efi.h>
38 #include <efilib.h>
39
40 #include "libia64.h"
41
42 /*
43  * Return a 'boothowto' value corresponding to the kernel arguments in
44  * (kargs) and any relevant environment variables.
45  */
46 static struct 
47 {
48         const char      *ev;
49         int             mask;
50 } howto_names[] = {
51         { "boot_askname",       RB_ASKNAME},
52         { "boot_cdrom",         RB_CDROM},
53         { "boot_ddb",           RB_KDB},
54         { "boot_dfltroot",      RB_DFLTROOT},
55         { "boot_gdb",           RB_GDB},
56         { "boot_multicons",     RB_MULTIPLE},
57         { "boot_mute",          RB_MUTE},
58         { "boot_pause",         RB_PAUSE},
59         { "boot_serial",        RB_SERIAL},
60         { "boot_single",        RB_SINGLE},
61         { "boot_verbose",       RB_VERBOSE},
62         { NULL, 0}
63 };
64
65 static const char howto_switches[] = "aCdrgDmphsv";
66 static int howto_masks[] = {
67         RB_ASKNAME, RB_CDROM, RB_KDB, RB_DFLTROOT, RB_GDB, RB_MULTIPLE,
68         RB_MUTE, RB_PAUSE, RB_SERIAL, RB_SINGLE, RB_VERBOSE
69 };
70
71 int
72 bi_getboothowto(char *kargs)
73 {
74         const char *sw;
75         char *opts;
76         int howto, i;
77
78         howto = 0;
79
80         /* Get the boot options from the environment first. */
81         for (i = 0; howto_names[i].ev != NULL; i++) {
82                 if (getenv(howto_names[i].ev) != NULL)
83                         howto |= howto_names[i].mask;
84         }
85
86         /* Parse kargs */
87         if (kargs == NULL)
88                 return (howto);
89
90         opts = strchr(kargs, '-');
91         while (opts != NULL) {
92                 while (*(++opts) != '\0') {
93                         sw = strchr(howto_switches, *opts);
94                         if (sw == NULL)
95                                 break;
96                         howto |= howto_masks[sw - howto_switches];
97                 }
98                 opts = strchr(opts, '-');
99         }
100
101         return (howto);
102 }
103
104 /*
105  * Copy the environment into the load area starting at (addr).
106  * Each variable is formatted as <name>=<value>, with a single nul
107  * separating each variable, and a double nul terminating the environment.
108  */
109 vm_offset_t
110 bi_copyenv(vm_offset_t start)
111 {
112         struct env_var *ep;
113         vm_offset_t addr, last;
114         size_t len;
115
116         addr = last = start;
117
118         /* Traverse the environment. */
119         for (ep = environ; ep != NULL; ep = ep->ev_next) {
120                 len = strlen(ep->ev_name);
121                 if (ia64_copyin(ep->ev_name, addr, len) != len)
122                         break;
123                 addr += len;
124                 if (ia64_copyin("=", addr, 1) != 1)
125                         break;
126                 addr++;
127                 if (ep->ev_value != NULL) {
128                         len = strlen(ep->ev_value);
129                         if (ia64_copyin(ep->ev_value, addr, len) != len)
130                                 break;
131                         addr += len;
132                 }
133                 if (ia64_copyin("", addr, 1) != 1)
134                         break;
135                 last = ++addr;
136         }
137
138         if (ia64_copyin("", last++, 1) != 1)
139                 last = start;
140         return(last);
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 preceded 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_ARGS     (variable)              module parameters (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     ia64_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     ia64_copyin(s, a, strlen(s) + 1);           \
169     a += roundup(strlen(s) + 1, sizeof(u_int64_t));\
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 #define MOD_ARGS(a, s)  MOD_STR(MODINFO_ARGS, a, s)
175
176 #define MOD_VAR(t, a, s) {                      \
177     COPY32(t, a);                               \
178     COPY32(sizeof(s), a);                       \
179     ia64_copyin(&s, a, sizeof(s));              \
180     a += roundup(sizeof(s), sizeof(u_int64_t)); \
181 }
182
183 #define MOD_ADDR(a, s)  MOD_VAR(MODINFO_ADDR, a, s)
184 #define MOD_SIZE(a, s)  MOD_VAR(MODINFO_SIZE, a, s)
185
186 #define MOD_METADATA(a, mm) {                   \
187     COPY32(MODINFO_METADATA | mm->md_type, a);  \
188     COPY32(mm->md_size, a);                     \
189     ia64_copyin(mm->md_data, a, mm->md_size);   \
190     a += roundup(mm->md_size, sizeof(u_int64_t));\
191 }
192
193 #define MOD_END(a) {                            \
194     COPY32(MODINFO_END, a);                     \
195     COPY32(0, a);                               \
196 }
197
198 vm_offset_t
199 bi_copymodules(vm_offset_t addr)
200 {
201         struct preloaded_file *fp;
202         struct file_metadata *md;
203
204         /* Start with the first module on the list, should be the kernel. */
205         for (fp = file_findfile(NULL, NULL); fp != NULL; fp = fp->f_next) {
206                 /* The name field must come first. */
207                 MOD_NAME(addr, fp->f_name);
208                 MOD_TYPE(addr, fp->f_type);
209                 if (fp->f_args)
210                         MOD_ARGS(addr, fp->f_args);
211                 MOD_ADDR(addr, fp->f_addr);
212                 MOD_SIZE(addr, fp->f_size);
213                 for (md = fp->f_metadata; md != NULL; md = md->md_next) {
214                         if (!(md->md_type & MODINFOMD_NOCOPY))
215                                 MOD_METADATA(addr, md);
216                 }
217         }
218         MOD_END(addr);
219         return(addr);
220 }
221
222 /*
223  * Load the information expected by the kernel.
224  *
225  * - The kernel environment is copied into kernel space.
226  * - Module metadata are formatted and placed in kernel space.
227  */
228 int
229 ia64_bootinfo(struct preloaded_file *fp, struct bootinfo **res)
230 {
231         struct bootinfo bi;
232         struct preloaded_file *xp;
233         struct file_metadata *md;
234         struct devdesc *rootdev;
235         char *rootdevname;
236         vm_offset_t addr, ssym, esym;
237         int error;
238
239         *res = NULL;
240         bzero(&bi, sizeof(struct bootinfo));
241         bi.bi_magic = BOOTINFO_MAGIC;
242         bi.bi_version = 1;
243         bi.bi_boothowto = bi_getboothowto(fp->f_args);
244
245         /* 
246          * Allow the environment variable 'rootdev' to override the supplied
247          * device. This should perhaps go to MI code and/or have $rootdev
248          * tested/set by MI code before launching the kernel.
249          */
250         rootdevname = getenv("rootdev");
251         ia64_getdev((void**)&rootdev, rootdevname, NULL);
252         if (rootdev != NULL) {
253                 /* Try reading /etc/fstab to select the root device. */
254                 getrootmount(ia64_fmtdev(rootdev));
255                 free(rootdev);
256         }
257
258         md = file_findmetadata(fp, MODINFOMD_SSYM);
259         ssym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0;
260         md = file_findmetadata(fp, MODINFOMD_ESYM);
261         esym = (md != NULL) ? *((vm_offset_t *)&(md->md_data)) : 0;
262         if (ssym != 0 && esym != 0) {
263                 bi.bi_symtab = ssym;
264                 bi.bi_esymtab = esym;
265         }
266
267         /* Find the last module in the chain. */
268         addr = 0;
269         for (xp = file_findfile(NULL, NULL); xp != NULL; xp = xp->f_next) {
270                 if (addr < (xp->f_addr + xp->f_size))
271                         addr = xp->f_addr + xp->f_size;
272         }
273
274         addr = (addr + 15) & ~15;
275
276         /* Copy module list and metadata. */
277         bi.bi_modulep = addr;
278         addr = bi_copymodules(addr);
279         if (addr <= bi.bi_modulep) {
280                 addr = bi.bi_modulep;
281                 bi.bi_modulep = 0;
282         }
283
284         addr = (addr + 15) & ~15;
285
286         /* Copy our environment. */
287         bi.bi_envp = addr;
288         addr = bi_copyenv(addr);
289         if (addr <= bi.bi_envp) {
290                 addr = bi.bi_envp;
291                 bi.bi_envp = 0;
292         }
293
294         addr = (addr + 15) & ~15;
295         bi.bi_kernend = addr;
296
297         error = ia64_platform_bootinfo(&bi, res);
298         if (error)
299                 return (error);
300
301         if (IS_LEGACY_KERNEL()) {
302                 if (*res == NULL)
303                         return (EDOOFUS);
304
305                 bcopy(&bi, *res, sizeof(bi));
306                 return (0);
307         }
308
309         bi.bi_pbvm_pgtbl = (uintptr_t)ia64_pgtbl;
310         bi.bi_pbvm_pgtblsz = ia64_pgtblsz;
311         ia64_copyin((void *)bi.bi_memmap, addr, bi.bi_memmap_size);
312         bi.bi_memmap = addr;
313         addr = (addr + bi.bi_memmap_size + 15) & ~15;
314         bi.bi_kernend = addr + sizeof(bi);      
315         ia64_copyin(&bi, addr, sizeof(bi));
316         *res = (void *)addr;
317         return (0);
318 }