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