]>
Commit | Line | Data |
---|---|---|
a13f9237 | 1 | /* main.c - the kernel main routine */ |
6a161fa9 | 2 | /* |
4b13b216 | 3 | * GRUB -- GRand Unified Bootloader |
58bc8bd5 | 4 | * Copyright (C) 2002,2003,2005,2006,2008,2009 Free Software Foundation, Inc. |
6a161fa9 | 5 | * |
5a79f472 | 6 | * GRUB is free software: you can redistribute it and/or modify |
6a161fa9 | 7 | * it under the terms of the GNU General Public License as published by |
5a79f472 | 8 | * the Free Software Foundation, either version 3 of the License, or |
6a161fa9 | 9 | * (at your option) any later version. |
10 | * | |
5a79f472 | 11 | * GRUB is distributed in the hope that it will be useful, |
6a161fa9 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
5a79f472 | 17 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. |
6a161fa9 | 18 | */ |
19 | ||
4b13b216 | 20 | #include <grub/kernel.h> |
21 | #include <grub/misc.h> | |
4b13b216 | 22 | #include <grub/symbol.h> |
23 | #include <grub/dl.h> | |
24 | #include <grub/term.h> | |
4b13b216 | 25 | #include <grub/file.h> |
26 | #include <grub/device.h> | |
27 | #include <grub/env.h> | |
8d23f507 | 28 | #include <grub/mm.h> |
d558e6b5 | 29 | #include <grub/command.h> |
30 | #include <grub/reader.h> | |
31 | #include <grub/parser.h> | |
6a161fa9 | 32 | |
77468368 VS |
33 | #ifdef GRUB_MACHINE_PCBIOS |
34 | #include <grub/machine/memory.h> | |
35 | #endif | |
36 | ||
a49217cf VS |
37 | grub_addr_t |
38 | grub_modules_get_end (void) | |
39 | { | |
40 | struct grub_module_info *modinfo; | |
a49217cf | 41 | |
39705fad | 42 | modinfo = (struct grub_module_info *) grub_modbase; |
a49217cf VS |
43 | |
44 | /* Check if there are any modules. */ | |
45 | if ((modinfo == 0) || modinfo->magic != GRUB_MODULE_MAGIC) | |
39705fad | 46 | return grub_modbase; |
a49217cf | 47 | |
39705fad | 48 | return grub_modbase + modinfo->size; |
a49217cf | 49 | } |
a49217cf | 50 | |
3bd0a12a | 51 | /* Load all modules in core. */ |
52 | static void | |
53 | grub_load_modules (void) | |
54 | { | |
39705fad VS |
55 | struct grub_module_header *header; |
56 | FOR_MODULES (header) | |
57 | { | |
58 | /* Not an ELF module, skip. */ | |
59 | if (header->type != OBJ_TYPE_ELF) | |
60 | continue; | |
d0780363 | 61 | |
39705fad VS |
62 | if (! grub_dl_load_core ((char *) header + sizeof (struct grub_module_header), |
63 | (header->size - sizeof (struct grub_module_header)))) | |
64 | grub_fatal ("%s", grub_errmsg); | |
6a161fa9 | 65 | |
39705fad VS |
66 | if (grub_errno) |
67 | grub_print_error (); | |
68 | } | |
6a161fa9 | 69 | } |
70 | ||
77468368 VS |
71 | static char *load_config; |
72 | ||
5e898c9d | 73 | static void |
74 | grub_load_config (void) | |
75 | { | |
39705fad VS |
76 | struct grub_module_header *header; |
77 | FOR_MODULES (header) | |
78 | { | |
79 | /* Not an embedded config, skip. */ | |
80 | if (header->type != OBJ_TYPE_CONFIG) | |
81 | continue; | |
77468368 VS |
82 | |
83 | load_config = grub_malloc (header->size - sizeof (struct grub_module_header) + 1); | |
84 | if (!load_config) | |
85 | { | |
86 | grub_print_error (); | |
87 | break; | |
88 | } | |
89 | grub_memcpy (load_config, (char *) header + | |
90 | sizeof (struct grub_module_header), | |
91 | header->size - sizeof (struct grub_module_header)); | |
92 | load_config[header->size - sizeof (struct grub_module_header)] = 0; | |
39705fad VS |
93 | break; |
94 | } | |
5e898c9d | 95 | } |
96 | ||
5f968e1e | 97 | /* Write hook for the environment variables of root. Remove surrounding |
98 | parentheses, if any. */ | |
99 | static char * | |
8de3495c | 100 | grub_env_write_root (struct grub_env_var *var __attribute__ ((unused)), |
101 | const char *val) | |
5f968e1e | 102 | { |
103 | /* XXX Is it better to check the existence of the device? */ | |
104 | grub_size_t len = grub_strlen (val); | |
b39f9d20 | 105 | |
5f968e1e | 106 | if (val[0] == '(' && val[len - 1] == ')') |
107 | return grub_strndup (val + 1, len - 2); | |
108 | ||
109 | return grub_strdup (val); | |
110 | } | |
111 | ||
a13f9237 | 112 | static void |
574618a2 | 113 | grub_set_prefix_and_root (void) |
a13f9237 | 114 | { |
574618a2 VS |
115 | char *device = NULL; |
116 | char *path = NULL; | |
117 | char *fwdevice = NULL; | |
118 | char *fwpath = NULL; | |
36dd20ad | 119 | char *prefix = NULL; |
a97501d2 VS |
120 | struct grub_module_header *header; |
121 | ||
122 | FOR_MODULES (header) | |
123 | if (header->type == OBJ_TYPE_PREFIX) | |
124 | prefix = (char *) header + sizeof (struct grub_module_header); | |
a13f9237 | 125 | |
5f968e1e | 126 | grub_register_variable_hook ("root", 0, grub_env_write_root); |
b39f9d20 | 127 | |
a97501d2 VS |
128 | if (prefix) |
129 | { | |
130 | char *pptr = NULL; | |
131 | if (prefix[0] == '(') | |
132 | { | |
133 | pptr = grub_strrchr (prefix, ')'); | |
134 | if (pptr) | |
135 | { | |
136 | device = grub_strndup (prefix + 1, pptr - prefix - 1); | |
137 | pptr++; | |
138 | } | |
139 | } | |
140 | if (!pptr) | |
141 | pptr = prefix; | |
142 | if (pptr[0]) | |
143 | path = grub_strdup (pptr); | |
144 | } | |
574618a2 VS |
145 | if ((!device || device[0] == ',' || !device[0]) || !path) |
146 | grub_machine_get_bootlocation (&fwdevice, &fwpath); | |
147 | ||
148 | if (!device && fwdevice) | |
149 | device = fwdevice; | |
150 | else if (fwdevice && (device[0] == ',' || !device[0])) | |
a13f9237 | 151 | { |
574618a2 VS |
152 | /* We have a partition, but still need to fill in the drive. */ |
153 | char *comma, *new_device; | |
154 | ||
eb6d0dd3 VS |
155 | for (comma = fwdevice; *comma; ) |
156 | { | |
157 | if (comma[0] == '\\' && comma[1] == ',') | |
158 | { | |
159 | comma += 2; | |
160 | continue; | |
161 | } | |
162 | if (*comma == ',') | |
163 | break; | |
164 | comma++; | |
165 | } | |
166 | if (*comma) | |
574618a2 VS |
167 | { |
168 | char *drive = grub_strndup (fwdevice, comma - fwdevice); | |
169 | new_device = grub_xasprintf ("%s%s", drive, device); | |
170 | grub_free (drive); | |
171 | } | |
172 | else | |
173 | new_device = grub_xasprintf ("%s%s", fwdevice, device); | |
a13f9237 | 174 | |
574618a2 VS |
175 | grub_free (fwdevice); |
176 | grub_free (device); | |
177 | device = new_device; | |
178 | } | |
f35abd81 VS |
179 | else |
180 | grub_free (fwdevice); | |
574618a2 | 181 | if (fwpath && !path) |
be174e5e VS |
182 | { |
183 | grub_size_t len = grub_strlen (fwpath); | |
184 | while (len > 1 && fwpath[len - 1] == '/') | |
185 | fwpath[--len] = 0; | |
186 | if (len >= sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1 | |
187 | && grub_memcmp (fwpath + len - (sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1), GRUB_TARGET_CPU "-" GRUB_PLATFORM, | |
188 | sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1) == 0) | |
189 | fwpath[len - (sizeof (GRUB_TARGET_CPU "-" GRUB_PLATFORM) - 1)] = 0; | |
190 | path = fwpath; | |
191 | } | |
f35abd81 VS |
192 | else |
193 | grub_free (fwpath); | |
574618a2 VS |
194 | if (device) |
195 | { | |
a97501d2 | 196 | char *prefix_set; |
574618a2 | 197 | |
a97501d2 VS |
198 | prefix_set = grub_xasprintf ("(%s)%s", device, path ? : ""); |
199 | if (prefix_set) | |
a13f9237 | 200 | { |
a97501d2 VS |
201 | grub_env_set ("prefix", prefix_set); |
202 | grub_free (prefix_set); | |
a13f9237 | 203 | } |
574618a2 | 204 | grub_env_set ("root", device); |
a13f9237 | 205 | } |
574618a2 VS |
206 | |
207 | grub_free (device); | |
208 | grub_free (path); | |
209 | grub_print_error (); | |
a13f9237 | 210 | } |
211 | ||
212 | /* Load the normal mode module and execute the normal mode if possible. */ | |
213 | static void | |
4b13b216 | 214 | grub_load_normal_mode (void) |
a13f9237 | 215 | { |
ce5bf700 | 216 | /* Load the module. */ |
4b13b216 | 217 | grub_dl_load ("normal"); |
b39f9d20 | 218 | |
6295b32f | 219 | /* Print errors if any. */ |
b5db202a | 220 | grub_print_error (); |
d558e6b5 | 221 | grub_errno = 0; |
222 | ||
223 | grub_command_execute ("normal", 0, 0); | |
a13f9237 | 224 | } |
225 | ||
77468368 VS |
226 | static void |
227 | reclaim_module_space (void) | |
228 | { | |
229 | grub_addr_t modstart, modend; | |
230 | ||
231 | if (!grub_modbase) | |
232 | return; | |
233 | ||
234 | #ifdef GRUB_MACHINE_PCBIOS | |
235 | modstart = GRUB_MEMORY_MACHINE_DECOMPRESSION_ADDR; | |
236 | #else | |
237 | modstart = grub_modbase; | |
238 | #endif | |
239 | modend = grub_modules_get_end (); | |
240 | grub_modbase = 0; | |
241 | ||
242 | #if GRUB_KERNEL_PRELOAD_SPACE_REUSABLE | |
243 | grub_mm_init_region ((void *) modstart, modend - modstart); | |
244 | #else | |
245 | (void) modstart; | |
246 | (void) modend; | |
247 | #endif | |
248 | } | |
249 | ||
6a161fa9 | 250 | /* The main routine. */ |
02a2bf83 | 251 | void __attribute__ ((noreturn)) |
4b13b216 | 252 | grub_main (void) |
6a161fa9 | 253 | { |
6a161fa9 | 254 | /* First of all, initialize the machine. */ |
4b13b216 | 255 | grub_machine_init (); |
6a161fa9 | 256 | |
e744219b VS |
257 | grub_boot_time ("After machine init."); |
258 | ||
6a161fa9 | 259 | /* Hello. */ |
4b13b216 | 260 | grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); |
261 | grub_printf ("Welcome to GRUB!\n\n"); | |
262 | grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); | |
6a161fa9 | 263 | |
77468368 VS |
264 | grub_load_config (); |
265 | ||
e744219b VS |
266 | grub_boot_time ("Before loading embedded modules."); |
267 | ||
a13f9237 | 268 | /* Load pre-loaded modules and free the space. */ |
4b13b216 | 269 | grub_register_exported_symbols (); |
6abdf8e2 VS |
270 | #ifdef GRUB_LINKER_HAVE_INIT |
271 | grub_arch_dl_init_linker (); | |
272 | #endif | |
4b13b216 | 273 | grub_load_modules (); |
6a161fa9 | 274 | |
e744219b VS |
275 | grub_boot_time ("After loading embedded modules."); |
276 | ||
2965c7cc | 277 | /* It is better to set the root device as soon as possible, |
278 | for convenience. */ | |
574618a2 | 279 | grub_set_prefix_and_root (); |
4531a206 VS |
280 | grub_env_export ("root"); |
281 | grub_env_export ("prefix"); | |
2965c7cc | 282 | |
77468368 VS |
283 | /* Reclaim space used for modules. */ |
284 | reclaim_module_space (); | |
285 | ||
e744219b VS |
286 | grub_boot_time ("After reclaiming module space."); |
287 | ||
d558e6b5 | 288 | grub_register_core_commands (); |
b39f9d20 | 289 | |
e744219b VS |
290 | grub_boot_time ("Before execution of embedded config."); |
291 | ||
77468368 VS |
292 | if (load_config) |
293 | grub_parser_execute (load_config); | |
294 | ||
e744219b VS |
295 | grub_boot_time ("After execution of embedded config. Attempt to go to normal mode"); |
296 | ||
d558e6b5 | 297 | grub_load_normal_mode (); |
f4c623e1 | 298 | grub_rescue_run (); |
6a161fa9 | 299 | } |