1 | /* |
---|
2 | * This program is free software; you can redistribute it and/or modify |
---|
3 | * it under the terms of the GNU General Public License as published by |
---|
4 | * the Free Software Foundation; either version 2 of the License, or |
---|
5 | * (at your option) any later version. |
---|
6 | * |
---|
7 | * This program is distributed in the hope that it will be useful, |
---|
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
10 | * GNU General Public License for more details. |
---|
11 | * |
---|
12 | * You should have received a copy of the GNU General Public License |
---|
13 | * along with this program; if not, write to the Free Software |
---|
14 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
---|
15 | * |
---|
16 | * Copyright IBM Corp. 2005, 2006, 2007 |
---|
17 | * |
---|
18 | * Authors: Jimi Xenidis <jimix@watson.ibm.com> |
---|
19 | * Hollis Blanchard <hollisb@us.ibm.com> |
---|
20 | */ |
---|
21 | |
---|
22 | #include <xen/config.h> |
---|
23 | #include <xen/init.h> |
---|
24 | #include <xen/lib.h> |
---|
25 | #include <xen/multiboot.h> |
---|
26 | #include <xen/version.h> |
---|
27 | #include <xen/spinlock.h> |
---|
28 | #include <xen/serial.h> |
---|
29 | #include <xen/time.h> |
---|
30 | #include <xen/sched.h> |
---|
31 | #include <asm/page.h> |
---|
32 | #include <asm/io.h> |
---|
33 | #include "exceptions.h" |
---|
34 | #include "of-devtree.h" |
---|
35 | #include "oftree.h" |
---|
36 | #include "rtas.h" |
---|
37 | |
---|
38 | /* Secondary processors use this for handshaking with main processor. */ |
---|
39 | volatile unsigned int __spin_ack; |
---|
40 | |
---|
41 | static ulong of_vec; |
---|
42 | static ulong of_msr; |
---|
43 | static int of_out; |
---|
44 | static ulong eomem; |
---|
45 | |
---|
46 | /* Track memory during early boot with a limited per-page bitmap. We need an |
---|
47 | * allocator to tell us where we can place RTAS, our copy of the device tree. |
---|
48 | * We could examine the "available" properties in memory nodes, but we |
---|
49 | * apparently can't depend on firmware to update those when we call "claim". So |
---|
50 | * we need to track it ourselves. |
---|
51 | * We can't dynamically allocate the bitmap, because we would need something |
---|
52 | * to tell us where it's safe to allocate... |
---|
53 | */ |
---|
54 | #define MEM_AVAILABLE_PAGES ((32 << 20) >> PAGE_SHIFT) |
---|
55 | static DECLARE_BITMAP(mem_available_pages, MEM_AVAILABLE_PAGES); |
---|
56 | |
---|
57 | extern char builtin_cmdline[]; |
---|
58 | extern struct ns16550_defaults ns16550; |
---|
59 | |
---|
60 | #undef OF_DEBUG |
---|
61 | #undef OF_DEBUG_LOW |
---|
62 | |
---|
63 | #ifdef OF_DEBUG |
---|
64 | #define DBG(args...) of_printf(args) |
---|
65 | #else |
---|
66 | #define DBG(args...) |
---|
67 | #endif |
---|
68 | |
---|
69 | #ifdef OF_DEBUG_LOW |
---|
70 | #define DBG_LOW(args...) of_printf(args) |
---|
71 | #else |
---|
72 | #define DBG_LOW(args...) |
---|
73 | #endif |
---|
74 | |
---|
75 | #define of_panic(MSG...) \ |
---|
76 | do { of_printf(MSG); of_printf("\nHANG\n"); for (;;); } while (0) |
---|
77 | |
---|
78 | struct of_service { |
---|
79 | u32 ofs_service; |
---|
80 | u32 ofs_nargs; |
---|
81 | u32 ofs_nrets; |
---|
82 | u32 ofs_args[10]; |
---|
83 | }; |
---|
84 | |
---|
85 | static int bof_chosen; |
---|
86 | |
---|
87 | static struct of_service s; |
---|
88 | |
---|
89 | static int __init of_call( |
---|
90 | const char *service, u32 nargs, u32 nrets, s32 rets[], ...) |
---|
91 | { |
---|
92 | int rc; |
---|
93 | |
---|
94 | if (of_vec != 0) { |
---|
95 | va_list args; |
---|
96 | int i; |
---|
97 | memset(&s, 0, sizeof (s)); |
---|
98 | s.ofs_service = (ulong)service; |
---|
99 | s.ofs_nargs = nargs; |
---|
100 | s.ofs_nrets = nrets; |
---|
101 | s.ofs_nargs = nargs; |
---|
102 | |
---|
103 | /* copy all the params into the args array */ |
---|
104 | va_start(args, rets); |
---|
105 | |
---|
106 | for (i = 0; i < nargs; i++) { |
---|
107 | s.ofs_args[i] = va_arg(args, u32); |
---|
108 | } |
---|
109 | |
---|
110 | va_end(args); |
---|
111 | |
---|
112 | rc = prom_call(&s, 0, of_vec, of_msr); |
---|
113 | |
---|
114 | /* yes always to the copy, just in case */ |
---|
115 | for (i = 0; i < nrets; i++) { |
---|
116 | rets[i] = s.ofs_args[i + nargs]; |
---|
117 | } |
---|
118 | } else { |
---|
119 | rc = OF_FAILURE; |
---|
120 | } |
---|
121 | return rc; |
---|
122 | } |
---|
123 | |
---|
124 | /* popular OF methods */ |
---|
125 | static int __init _of_write(int ih, const char *addr, u32 len) |
---|
126 | { |
---|
127 | int rets[1] = { OF_FAILURE }; |
---|
128 | if (of_call("write", 3, 1, rets, ih, addr, len) == OF_FAILURE) { |
---|
129 | return OF_FAILURE; |
---|
130 | } |
---|
131 | return rets[0]; |
---|
132 | } |
---|
133 | |
---|
134 | /* popular OF methods */ |
---|
135 | static int __init of_write(int ih, const char *addr, u32 len) |
---|
136 | { |
---|
137 | int rc; |
---|
138 | int i = 0; |
---|
139 | int sum = 0; |
---|
140 | |
---|
141 | while (i < len) { |
---|
142 | if (addr[i] == '\n') { |
---|
143 | if (i > 0) { |
---|
144 | rc = _of_write(ih, addr, i); |
---|
145 | if (rc == OF_FAILURE) |
---|
146 | return rc; |
---|
147 | sum += rc; |
---|
148 | } |
---|
149 | rc = _of_write(ih, "\r\n", 2); |
---|
150 | if (rc == OF_FAILURE) |
---|
151 | return rc; |
---|
152 | sum += rc; |
---|
153 | i++; |
---|
154 | addr += i; |
---|
155 | len -= i; |
---|
156 | i = 0; |
---|
157 | continue; |
---|
158 | } |
---|
159 | i++; |
---|
160 | } |
---|
161 | if (len > 0) { |
---|
162 | rc = _of_write(ih, addr, len); |
---|
163 | if (rc == OF_FAILURE) |
---|
164 | return rc; |
---|
165 | sum += rc; |
---|
166 | } |
---|
167 | |
---|
168 | return sum; |
---|
169 | } |
---|
170 | |
---|
171 | static int of_printf(const char *fmt, ...) |
---|
172 | __attribute__ ((format (printf, 1, 2))); |
---|
173 | static int __init of_printf(const char *fmt, ...) |
---|
174 | { |
---|
175 | static char buf[1024]; |
---|
176 | va_list args; |
---|
177 | int sz; |
---|
178 | |
---|
179 | if (of_out == 0) { |
---|
180 | return OF_FAILURE; |
---|
181 | } |
---|
182 | |
---|
183 | va_start(args, fmt); |
---|
184 | |
---|
185 | sz = vsnprintf(buf, sizeof (buf), fmt, args); |
---|
186 | if (sz <= sizeof (buf)) { |
---|
187 | of_write(of_out, buf, sz); |
---|
188 | } else { |
---|
189 | static const char trunc[] = "\n(TRUNCATED)\n"; |
---|
190 | |
---|
191 | sz = sizeof (buf); |
---|
192 | of_write(of_out, buf, sz); |
---|
193 | of_write(of_out, trunc, sizeof (trunc)); |
---|
194 | } |
---|
195 | return sz; |
---|
196 | } |
---|
197 | |
---|
198 | static int __init of_finddevice(const char *devspec) |
---|
199 | { |
---|
200 | int rets[1] = { OF_FAILURE }; |
---|
201 | |
---|
202 | of_call("finddevice", 1, 1, rets, devspec); |
---|
203 | if (rets[0] == OF_FAILURE) { |
---|
204 | DBG("finddevice %s -> FAILURE %d\n",devspec,rets[0]); |
---|
205 | return OF_FAILURE; |
---|
206 | } |
---|
207 | DBG_LOW("finddevice %s -> %d\n",devspec, rets[0]); |
---|
208 | return rets[0]; |
---|
209 | } |
---|
210 | |
---|
211 | static int __init of_getprop(int ph, const char *name, void *buf, u32 buflen) |
---|
212 | { |
---|
213 | int rets[1] = { OF_FAILURE }; |
---|
214 | |
---|
215 | of_call("getprop", 4, 1, rets, ph, name, buf, buflen); |
---|
216 | |
---|
217 | if (rets[0] == OF_FAILURE) { |
---|
218 | DBG_LOW("getprop 0x%x %s -> FAILURE\n", ph, name); |
---|
219 | return OF_FAILURE; |
---|
220 | } |
---|
221 | |
---|
222 | DBG_LOW("getprop 0x%x %s -> 0x%x (%s)\n", ph, name, rets[0], (char *)buf); |
---|
223 | return rets[0]; |
---|
224 | } |
---|
225 | |
---|
226 | static int __init of_setprop( |
---|
227 | int ph, const char *name, const void *buf, u32 buflen) |
---|
228 | { |
---|
229 | int rets[1] = { OF_FAILURE }; |
---|
230 | |
---|
231 | of_call("setprop", 4, 1, rets, ph, name, buf, buflen); |
---|
232 | |
---|
233 | if (rets[0] == OF_FAILURE) { |
---|
234 | DBG("setprop 0x%x %s -> FAILURE\n", ph, name); |
---|
235 | return OF_FAILURE; |
---|
236 | } |
---|
237 | |
---|
238 | DBG_LOW("setprop 0x%x %s -> %s\n", ph, name, (char *)buf); |
---|
239 | return rets[0]; |
---|
240 | } |
---|
241 | |
---|
242 | /* |
---|
243 | * returns 0 if there are no children (of spec) |
---|
244 | */ |
---|
245 | static int __init of_getchild(int ph) |
---|
246 | { |
---|
247 | int rets[1] = { OF_FAILURE }; |
---|
248 | |
---|
249 | of_call("child", 1, 1, rets, ph); |
---|
250 | DBG_LOW("getchild 0x%x -> 0x%x\n", ph, rets[0]); |
---|
251 | |
---|
252 | return rets[0]; |
---|
253 | } |
---|
254 | |
---|
255 | /* |
---|
256 | * returns 0 is there are no peers |
---|
257 | */ |
---|
258 | static int __init of_getpeer(int ph) |
---|
259 | { |
---|
260 | int rets[1] = { OF_FAILURE }; |
---|
261 | |
---|
262 | of_call("peer", 1, 1, rets, ph); |
---|
263 | DBG_LOW("getpeer 0x%x -> 0x%x\n", ph, rets[0]); |
---|
264 | |
---|
265 | return rets[0]; |
---|
266 | } |
---|
267 | |
---|
268 | static int __init of_getproplen(int ph, const char *name) |
---|
269 | { |
---|
270 | int rets[1] = { OF_FAILURE }; |
---|
271 | |
---|
272 | of_call("getproplen", 2, 1, rets, ph, name); |
---|
273 | if (rets[0] == OF_FAILURE) { |
---|
274 | DBG("getproplen 0x%x %s -> FAILURE\n", ph, name); |
---|
275 | return OF_FAILURE; |
---|
276 | } |
---|
277 | DBG_LOW("getproplen 0x%x %s -> 0x%x\n", ph, name, rets[0]); |
---|
278 | return rets[0]; |
---|
279 | } |
---|
280 | |
---|
281 | static int __init of_package_to_path(int ph, char *buffer, u32 buflen) |
---|
282 | { |
---|
283 | int rets[1] = { OF_FAILURE }; |
---|
284 | |
---|
285 | of_call("package-to-path", 3, 1, rets, ph, buffer, buflen); |
---|
286 | if (rets[0] == OF_FAILURE) { |
---|
287 | DBG("%s 0x%x -> FAILURE\n", __func__, ph); |
---|
288 | return OF_FAILURE; |
---|
289 | } |
---|
290 | DBG_LOW("%s 0x%x %s -> 0x%x\n", __func__, ph, buffer, rets[0]); |
---|
291 | if (rets[0] <= buflen) |
---|
292 | buffer[rets[0]] = '\0'; |
---|
293 | return rets[0]; |
---|
294 | } |
---|
295 | |
---|
296 | static int __init of_nextprop(int ph, const char *name, void *buf) |
---|
297 | { |
---|
298 | int rets[1] = { OF_FAILURE }; |
---|
299 | |
---|
300 | of_call("nextprop", 3, 1, rets, ph, name, buf); |
---|
301 | |
---|
302 | if (rets[0] == OF_FAILURE) { |
---|
303 | DBG("nextprop 0x%x %s -> FAILURE\n", ph, name); |
---|
304 | return OF_FAILURE; |
---|
305 | } |
---|
306 | |
---|
307 | DBG_LOW("nextprop 0x%x %s -> %s\n", ph, name, (char *)buf); |
---|
308 | return rets[0]; |
---|
309 | } |
---|
310 | |
---|
311 | static int __init of_instance_to_path(int ih, char *buffer, u32 buflen) |
---|
312 | { |
---|
313 | int rets[1] = { OF_FAILURE }; |
---|
314 | |
---|
315 | if (of_call("instance-to-path", 3, 1, rets, ih, buffer, buflen) |
---|
316 | == OF_FAILURE) |
---|
317 | return OF_FAILURE; |
---|
318 | |
---|
319 | if (rets[0] <= buflen) |
---|
320 | buffer[rets[0]] = '\0'; |
---|
321 | return rets[0]; |
---|
322 | } |
---|
323 | |
---|
324 | static int __init of_start_cpu(int cpu, u32 pc, u32 reg) |
---|
325 | { |
---|
326 | int ret; |
---|
327 | |
---|
328 | ret = of_call("start-cpu", 3, 0, NULL, cpu, pc, reg); |
---|
329 | |
---|
330 | return ret; |
---|
331 | } |
---|
332 | |
---|
333 | static void __init of_test(const char *of_method_name) |
---|
334 | { |
---|
335 | int rets[1] = { OF_FAILURE }; |
---|
336 | |
---|
337 | of_call("test", 1, 1, rets, of_method_name); |
---|
338 | if (rets[0] == OF_FAILURE ) { |
---|
339 | of_printf("Warning: possibly no OF method %s.\n" |
---|
340 | "(Ignore this warning on PIBS.)\n", of_method_name); |
---|
341 | } |
---|
342 | } |
---|
343 | |
---|
344 | static int __init of_claim(u32 virt, u32 size, u32 align) |
---|
345 | { |
---|
346 | int rets[1] = { OF_FAILURE }; |
---|
347 | |
---|
348 | of_call("claim", 3, 1, rets, virt, size, align); |
---|
349 | if (rets[0] == OF_FAILURE) { |
---|
350 | DBG("%s 0x%08x 0x%08x 0x%08x -> FAIL\n", __func__, virt, size, align); |
---|
351 | return OF_FAILURE; |
---|
352 | } |
---|
353 | |
---|
354 | DBG_LOW("%s 0x%08x 0x%08x 0x%08x -> 0x%08x\n", __func__, virt, size, align, |
---|
355 | rets[0]); |
---|
356 | return rets[0]; |
---|
357 | } |
---|
358 | |
---|
359 | static int __init of_instance_to_package(int ih) |
---|
360 | { |
---|
361 | int rets[1] = { OF_FAILURE }; |
---|
362 | |
---|
363 | of_call("instance-to-package", 1, 1, rets, ih); |
---|
364 | if (rets[0] == OF_FAILURE) |
---|
365 | return OF_FAILURE; |
---|
366 | |
---|
367 | return rets[0]; |
---|
368 | } |
---|
369 | |
---|
370 | static int __init of_getparent(int ph) |
---|
371 | { |
---|
372 | int rets[1] = { OF_FAILURE }; |
---|
373 | |
---|
374 | of_call("parent", 1, 1, rets, ph); |
---|
375 | |
---|
376 | DBG_LOW("getparent 0x%x -> 0x%x\n", ph, rets[0]); |
---|
377 | return rets[0]; |
---|
378 | } |
---|
379 | |
---|
380 | static int __init of_open(const char *devspec) |
---|
381 | { |
---|
382 | int rets[1] = { OF_FAILURE }; |
---|
383 | |
---|
384 | of_call("open", 1, 1, rets, devspec); |
---|
385 | return rets[0]; |
---|
386 | } |
---|
387 | |
---|
388 | static void boot_of_alloc_init(int m, uint addr_cells, uint size_cells) |
---|
389 | { |
---|
390 | int rc; |
---|
391 | uint pg; |
---|
392 | uint a[64]; |
---|
393 | int tst; |
---|
394 | u64 start; |
---|
395 | u64 size; |
---|
396 | |
---|
397 | rc = of_getprop(m, "available", a, sizeof (a)); |
---|
398 | if (rc > 0) { |
---|
399 | int l = rc / sizeof(a[0]); |
---|
400 | int r = 0; |
---|
401 | |
---|
402 | #ifdef OF_DEBUG |
---|
403 | { |
---|
404 | int i; |
---|
405 | of_printf("avail:\n"); |
---|
406 | for (i = 0; i < l; i += 4) |
---|
407 | of_printf(" 0x%x%x, 0x%x%x\n", |
---|
408 | a[i], a[i + 1], |
---|
409 | a[i + 2] ,a[i + 3]); |
---|
410 | } |
---|
411 | #endif |
---|
412 | |
---|
413 | pg = 0; |
---|
414 | while (pg < MEM_AVAILABLE_PAGES && r < l) { |
---|
415 | ulong end; |
---|
416 | |
---|
417 | start = a[r++]; |
---|
418 | if (addr_cells == 2 && (r < l) ) |
---|
419 | start = (start << 32) | a[r++]; |
---|
420 | |
---|
421 | size = a[r++]; |
---|
422 | if (size_cells == 2 && (r < l) ) |
---|
423 | size = (size << 32) | a[r++]; |
---|
424 | |
---|
425 | end = ALIGN_DOWN(start + size, PAGE_SIZE); |
---|
426 | |
---|
427 | start = ALIGN_UP(start, PAGE_SIZE); |
---|
428 | |
---|
429 | DBG("%s: marking 0x%x - 0x%lx\n", __func__, |
---|
430 | pg << PAGE_SHIFT, start); |
---|
431 | |
---|
432 | start >>= PAGE_SHIFT; |
---|
433 | while (pg < MEM_AVAILABLE_PAGES && pg < start) { |
---|
434 | set_bit(pg, mem_available_pages); |
---|
435 | pg++; |
---|
436 | } |
---|
437 | |
---|
438 | pg = end >> PAGE_SHIFT; |
---|
439 | } |
---|
440 | } |
---|
441 | |
---|
442 | /* Now make sure we mark our own memory */ |
---|
443 | pg = (ulong)_start >> PAGE_SHIFT; |
---|
444 | start = (ulong)_end >> PAGE_SHIFT; |
---|
445 | |
---|
446 | DBG("%s: marking 0x%x - 0x%lx\n", __func__, |
---|
447 | pg << PAGE_SHIFT, start << PAGE_SHIFT); |
---|
448 | |
---|
449 | /* Lets try and detect if our image has stepped on something. It |
---|
450 | * is possible that FW has already subtracted our image from |
---|
451 | * available memory so we must make sure that the previous bits |
---|
452 | * are the same for the whole image */ |
---|
453 | tst = test_and_set_bit(pg, mem_available_pages); |
---|
454 | ++pg; |
---|
455 | while (pg <= start) { |
---|
456 | if (test_and_set_bit(pg, mem_available_pages) != tst) |
---|
457 | of_panic("%s: pg :0x%x of our image is different\n", |
---|
458 | __func__, pg); |
---|
459 | ++pg; |
---|
460 | } |
---|
461 | |
---|
462 | DBG("%s: marking 0x%x - 0x%x\n", __func__, |
---|
463 | 0 << PAGE_SHIFT, 3 << PAGE_SHIFT); |
---|
464 | /* First for pages (where the vectors are) should be left alone as well */ |
---|
465 | set_bit(0, mem_available_pages); |
---|
466 | set_bit(1, mem_available_pages); |
---|
467 | set_bit(2, mem_available_pages); |
---|
468 | set_bit(3, mem_available_pages); |
---|
469 | } |
---|
470 | |
---|
471 | #ifdef BOOT_OF_FREE |
---|
472 | /* this is here in case we ever need a free call at a later date */ |
---|
473 | static void boot_of_free(ulong addr, ulong size) |
---|
474 | { |
---|
475 | ulong bits; |
---|
476 | ulong pos; |
---|
477 | ulong i; |
---|
478 | |
---|
479 | size = ALIGN_UP(size, PAGE_SIZE); |
---|
480 | bits = size >> PAGE_SHIFT; |
---|
481 | pos = addr >> PAGE_SHIFT; |
---|
482 | |
---|
483 | for (i = 0; i < bits; i++) { |
---|
484 | if (!test_and_clear_bit(pos + i, mem_available_pages)) |
---|
485 | of_panic("%s: pg :0x%lx was never allocated\n", |
---|
486 | __func__, pos + i); |
---|
487 | } |
---|
488 | } |
---|
489 | #endif |
---|
490 | |
---|
491 | static ulong boot_of_alloc(ulong size) |
---|
492 | { |
---|
493 | ulong bits; |
---|
494 | ulong pos; |
---|
495 | |
---|
496 | if (size == 0) |
---|
497 | return 0; |
---|
498 | |
---|
499 | DBG("%s(0x%lx)\n", __func__, size); |
---|
500 | |
---|
501 | size = ALIGN_UP(size, PAGE_SIZE); |
---|
502 | bits = size >> PAGE_SHIFT; |
---|
503 | pos = 0; |
---|
504 | for (;;) { |
---|
505 | ulong i; |
---|
506 | |
---|
507 | pos = find_next_zero_bit(mem_available_pages, |
---|
508 | MEM_AVAILABLE_PAGES, pos); |
---|
509 | DBG("%s: found start bit at: 0x%lx\n", __func__, pos); |
---|
510 | |
---|
511 | /* found nothing */ |
---|
512 | if ((pos + bits) > MEM_AVAILABLE_PAGES) { |
---|
513 | of_printf("%s: allocation of size: 0x%lx failed\n", |
---|
514 | __func__, size); |
---|
515 | return 0; |
---|
516 | } |
---|
517 | |
---|
518 | /* find a set that fits */ |
---|
519 | DBG("%s: checking for 0x%lx bits: 0x%lx\n", __func__, bits, pos); |
---|
520 | |
---|
521 | i = find_next_bit(mem_available_pages, MEM_AVAILABLE_PAGES, pos); |
---|
522 | if (i - pos >= bits) { |
---|
523 | uint addr = pos << PAGE_SHIFT; |
---|
524 | |
---|
525 | /* make sure OF is happy with our choice */ |
---|
526 | if (of_claim(addr, size, 0) != OF_FAILURE) { |
---|
527 | for (i = 0; i < bits; i++) |
---|
528 | set_bit(pos + i, mem_available_pages); |
---|
529 | |
---|
530 | DBG("%s: 0x%lx is good returning 0x%x\n", |
---|
531 | __func__, pos, addr); |
---|
532 | return addr; |
---|
533 | } |
---|
534 | /* if OF did not like the address then simply start from |
---|
535 | * the next bit */ |
---|
536 | i = 1; |
---|
537 | } |
---|
538 | |
---|
539 | pos = pos + i; |
---|
540 | } |
---|
541 | } |
---|
542 | |
---|
543 | int boot_of_mem_avail(int pos, ulong *startpage, ulong *endpage) |
---|
544 | { |
---|
545 | ulong freebit; |
---|
546 | ulong usedbit; |
---|
547 | |
---|
548 | if (pos >= MEM_AVAILABLE_PAGES) |
---|
549 | /* Stop iterating. */ |
---|
550 | return -1; |
---|
551 | |
---|
552 | /* Find first free page. */ |
---|
553 | freebit = find_next_zero_bit(mem_available_pages, MEM_AVAILABLE_PAGES, pos); |
---|
554 | if (freebit >= MEM_AVAILABLE_PAGES) { |
---|
555 | /* We know everything after MEM_AVAILABLE_PAGES is still free. */ |
---|
556 | *startpage = MEM_AVAILABLE_PAGES << PAGE_SHIFT; |
---|
557 | *endpage = ~0UL; |
---|
558 | return freebit; |
---|
559 | } |
---|
560 | *startpage = freebit << PAGE_SHIFT; |
---|
561 | |
---|
562 | /* Now find first used page after that. */ |
---|
563 | usedbit = find_next_bit(mem_available_pages, MEM_AVAILABLE_PAGES, freebit); |
---|
564 | if (usedbit >= MEM_AVAILABLE_PAGES) { |
---|
565 | /* We know everything after MEM_AVAILABLE_PAGES is still free. */ |
---|
566 | *endpage = ~0UL; |
---|
567 | return usedbit; |
---|
568 | } |
---|
569 | |
---|
570 | *endpage = usedbit << PAGE_SHIFT; |
---|
571 | return usedbit; |
---|
572 | } |
---|
573 | |
---|
574 | static ulong boot_of_mem_init(void) |
---|
575 | { |
---|
576 | int root; |
---|
577 | int p; |
---|
578 | int rc; |
---|
579 | uint addr_cells; |
---|
580 | uint size_cells; |
---|
581 | |
---|
582 | root = of_finddevice("/"); |
---|
583 | p = of_getchild(root); |
---|
584 | |
---|
585 | /* code is writen to assume sizes of 1 */ |
---|
586 | of_getprop(root, "#address-cells", &addr_cells, |
---|
587 | sizeof (addr_cells)); |
---|
588 | of_getprop(root, "#size-cells", &size_cells, |
---|
589 | sizeof (size_cells)); |
---|
590 | DBG("%s: address_cells=%d size_cells=%d\n", |
---|
591 | __func__, addr_cells, size_cells); |
---|
592 | |
---|
593 | /* We do ream memory discovery later, for now we only want to find |
---|
594 | * the first LMB */ |
---|
595 | do { |
---|
596 | const char memory[] = "memory"; |
---|
597 | char type[32]; |
---|
598 | |
---|
599 | type[0] = '\0'; |
---|
600 | |
---|
601 | of_getprop(p, "device_type", type, sizeof (type)); |
---|
602 | if (strncmp(type, memory, sizeof (memory)) == 0) { |
---|
603 | uint reg[48]; |
---|
604 | u64 start; |
---|
605 | u64 size; |
---|
606 | int r; |
---|
607 | int l; |
---|
608 | |
---|
609 | rc = of_getprop(p, "reg", reg, sizeof (reg)); |
---|
610 | if (rc == OF_FAILURE) { |
---|
611 | of_panic("no reg property for memory node: 0x%x.\n", p); |
---|
612 | } |
---|
613 | |
---|
614 | l = rc / sizeof(reg[0]); /* number reg element */ |
---|
615 | DBG("%s: number of bytes in property 'reg' %d\n", |
---|
616 | __func__, rc); |
---|
617 | |
---|
618 | r = 0; |
---|
619 | while (r < l) { |
---|
620 | start = reg[r++]; |
---|
621 | if (addr_cells == 2 && (r < l) ) |
---|
622 | start = (start << 32) | reg[r++]; |
---|
623 | |
---|
624 | if (r >= l) |
---|
625 | break; /* partial line. Skip */ |
---|
626 | |
---|
627 | if (start > 0) { |
---|
628 | /* this is not the first LMB so we skip it */ |
---|
629 | break; |
---|
630 | } |
---|
631 | |
---|
632 | size = reg[r++]; |
---|
633 | if (size_cells == 2 && (r < l) ) |
---|
634 | size = (size << 32) | reg[r++]; |
---|
635 | |
---|
636 | if (r > l) |
---|
637 | break; /* partial line. Skip */ |
---|
638 | |
---|
639 | boot_of_alloc_init(p, addr_cells, size_cells); |
---|
640 | |
---|
641 | eomem = size; |
---|
642 | return size; |
---|
643 | } |
---|
644 | } |
---|
645 | p = of_getpeer(p); |
---|
646 | } while (p != OF_FAILURE && p != 0); |
---|
647 | |
---|
648 | return 0; |
---|
649 | } |
---|
650 | |
---|
651 | static void boot_of_bootargs(multiboot_info_t *mbi) |
---|
652 | { |
---|
653 | int rc; |
---|
654 | |
---|
655 | if (builtin_cmdline[0] == '\0') { |
---|
656 | rc = of_getprop(bof_chosen, "bootargs", builtin_cmdline, |
---|
657 | CONFIG_CMDLINE_SIZE); |
---|
658 | if (rc > CONFIG_CMDLINE_SIZE) |
---|
659 | of_panic("bootargs[] not big enough for /chosen/bootargs\n"); |
---|
660 | } |
---|
661 | |
---|
662 | mbi->flags |= MBI_CMDLINE; |
---|
663 | mbi->cmdline = (ulong)builtin_cmdline; |
---|
664 | |
---|
665 | of_printf("bootargs = %s\n", builtin_cmdline); |
---|
666 | } |
---|
667 | |
---|
668 | static int save_props(void *m, ofdn_t n, int pkg) |
---|
669 | { |
---|
670 | int ret; |
---|
671 | char name[128]; |
---|
672 | int result = 1; |
---|
673 | int found_name = 0; |
---|
674 | int found_device_type = 0; |
---|
675 | const char name_str[] = "name"; |
---|
676 | const char devtype_str[] = "device_type"; |
---|
677 | |
---|
678 | /* get first */ |
---|
679 | result = of_nextprop(pkg, 0, name); |
---|
680 | |
---|
681 | while (result > 0) { |
---|
682 | int sz; |
---|
683 | u64 obj[1024]; |
---|
684 | |
---|
685 | sz = of_getproplen(pkg, name); |
---|
686 | if (sz >= 0) { |
---|
687 | ret = OF_SUCCESS; |
---|
688 | } else { |
---|
689 | ret = OF_FAILURE; |
---|
690 | } |
---|
691 | |
---|
692 | if (ret == OF_SUCCESS) { |
---|
693 | int actual = 0; |
---|
694 | ofdn_t pos; |
---|
695 | |
---|
696 | if (sz > 0) { |
---|
697 | if (sz > sizeof (obj)) { |
---|
698 | of_panic("obj array not big enough for 0x%x\n", sz); |
---|
699 | } |
---|
700 | actual = of_getprop(pkg, name, obj, sz); |
---|
701 | if (actual > sz) |
---|
702 | of_panic("obj too small"); |
---|
703 | } |
---|
704 | |
---|
705 | if (strncmp(name, name_str, sizeof(name_str)) == 0) { |
---|
706 | found_name = 1; |
---|
707 | } |
---|
708 | |
---|
709 | if (strncmp(name, devtype_str, sizeof(devtype_str)) == 0) { |
---|
710 | found_device_type = 1; |
---|
711 | } |
---|
712 | |
---|
713 | pos = ofd_prop_add(m, n, name, obj, actual); |
---|
714 | if (pos == 0) |
---|
715 | of_panic("prop_create"); |
---|
716 | } |
---|
717 | |
---|
718 | result = of_nextprop(pkg, name, name); |
---|
719 | } |
---|
720 | |
---|
721 | return 1; |
---|
722 | } |
---|
723 | |
---|
724 | |
---|
725 | static void do_pkg(void *m, ofdn_t n, int p, char *path, size_t psz) |
---|
726 | { |
---|
727 | int pnext; |
---|
728 | ofdn_t nnext; |
---|
729 | int sz; |
---|
730 | |
---|
731 | retry: |
---|
732 | save_props(m, n, p); |
---|
733 | |
---|
734 | /* do children first */ |
---|
735 | pnext = of_getchild(p); |
---|
736 | |
---|
737 | if (pnext != 0) { |
---|
738 | sz = of_package_to_path(pnext, path, psz); |
---|
739 | if (sz == OF_FAILURE) |
---|
740 | of_panic("bad path\n"); |
---|
741 | |
---|
742 | nnext = ofd_node_child_create(m, n, path, sz); |
---|
743 | if (nnext == 0) |
---|
744 | of_panic("out of mem\n"); |
---|
745 | |
---|
746 | do_pkg(m, nnext, pnext, path, psz); |
---|
747 | } |
---|
748 | |
---|
749 | /* do peer */ |
---|
750 | pnext = of_getpeer(p); |
---|
751 | |
---|
752 | if (pnext != 0) { |
---|
753 | sz = of_package_to_path(pnext, path, psz); |
---|
754 | |
---|
755 | nnext = ofd_node_peer_create(m, n, path, sz); |
---|
756 | if (nnext <= 0) |
---|
757 | of_panic("out of space in OFD tree.\n"); |
---|
758 | |
---|
759 | n = nnext; |
---|
760 | p = pnext; |
---|
761 | goto retry; |
---|
762 | } |
---|
763 | } |
---|
764 | |
---|
765 | static long pkg_save(void *mem) |
---|
766 | { |
---|
767 | int root; |
---|
768 | char path[256]; |
---|
769 | int r; |
---|
770 | |
---|
771 | path[0]='/'; |
---|
772 | path[1]='\0'; |
---|
773 | |
---|
774 | /* get root */ |
---|
775 | root = of_getpeer(0); |
---|
776 | if (root == OF_FAILURE) |
---|
777 | of_panic("no root package\n"); |
---|
778 | |
---|
779 | do_pkg(mem, OFD_ROOT, root, path, sizeof(path)); |
---|
780 | |
---|
781 | r = ofd_size(mem); |
---|
782 | |
---|
783 | of_printf("%s: saved device tree in 0x%x bytes\n", __func__, r); |
---|
784 | |
---|
785 | return r; |
---|
786 | } |
---|
787 | |
---|
788 | static int boot_of_fixup_refs(void *mem) |
---|
789 | { |
---|
790 | static const char *fixup_props[] = { |
---|
791 | "interrupt-parent", |
---|
792 | }; |
---|
793 | int i; |
---|
794 | int count = 0; |
---|
795 | |
---|
796 | for (i = 0; i < ARRAY_SIZE(fixup_props); i++) { |
---|
797 | ofdn_t c; |
---|
798 | const char *name = fixup_props[i]; |
---|
799 | |
---|
800 | c = ofd_node_find_by_prop(mem, OFD_ROOT, name, NULL, 0); |
---|
801 | while (c > 0) { |
---|
802 | const char *path; |
---|
803 | int rp; |
---|
804 | int ref; |
---|
805 | ofdn_t dp; |
---|
806 | int rc; |
---|
807 | ofdn_t upd; |
---|
808 | char ofpath[256]; |
---|
809 | |
---|
810 | path = ofd_node_path(mem, c); |
---|
811 | if (path == NULL) |
---|
812 | of_panic("no path to found prop: %s\n", name); |
---|
813 | |
---|
814 | rp = of_finddevice(path); |
---|
815 | if (rp == OF_FAILURE) |
---|
816 | of_panic("no real device for: name %s, path %s\n", |
---|
817 | name, path); |
---|
818 | /* Note: In theory 0 is a valid node handle but it is highly |
---|
819 | * unlikely. |
---|
820 | */ |
---|
821 | if (rp == 0) { |
---|
822 | of_panic("%s: of_finddevice returns 0 for path %s\n", |
---|
823 | __func__, path); |
---|
824 | } |
---|
825 | |
---|
826 | rc = of_getprop(rp, name, &ref, sizeof(ref)); |
---|
827 | if ((rc == OF_FAILURE) || (rc == 0)) |
---|
828 | of_panic("no prop: name %s, path %s, device 0x%x\n", |
---|
829 | name, path, rp); |
---|
830 | |
---|
831 | rc = of_package_to_path(ref, ofpath, sizeof (ofpath)); |
---|
832 | if (rc == OF_FAILURE) |
---|
833 | of_panic("no package: name %s, path %s, device 0x%x,\n" |
---|
834 | "ref 0x%x\n", name, path, rp, ref); |
---|
835 | |
---|
836 | dp = ofd_node_find(mem, ofpath); |
---|
837 | if (dp <= 0) |
---|
838 | of_panic("no ofd node for OF node[0x%x]: %s\n", |
---|
839 | ref, ofpath); |
---|
840 | |
---|
841 | ref = dp; |
---|
842 | |
---|
843 | upd = ofd_prop_add(mem, c, name, &ref, sizeof(ref)); |
---|
844 | if (upd <= 0) |
---|
845 | of_panic("update failed: %s\n", name); |
---|
846 | |
---|
847 | #ifdef DEBUG |
---|
848 | of_printf("%s: %s/%s -> %s\n", __func__, |
---|
849 | path, name, ofpath); |
---|
850 | #endif |
---|
851 | ++count; |
---|
852 | c = ofd_node_find_next(mem, c); |
---|
853 | } |
---|
854 | } |
---|
855 | return count; |
---|
856 | } |
---|
857 | |
---|
858 | static int boot_of_fixup_chosen(void *mem) |
---|
859 | { |
---|
860 | int ch; |
---|
861 | ofdn_t dn; |
---|
862 | ofdn_t dc; |
---|
863 | int val; |
---|
864 | int rc; |
---|
865 | char ofpath[256]; |
---|
866 | |
---|
867 | ch = of_finddevice("/chosen"); |
---|
868 | if (ch == OF_FAILURE) |
---|
869 | of_panic("/chosen not found\n"); |
---|
870 | |
---|
871 | rc = of_getprop(ch, "cpu", &val, sizeof (val)); |
---|
872 | |
---|
873 | if (rc != OF_FAILURE) { |
---|
874 | rc = of_instance_to_path(val, ofpath, sizeof (ofpath)); |
---|
875 | |
---|
876 | if (rc > 0) { |
---|
877 | dn = ofd_node_find(mem, ofpath); |
---|
878 | if (dn <= 0) |
---|
879 | of_panic("no node for: %s\n", ofpath); |
---|
880 | |
---|
881 | ofd_boot_cpu = dn; |
---|
882 | val = dn; |
---|
883 | |
---|
884 | dn = ofd_node_find(mem, "/chosen"); |
---|
885 | if (dn <= 0) |
---|
886 | of_panic("no /chosen node\n"); |
---|
887 | |
---|
888 | dc = ofd_prop_add(mem, dn, "cpu", &val, sizeof (val)); |
---|
889 | if (dc <= 0) |
---|
890 | of_panic("could not fix /chosen/cpu\n"); |
---|
891 | rc = 1; |
---|
892 | } else { |
---|
893 | of_printf("*** can't find path to booting cpu, " |
---|
894 | "SMP is disabled\n"); |
---|
895 | ofd_boot_cpu = -1; |
---|
896 | } |
---|
897 | } |
---|
898 | return rc; |
---|
899 | } |
---|
900 | |
---|
901 | /* PIBS Version 1.05.0000 04/26/2005 has an incorrect /ht/isa/ranges |
---|
902 | * property. The values are bad, and it doesn't even have the |
---|
903 | * right number of cells. */ |
---|
904 | |
---|
905 | static void __init boot_of_fix_maple(void) |
---|
906 | { |
---|
907 | int isa; |
---|
908 | const char *ranges = "ranges"; |
---|
909 | u32 isa_ranges[3]; |
---|
910 | const u32 isa_test[] = { 0x00000001, 0xf4000000, 0x00010000 }; |
---|
911 | const u32 isa_fixed[] = { |
---|
912 | 0x00000001, |
---|
913 | 0x00000000, |
---|
914 | 0x00000000, /* 0xf4000000, matt says this */ |
---|
915 | 0x00000000, |
---|
916 | 0x00000000, |
---|
917 | 0x00010000 |
---|
918 | }; |
---|
919 | |
---|
920 | isa = of_finddevice("/ht@0/isa@4"); |
---|
921 | if (isa != OF_FAILURE) { |
---|
922 | if (of_getproplen(isa, ranges) == sizeof (isa_test)) { |
---|
923 | of_getprop(isa, ranges, isa_ranges, sizeof (isa_ranges)); |
---|
924 | if (memcmp(isa_ranges, isa_test, sizeof (isa_test)) == 0) { |
---|
925 | int rc; |
---|
926 | |
---|
927 | of_printf("OF: fixing bogus ISA range on maple\n"); |
---|
928 | rc = of_setprop(isa, ranges, isa_fixed, sizeof (isa_fixed)); |
---|
929 | if (rc == OF_FAILURE) { |
---|
930 | of_panic("of_setprop() failed\n"); |
---|
931 | } |
---|
932 | } |
---|
933 | } |
---|
934 | } |
---|
935 | } |
---|
936 | |
---|
937 | static int __init boot_of_serial(void *oft) |
---|
938 | { |
---|
939 | int n; |
---|
940 | int p; |
---|
941 | int rc; |
---|
942 | u32 val[3]; |
---|
943 | char buf[128]; |
---|
944 | |
---|
945 | n = of_instance_to_package(of_out); |
---|
946 | if (n == OF_FAILURE) { |
---|
947 | of_panic("instance-to-package of /chosen/stdout: failed\n"); |
---|
948 | } |
---|
949 | |
---|
950 | /* Prune all serial devices from the device tree, including the |
---|
951 | * one pointed to by /chosen/stdout, because a guest domain can |
---|
952 | * initialize them and in so doing corrupt our console output. |
---|
953 | */ |
---|
954 | for (p = n; p > 0; p = of_getpeer(p)) { |
---|
955 | char type[32]; |
---|
956 | |
---|
957 | rc = of_package_to_path(p, buf, sizeof(buf)); |
---|
958 | if (rc == OF_FAILURE) |
---|
959 | of_panic("package-to-path failed\n"); |
---|
960 | |
---|
961 | rc = of_getprop(p, "device_type", type, sizeof (type)); |
---|
962 | if (rc == OF_FAILURE) { |
---|
963 | of_printf("%s: fetching type of `%s' failed\n", __func__, buf); |
---|
964 | continue; |
---|
965 | } |
---|
966 | |
---|
967 | if (strcmp(type, "serial") != 0) |
---|
968 | continue; |
---|
969 | |
---|
970 | of_printf("pruning `%s' from devtree\n", buf); |
---|
971 | rc = ofd_prune_path(oft, buf); |
---|
972 | if (rc < 0) |
---|
973 | of_panic("prune of `%s' failed\n", buf); |
---|
974 | } |
---|
975 | |
---|
976 | p = of_getparent(n); |
---|
977 | if (p == OF_FAILURE) { |
---|
978 | of_panic("no parent for: 0x%x\n", n); |
---|
979 | } |
---|
980 | |
---|
981 | buf[0] = '\0'; |
---|
982 | of_getprop(p, "device_type", buf, sizeof (buf)); |
---|
983 | if (strstr(buf, "isa") == NULL) { |
---|
984 | of_panic("only ISA UARTS supported\n"); |
---|
985 | } |
---|
986 | |
---|
987 | /* should get this from devtree */ |
---|
988 | isa_io_base = 0xf4000000; |
---|
989 | of_printf("%s: ISA base: 0x%lx\n", __func__, isa_io_base); |
---|
990 | |
---|
991 | buf[0] = '\0'; |
---|
992 | of_getprop(n, "device_type", buf, sizeof (buf)); |
---|
993 | if (strstr(buf, "serial") == NULL) { |
---|
994 | of_panic("only UARTS supported\n"); |
---|
995 | } |
---|
996 | |
---|
997 | rc = of_getprop(n, "reg", val, sizeof (val)); |
---|
998 | if (rc == OF_FAILURE) { |
---|
999 | of_panic("%s: no location for serial port\n", __func__); |
---|
1000 | } |
---|
1001 | |
---|
1002 | ns16550.baud = BAUD_AUTO; |
---|
1003 | ns16550.data_bits = 8; |
---|
1004 | ns16550.parity = 'n'; |
---|
1005 | ns16550.stop_bits = 1; |
---|
1006 | |
---|
1007 | rc = of_getprop(n, "interrupts", val, sizeof (val)); |
---|
1008 | if (rc == OF_FAILURE) { |
---|
1009 | of_printf("%s: no ISRC, forcing poll mode\n", __func__); |
---|
1010 | ns16550.irq = 0; |
---|
1011 | } else { |
---|
1012 | ns16550.irq = val[0]; |
---|
1013 | of_printf("%s: ISRC=0x%x, but forcing poll mode\n", |
---|
1014 | __func__, ns16550.irq); |
---|
1015 | ns16550.irq = 0; |
---|
1016 | } |
---|
1017 | |
---|
1018 | return 1; |
---|
1019 | } |
---|
1020 | |
---|
1021 | static int __init boot_of_rtas(module_t *mod, multiboot_info_t *mbi) |
---|
1022 | { |
---|
1023 | int rtas_node; |
---|
1024 | int rtas_instance; |
---|
1025 | uint size = 0; |
---|
1026 | int res[2]; |
---|
1027 | int mem; |
---|
1028 | int ret; |
---|
1029 | |
---|
1030 | rtas_node = of_finddevice("/rtas"); |
---|
1031 | |
---|
1032 | if (rtas_node <= 0) { |
---|
1033 | of_printf("No RTAS, Xen has no power control\n"); |
---|
1034 | return 0; |
---|
1035 | } |
---|
1036 | of_getprop(rtas_node, "rtas-size", &size, sizeof (size)); |
---|
1037 | if (size == 0) { |
---|
1038 | of_printf("RTAS, has no size\n"); |
---|
1039 | return 0; |
---|
1040 | } |
---|
1041 | |
---|
1042 | rtas_instance = of_open("/rtas"); |
---|
1043 | if (rtas_instance == OF_FAILURE) { |
---|
1044 | of_printf("RTAS, could not open\n"); |
---|
1045 | return 0; |
---|
1046 | } |
---|
1047 | |
---|
1048 | size = ALIGN_UP(size, PAGE_SIZE); |
---|
1049 | |
---|
1050 | mem = boot_of_alloc(size); |
---|
1051 | if (mem == 0) |
---|
1052 | of_panic("Could not allocate RTAS tree\n"); |
---|
1053 | |
---|
1054 | of_printf("instantiating RTAS at: 0x%x\n", mem); |
---|
1055 | |
---|
1056 | ret = of_call("call-method", 3, 2, res, |
---|
1057 | "instantiate-rtas", rtas_instance, mem); |
---|
1058 | if (ret == OF_FAILURE) { |
---|
1059 | of_printf("RTAS, could not open\n"); |
---|
1060 | return 0; |
---|
1061 | } |
---|
1062 | |
---|
1063 | rtas_entry = res[1]; |
---|
1064 | rtas_base = mem; |
---|
1065 | rtas_end = mem + size; |
---|
1066 | rtas_msr = of_msr; |
---|
1067 | |
---|
1068 | mod->mod_start = rtas_base; |
---|
1069 | mod->mod_end = rtas_end; |
---|
1070 | return 1; |
---|
1071 | } |
---|
1072 | |
---|
1073 | static void * __init boot_of_devtree(module_t *mod, multiboot_info_t *mbi) |
---|
1074 | { |
---|
1075 | void *oft; |
---|
1076 | ulong oft_sz = 48 * PAGE_SIZE; |
---|
1077 | |
---|
1078 | /* snapshot the tree */ |
---|
1079 | oft = (void *)boot_of_alloc(oft_sz); |
---|
1080 | if (oft == NULL) |
---|
1081 | of_panic("Could not allocate OFD tree\n"); |
---|
1082 | |
---|
1083 | of_printf("creating oftree at: 0x%p\n", oft); |
---|
1084 | of_test("package-to-path"); |
---|
1085 | oft = ofd_create(oft, oft_sz); |
---|
1086 | pkg_save(oft); |
---|
1087 | |
---|
1088 | if (ofd_size(oft) > oft_sz) |
---|
1089 | of_panic("Could not fit all of native devtree\n"); |
---|
1090 | |
---|
1091 | boot_of_fixup_refs(oft); |
---|
1092 | boot_of_fixup_chosen(oft); |
---|
1093 | |
---|
1094 | if (ofd_size(oft) > oft_sz) |
---|
1095 | of_panic("Could not fit all devtree fixups\n"); |
---|
1096 | |
---|
1097 | ofd_walk(oft, __func__, OFD_ROOT, /* add_hype_props */ NULL, 2); |
---|
1098 | |
---|
1099 | mod->mod_start = (ulong)oft; |
---|
1100 | mod->mod_end = mod->mod_start + oft_sz; |
---|
1101 | of_printf("%s: devtree mod @ 0x%016x - 0x%016x\n", __func__, |
---|
1102 | mod->mod_start, mod->mod_end); |
---|
1103 | |
---|
1104 | return oft; |
---|
1105 | } |
---|
1106 | |
---|
1107 | static void * __init boot_of_module(ulong r3, ulong r4, multiboot_info_t *mbi) |
---|
1108 | { |
---|
1109 | static module_t mods[4]; |
---|
1110 | ulong mod0_start; |
---|
1111 | ulong mod0_size; |
---|
1112 | static const char * sepr[] = {" -- ", " || "}; |
---|
1113 | int sepr_index; |
---|
1114 | extern char dom0_start[] __attribute__ ((weak)); |
---|
1115 | extern char dom0_size[] __attribute__ ((weak)); |
---|
1116 | const char *p = NULL; |
---|
1117 | int mod; |
---|
1118 | void *oft; |
---|
1119 | |
---|
1120 | if ((r3 > 0) && (r4 > 0)) { |
---|
1121 | /* was it handed to us in registers ? */ |
---|
1122 | mod0_start = r3; |
---|
1123 | mod0_size = r4; |
---|
1124 | of_printf("%s: Dom0 was loaded and found using r3/r4:" |
---|
1125 | "0x%lx[size 0x%lx]\n", |
---|
1126 | __func__, mod0_start, mod0_size); |
---|
1127 | } else { |
---|
1128 | /* see if it is in the boot params */ |
---|
1129 | p = strstr((char *)((ulong)mbi->cmdline), "dom0_start="); |
---|
1130 | if ( p != NULL) { |
---|
1131 | p += 11; |
---|
1132 | mod0_start = simple_strtoul(p, NULL, 0); |
---|
1133 | |
---|
1134 | p = strstr((char *)((ulong)mbi->cmdline), "dom0_size="); |
---|
1135 | p += 10; |
---|
1136 | mod0_size = simple_strtoul(p, NULL, 0); |
---|
1137 | of_printf("%s: Dom0 was loaded and found using cmdline:" |
---|
1138 | "0x%lx[size 0x%lx]\n", |
---|
1139 | __func__, mod0_start, mod0_size); |
---|
1140 | } else if ( ((ulong)dom0_start != 0) && ((ulong)dom0_size != 0) ) { |
---|
1141 | /* was it linked in ? */ |
---|
1142 | |
---|
1143 | mod0_start = (ulong)dom0_start; |
---|
1144 | mod0_size = (ulong)dom0_size; |
---|
1145 | of_printf("%s: Dom0 is linked in: 0x%lx[size 0x%lx]\n", |
---|
1146 | __func__, mod0_start, mod0_size); |
---|
1147 | } else { |
---|
1148 | mod0_start = (ulong)_end; |
---|
1149 | mod0_size = 0; |
---|
1150 | of_printf("%s: FYI Dom0 is unknown, will be caught later\n", |
---|
1151 | __func__); |
---|
1152 | } |
---|
1153 | } |
---|
1154 | |
---|
1155 | if (mod0_size > 0) { |
---|
1156 | const char *c = (const char *)mod0_start; |
---|
1157 | |
---|
1158 | of_printf("mod0: %o %c %c %c\n", c[0], c[1], c[2], c[3]); |
---|
1159 | } |
---|
1160 | |
---|
1161 | mod = 0; |
---|
1162 | mods[mod].mod_start = mod0_start; |
---|
1163 | mods[mod].mod_end = mod0_start + mod0_size; |
---|
1164 | |
---|
1165 | of_printf("%s: dom0 mod @ 0x%016x[0x%x]\n", __func__, |
---|
1166 | mods[mod].mod_start, mods[mod].mod_end); |
---|
1167 | |
---|
1168 | /* look for delimiter: "--" or "||" */ |
---|
1169 | for (sepr_index = 0; sepr_index < ARRAY_SIZE(sepr); sepr_index++){ |
---|
1170 | p = strstr((char *)(ulong)mbi->cmdline, sepr[sepr_index]); |
---|
1171 | if (p != NULL) |
---|
1172 | break; |
---|
1173 | } |
---|
1174 | |
---|
1175 | if (p != NULL) { |
---|
1176 | /* Xen proper should never know about the dom0 args. */ |
---|
1177 | *(char *)p = '\0'; |
---|
1178 | p += strlen(sepr[sepr_index]); |
---|
1179 | mods[mod].string = (u32)(ulong)p; |
---|
1180 | of_printf("%s: dom0 mod string: %s\n", __func__, p); |
---|
1181 | } |
---|
1182 | |
---|
1183 | ++mod; |
---|
1184 | if (boot_of_rtas(&mods[mod], mbi)) |
---|
1185 | ++mod; |
---|
1186 | |
---|
1187 | oft = boot_of_devtree(&mods[mod], mbi); |
---|
1188 | if (oft == NULL) |
---|
1189 | of_panic("%s: boot_of_devtree failed\n", __func__); |
---|
1190 | |
---|
1191 | ++mod; |
---|
1192 | |
---|
1193 | mbi->flags |= MBI_MODULES; |
---|
1194 | mbi->mods_count = mod; |
---|
1195 | mbi->mods_addr = (u32)mods; |
---|
1196 | |
---|
1197 | return oft; |
---|
1198 | } |
---|
1199 | |
---|
1200 | static int __init boot_of_cpus(void) |
---|
1201 | { |
---|
1202 | int cpus_node, cpu_node; |
---|
1203 | int bootcpu_instance, bootcpu_node; |
---|
1204 | int logical; |
---|
1205 | int result; |
---|
1206 | s32 cpuid; |
---|
1207 | u32 cpu_clock[2]; |
---|
1208 | extern uint cpu_hard_id[NR_CPUS]; |
---|
1209 | u32 tbf; |
---|
1210 | |
---|
1211 | /* Look up which CPU we are running on right now and get all info |
---|
1212 | * from there */ |
---|
1213 | result = of_getprop(bof_chosen, "cpu", |
---|
1214 | &bootcpu_instance, sizeof (bootcpu_instance)); |
---|
1215 | if (result == OF_FAILURE) |
---|
1216 | of_panic("Failed to look up boot cpu instance\n"); |
---|
1217 | |
---|
1218 | bootcpu_node = of_instance_to_package(bootcpu_instance); |
---|
1219 | if (result == OF_FAILURE) |
---|
1220 | of_panic("Failed to look up boot cpu package\n"); |
---|
1221 | |
---|
1222 | cpu_node = bootcpu_node; |
---|
1223 | |
---|
1224 | result = of_getprop(cpu_node, "timebase-frequency", &tbf, sizeof(tbf)); |
---|
1225 | timebase_freq = tbf; |
---|
1226 | if (result == OF_FAILURE) { |
---|
1227 | of_panic("Couldn't get timebase frequency!\n"); |
---|
1228 | } |
---|
1229 | of_printf("OF: timebase-frequency = %ld Hz\n", timebase_freq); |
---|
1230 | |
---|
1231 | result = of_getprop(cpu_node, "clock-frequency", |
---|
1232 | &cpu_clock, sizeof(cpu_clock)); |
---|
1233 | if (result == OF_FAILURE || (result !=4 && result != 8)) { |
---|
1234 | of_panic("Couldn't get clock frequency!\n"); |
---|
1235 | } |
---|
1236 | cpu_khz = cpu_clock[0]; |
---|
1237 | if (result == 8) { |
---|
1238 | cpu_khz <<= 32; |
---|
1239 | cpu_khz |= cpu_clock[1]; |
---|
1240 | } |
---|
1241 | cpu_khz /= 1000; |
---|
1242 | of_printf("OF: clock-frequency = %ld KHz\n", cpu_khz); |
---|
1243 | |
---|
1244 | /* We want a continuous logical cpu number space and we'll make |
---|
1245 | * the booting CPU logical 0. */ |
---|
1246 | cpu_set(0, cpu_present_map); |
---|
1247 | cpu_set(0, cpu_online_map); |
---|
1248 | cpu_set(0, cpu_possible_map); |
---|
1249 | |
---|
1250 | result = of_getprop(cpu_node, "reg", &cpuid, sizeof(cpuid)); |
---|
1251 | cpu_hard_id[0] = cpuid; |
---|
1252 | |
---|
1253 | /* Spin up all CPUS, even if there are more than NR_CPUS or we are |
---|
1254 | * runnign nosmp, because Open Firmware has them spinning on cache |
---|
1255 | * lines which will eventually be scrubbed, which could lead to |
---|
1256 | * random CPU activation. |
---|
1257 | */ |
---|
1258 | |
---|
1259 | /* Find the base of the multi-CPU package node */ |
---|
1260 | cpus_node = of_finddevice("/cpus"); |
---|
1261 | if (cpus_node <= 0) { |
---|
1262 | of_printf("Single Processor System\n"); |
---|
1263 | return 1; |
---|
1264 | } |
---|
1265 | /* Start with the first child */ |
---|
1266 | cpu_node = of_getchild(cpus_node); |
---|
1267 | |
---|
1268 | for (logical = 1; cpu_node > 0; logical++) { |
---|
1269 | unsigned int ping, pong; |
---|
1270 | unsigned long now, then, timeout; |
---|
1271 | |
---|
1272 | if (cpu_node == bootcpu_node) { |
---|
1273 | /* same CPU as boot CPU shich we have already made 0 so |
---|
1274 | * reduce the logical count */ |
---|
1275 | --logical; |
---|
1276 | } else { |
---|
1277 | result = of_getprop(cpu_node, "reg", &cpuid, sizeof(cpuid)); |
---|
1278 | if (result == OF_FAILURE) |
---|
1279 | of_panic("cpuid lookup failed\n"); |
---|
1280 | |
---|
1281 | cpu_hard_id[logical] = cpuid; |
---|
1282 | |
---|
1283 | of_printf("spinning up secondary processor #%d: ", logical); |
---|
1284 | |
---|
1285 | __spin_ack = ~0x0; |
---|
1286 | ping = __spin_ack; |
---|
1287 | pong = __spin_ack; |
---|
1288 | of_printf("ping = 0x%x: ", ping); |
---|
1289 | |
---|
1290 | mb(); |
---|
1291 | result = of_start_cpu(cpu_node, (ulong)spin_start, logical); |
---|
1292 | if (result == OF_FAILURE) |
---|
1293 | of_panic("start cpu failed\n"); |
---|
1294 | |
---|
1295 | /* We will give the secondary processor five seconds to reply. */ |
---|
1296 | then = mftb(); |
---|
1297 | timeout = then + (5 * timebase_freq); |
---|
1298 | |
---|
1299 | do { |
---|
1300 | now = mftb(); |
---|
1301 | if (now >= timeout) { |
---|
1302 | of_printf("BROKEN: "); |
---|
1303 | break; |
---|
1304 | } |
---|
1305 | |
---|
1306 | mb(); |
---|
1307 | pong = __spin_ack; |
---|
1308 | } while (pong == ping); |
---|
1309 | of_printf("pong = 0x%x\n", pong); |
---|
1310 | |
---|
1311 | if (pong != ping) { |
---|
1312 | cpu_set(logical, cpu_present_map); |
---|
1313 | cpu_set(logical, cpu_possible_map); |
---|
1314 | } |
---|
1315 | } |
---|
1316 | cpu_node = of_getpeer(cpu_node); |
---|
1317 | } |
---|
1318 | return 1; |
---|
1319 | } |
---|
1320 | |
---|
1321 | multiboot_info_t __init *boot_of_init( |
---|
1322 | ulong r3, ulong r4, ulong vec, ulong r6, ulong r7, ulong orig_msr) |
---|
1323 | { |
---|
1324 | static multiboot_info_t mbi; |
---|
1325 | void *oft; |
---|
1326 | int r; |
---|
1327 | |
---|
1328 | of_vec = vec; |
---|
1329 | of_msr = orig_msr; |
---|
1330 | |
---|
1331 | bof_chosen = of_finddevice("/chosen"); |
---|
1332 | of_getprop(bof_chosen, "stdout", &of_out, sizeof (of_out)); |
---|
1333 | |
---|
1334 | of_printf("%s\n", "---------------------------------------------------"); |
---|
1335 | of_printf("OF: Xen/PPC version %d.%d%s (%s@%s) (%s) %s\n", |
---|
1336 | xen_major_version(), xen_minor_version(), xen_extra_version(), |
---|
1337 | xen_compile_by(), xen_compile_domain(), |
---|
1338 | xen_compiler(), xen_compile_date()); |
---|
1339 | |
---|
1340 | of_printf("%s args: 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n" |
---|
1341 | "boot msr: 0x%lx\n", |
---|
1342 | __func__, |
---|
1343 | r3, r4, vec, r6, r7, orig_msr); |
---|
1344 | |
---|
1345 | if (is_kernel(vec)) { |
---|
1346 | of_panic("Hmm.. OF[0x%lx] seems to have stepped on our image " |
---|
1347 | "that ranges: %p .. %p.\n", |
---|
1348 | vec, _start, _end); |
---|
1349 | } |
---|
1350 | of_printf("%s: _start %p _end %p 0x%lx\n", __func__, _start, _end, r6); |
---|
1351 | |
---|
1352 | boot_of_fix_maple(); |
---|
1353 | r = boot_of_mem_init(); |
---|
1354 | if (r == 0) |
---|
1355 | of_panic("failure to initialize memory allocator"); |
---|
1356 | boot_of_bootargs(&mbi); |
---|
1357 | oft = boot_of_module(r3, r4, &mbi); |
---|
1358 | boot_of_cpus(); |
---|
1359 | boot_of_serial(oft); |
---|
1360 | |
---|
1361 | /* end of OF */ |
---|
1362 | of_printf("Quiescing Open Firmware ...\n"); |
---|
1363 | of_call("quiesce", 0, 0, NULL); |
---|
1364 | |
---|
1365 | return &mbi; |
---|
1366 | } |
---|
1367 | |
---|
1368 | /* |
---|
1369 | * Local variables: |
---|
1370 | * mode: C |
---|
1371 | * c-set-style: "BSD" |
---|
1372 | * c-basic-offset: 4 |
---|
1373 | * tab-width: 4 |
---|
1374 | * indent-tabs-mode: nil |
---|
1375 | * End: |
---|
1376 | */ |
---|