]>
Commit | Line | Data |
---|---|---|
4d8d554a CW |
1 | /* init.c -- Initialize GRUB on the newworld mac (PPC). */ |
2 | /* | |
3 | * GRUB -- GRand Unified Bootloader | |
4 | * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc. | |
5 | * | |
6 | * GRUB is free software: you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation, either version 3 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * GRUB is distributed in the hope that it will be useful, | |
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 | |
17 | * along with GRUB. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include <grub/kernel.h> | |
21 | #include <grub/dl.h> | |
22 | #include <grub/disk.h> | |
23 | #include <grub/mm.h> | |
24 | #include <grub/partition.h> | |
25 | #include <grub/normal.h> | |
26 | #include <grub/fs.h> | |
27 | #include <grub/setjmp.h> | |
28 | #include <grub/env.h> | |
29 | #include <grub/misc.h> | |
30 | #include <grub/time.h> | |
31 | #include <grub/ieee1275/console.h> | |
32 | #include <grub/ieee1275/ofdisk.h> | |
e1c95655 ES |
33 | #ifdef __sparc__ |
34 | #include <grub/ieee1275/obdisk.h> | |
35 | #endif | |
4d8d554a CW |
36 | #include <grub/ieee1275/ieee1275.h> |
37 | #include <grub/net.h> | |
38 | #include <grub/offsets.h> | |
39 | #include <grub/memory.h> | |
40 | #include <grub/loader.h> | |
41 | #ifdef __i386__ | |
42 | #include <grub/cpu/tsc.h> | |
43 | #endif | |
44 | #ifdef __sparc__ | |
45 | #include <grub/machine/kernel.h> | |
46 | #endif | |
47 | ||
48 | /* The minimal heap size we can live with. */ | |
49 | #define HEAP_MIN_SIZE (unsigned long) (2 * 1024 * 1024) | |
50 | ||
51 | /* The maximum heap size we're going to claim */ | |
52 | #ifdef __i386__ | |
53 | #define HEAP_MAX_SIZE (unsigned long) (64 * 1024 * 1024) | |
54 | #else | |
55 | #define HEAP_MAX_SIZE (unsigned long) (32 * 1024 * 1024) | |
56 | #endif | |
57 | ||
58 | /* If possible, we will avoid claiming heap above this address, because it | |
59 | seems to cause relocation problems with OSes that link at 4 MiB */ | |
60 | #ifdef __i386__ | |
61 | #define HEAP_MAX_ADDR (unsigned long) (64 * 1024 * 1024) | |
62 | #else | |
63 | #define HEAP_MAX_ADDR (unsigned long) (32 * 1024 * 1024) | |
64 | #endif | |
65 | ||
66 | extern char _start[]; | |
67 | extern char _end[]; | |
68 | ||
69 | #ifdef __sparc__ | |
70 | grub_addr_t grub_ieee1275_original_stack; | |
71 | #endif | |
72 | ||
73 | void | |
74 | grub_exit (void) | |
75 | { | |
76 | grub_ieee1275_exit (); | |
77 | } | |
78 | ||
80a30601 | 79 | #ifndef __i386__ |
4d8d554a CW |
80 | /* Translate an OF filesystem path (separated by backslashes), into a GRUB |
81 | path (separated by forward slashes). */ | |
82 | static void | |
83 | grub_translate_ieee1275_path (char *filepath) | |
84 | { | |
85 | char *backslash; | |
86 | ||
87 | backslash = grub_strchr (filepath, '\\'); | |
88 | while (backslash != 0) | |
89 | { | |
90 | *backslash = '/'; | |
91 | backslash = grub_strchr (filepath, '\\'); | |
92 | } | |
93 | } | |
80a30601 | 94 | #endif |
4d8d554a CW |
95 | |
96 | void (*grub_ieee1275_net_config) (const char *dev, char **device, char **path, | |
97 | char *bootpath); | |
80a30601 CW |
98 | #ifdef __i386__ |
99 | void | |
100 | grub_machine_get_bootlocation (char **device __attribute__ ((unused)), | |
101 | char **path __attribute__ ((unused))) | |
102 | { | |
103 | grub_env_set ("prefix", "(sd,1)/"); | |
104 | } | |
105 | #else | |
4d8d554a CW |
106 | void |
107 | grub_machine_get_bootlocation (char **device, char **path) | |
108 | { | |
e1c95655 | 109 | char *bootpath = NULL; |
4d8d554a CW |
110 | char *filename; |
111 | char *type; | |
112 | ||
e1c95655 ES |
113 | grub_ieee1275_get_boot_dev (&bootpath); |
114 | if (bootpath == NULL) | |
115 | return; | |
4d8d554a CW |
116 | |
117 | /* Transform an OF device path to a GRUB path. */ | |
118 | ||
119 | type = grub_ieee1275_get_device_type (bootpath); | |
120 | if (type && grub_strcmp (type, "network") == 0) | |
121 | { | |
122 | char *dev, *canon; | |
123 | char *ptr; | |
124 | dev = grub_ieee1275_get_aliasdevname (bootpath); | |
125 | canon = grub_ieee1275_canonicalise_devname (dev); | |
126 | ptr = canon + grub_strlen (canon) - 1; | |
127 | while (ptr > canon && (*ptr == ',' || *ptr == ':')) | |
128 | ptr--; | |
129 | ptr++; | |
130 | *ptr = 0; | |
131 | ||
132 | if (grub_ieee1275_net_config) | |
133 | grub_ieee1275_net_config (canon, device, path, bootpath); | |
134 | grub_free (dev); | |
135 | grub_free (canon); | |
136 | } | |
137 | else | |
138 | *device = grub_ieee1275_encode_devname (bootpath); | |
139 | grub_free (type); | |
140 | ||
141 | filename = grub_ieee1275_get_filename (bootpath); | |
142 | if (filename) | |
143 | { | |
144 | char *lastslash = grub_strrchr (filename, '\\'); | |
145 | ||
146 | /* Truncate at last directory. */ | |
147 | if (lastslash) | |
148 | { | |
149 | *lastslash = '\0'; | |
150 | grub_translate_ieee1275_path (filename); | |
151 | ||
152 | *path = filename; | |
153 | } | |
154 | } | |
155 | grub_free (bootpath); | |
156 | } | |
80a30601 | 157 | #endif |
4d8d554a CW |
158 | |
159 | /* Claim some available memory in the first /memory node. */ | |
160 | #ifdef __sparc__ | |
161 | static void | |
162 | grub_claim_heap (void) | |
163 | { | |
164 | grub_mm_init_region ((void *) (grub_modules_get_end () | |
165 | + GRUB_KERNEL_MACHINE_STACK_SIZE), 0x200000); | |
166 | } | |
167 | #else | |
168 | /* Helper for grub_claim_heap. */ | |
169 | static int | |
170 | heap_init (grub_uint64_t addr, grub_uint64_t len, grub_memory_type_t type, | |
171 | void *data) | |
172 | { | |
173 | unsigned long *total = data; | |
174 | ||
175 | if (type != GRUB_MEMORY_AVAILABLE) | |
176 | return 0; | |
177 | ||
178 | if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_NO_PRE1_5M_CLAIM)) | |
179 | { | |
180 | if (addr + len <= 0x180000) | |
181 | return 0; | |
182 | ||
183 | if (addr < 0x180000) | |
184 | { | |
185 | len = addr + len - 0x180000; | |
186 | addr = 0x180000; | |
187 | } | |
188 | } | |
189 | len -= 1; /* Required for some firmware. */ | |
190 | ||
191 | /* Never exceed HEAP_MAX_SIZE */ | |
192 | if (*total + len > HEAP_MAX_SIZE) | |
193 | len = HEAP_MAX_SIZE - *total; | |
194 | ||
195 | /* Avoid claiming anything above HEAP_MAX_ADDR, if possible. */ | |
196 | if ((addr < HEAP_MAX_ADDR) && /* if it's too late, don't bother */ | |
197 | (addr + len > HEAP_MAX_ADDR) && /* if it wasn't available anyway, don't bother */ | |
198 | (*total + (HEAP_MAX_ADDR - addr) > HEAP_MIN_SIZE)) /* only limit ourselves when we can afford to */ | |
199 | len = HEAP_MAX_ADDR - addr; | |
200 | ||
201 | /* In theory, firmware should already prevent this from happening by not | |
202 | listing our own image in /memory/available. The check below is intended | |
203 | as a safeguard in case that doesn't happen. However, it doesn't protect | |
204 | us from corrupting our module area, which extends up to a | |
205 | yet-undetermined region above _end. */ | |
206 | if ((addr < (grub_addr_t) _end) && ((addr + len) > (grub_addr_t) _start)) | |
207 | { | |
208 | grub_printf ("Warning: attempt to claim over our own code!\n"); | |
209 | len = 0; | |
210 | } | |
211 | ||
212 | if (len) | |
213 | { | |
214 | grub_err_t err; | |
215 | /* Claim and use it. */ | |
216 | err = grub_claimmap (addr, len); | |
217 | if (err) | |
218 | return err; | |
219 | grub_mm_init_region ((void *) (grub_addr_t) addr, len); | |
220 | } | |
221 | ||
222 | *total += len; | |
223 | if (*total >= HEAP_MAX_SIZE) | |
224 | return 1; | |
225 | ||
226 | return 0; | |
227 | } | |
228 | ||
229 | static void | |
230 | grub_claim_heap (void) | |
231 | { | |
232 | unsigned long total = 0; | |
233 | ||
234 | if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_FORCE_CLAIM)) | |
235 | heap_init (GRUB_IEEE1275_STATIC_HEAP_START, GRUB_IEEE1275_STATIC_HEAP_LEN, | |
236 | 1, &total); | |
237 | else | |
238 | grub_machine_mmap_iterate (heap_init, &total); | |
239 | } | |
240 | #endif | |
241 | ||
242 | static void | |
243 | grub_parse_cmdline (void) | |
244 | { | |
245 | grub_ssize_t actual; | |
246 | char args[256]; | |
247 | ||
248 | if (grub_ieee1275_get_property (grub_ieee1275_chosen, "bootargs", &args, | |
249 | sizeof args, &actual) == 0 | |
250 | && actual > 1) | |
251 | { | |
252 | int i = 0; | |
253 | ||
254 | while (i < actual) | |
255 | { | |
256 | char *command = &args[i]; | |
257 | char *end; | |
258 | char *val; | |
259 | ||
260 | end = grub_strchr (command, ';'); | |
261 | if (end == 0) | |
262 | i = actual; /* No more commands after this one. */ | |
263 | else | |
264 | { | |
265 | *end = '\0'; | |
266 | i += end - command + 1; | |
267 | while (grub_isspace(args[i])) | |
268 | i++; | |
269 | } | |
270 | ||
271 | /* Process command. */ | |
272 | val = grub_strchr (command, '='); | |
273 | if (val) | |
274 | { | |
275 | *val = '\0'; | |
276 | grub_env_set (command, val + 1); | |
277 | } | |
278 | } | |
279 | } | |
280 | } | |
281 | ||
282 | grub_addr_t grub_modbase; | |
283 | ||
284 | void | |
285 | grub_machine_init (void) | |
286 | { | |
287 | grub_modbase = ALIGN_UP((grub_addr_t) _end | |
288 | + GRUB_KERNEL_MACHINE_MOD_GAP, | |
289 | GRUB_KERNEL_MACHINE_MOD_ALIGN); | |
290 | grub_ieee1275_init (); | |
291 | ||
292 | grub_console_init_early (); | |
293 | grub_claim_heap (); | |
294 | grub_console_init_lately (); | |
e1c95655 ES |
295 | #ifdef __sparc__ |
296 | grub_obdisk_init (); | |
297 | #else | |
4d8d554a | 298 | grub_ofdisk_init (); |
e1c95655 | 299 | #endif |
4d8d554a CW |
300 | grub_parse_cmdline (); |
301 | ||
302 | #ifdef __i386__ | |
303 | grub_tsc_init (); | |
304 | #else | |
305 | grub_install_get_time_ms (grub_rtc_get_time_ms); | |
306 | #endif | |
307 | } | |
308 | ||
309 | void | |
310 | grub_machine_fini (int flags) | |
311 | { | |
312 | if (flags & GRUB_LOADER_FLAG_NORETURN) | |
313 | { | |
e1c95655 ES |
314 | #ifdef __sparc__ |
315 | grub_obdisk_fini (); | |
316 | #else | |
4d8d554a | 317 | grub_ofdisk_fini (); |
e1c95655 | 318 | #endif |
4d8d554a CW |
319 | grub_console_fini (); |
320 | } | |
321 | } | |
322 | ||
323 | grub_uint64_t | |
324 | grub_rtc_get_time_ms (void) | |
325 | { | |
326 | grub_uint32_t msecs = 0; | |
327 | ||
328 | grub_ieee1275_milliseconds (&msecs); | |
329 | ||
330 | return msecs; | |
331 | } |