source: trunk/packages/xen-3.1/xen-3.1/xen/arch/powerpc/boot_of.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 36.3 KB
Line 
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.  */
39volatile unsigned int __spin_ack;
40
41static ulong of_vec;
42static ulong of_msr;
43static int of_out;
44static 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)
55static DECLARE_BITMAP(mem_available_pages, MEM_AVAILABLE_PAGES);
56
57extern char builtin_cmdline[];
58extern 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
78struct of_service {
79    u32 ofs_service;
80    u32 ofs_nargs;
81    u32 ofs_nrets;
82    u32 ofs_args[10];
83};
84
85static int bof_chosen;
86
87static struct of_service s;
88
89static 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 */
125static 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 */
135static 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
171static int of_printf(const char *fmt, ...)
172    __attribute__ ((format (printf, 1, 2)));
173static 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
198static 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
211static 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
226static 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 */
245static 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 */
258static 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
268static 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
281static 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
296static 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
311static 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
324static 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
333static 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
344static 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
359static 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
370static 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
380static 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
388static 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 */
473static 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
491static 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
543int 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
574static 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
651static 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
668static 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
725static 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
731retry:
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
765static 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
788static 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
858static 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
905static 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   
937static 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
1021static 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
1073static 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
1107static 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
1200static 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
1321multiboot_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 */
Note: See TracBrowser for help on using the repository browser.