source: trunk/packages/xen-3.1/xen-3.1/xen/arch/powerpc/setup.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: 12.2 KB
Line 
1/*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License as
4 * published by the Free Software Foundation; either version 2 of the
5 * License, or (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 *          Amos Waterland <apw@us.ibm.com>
20 *          Hollis Blanchard <hollisb@us.ibm.com>
21 */
22
23#include <xen/config.h>
24#include <xen/init.h>
25#include <xen/lib.h>
26#include <xen/cpumask.h>
27#include <xen/sched.h>
28#include <xen/multiboot.h>
29#include <xen/serial.h>
30#include <xen/softirq.h>
31#include <xen/console.h>
32#include <xen/trace.h>
33#include <xen/mm.h>
34#include <xen/domain.h>
35#include <xen/gdbstub.h>
36#include <xen/symbols.h>
37#include <xen/keyhandler.h>
38#include <xen/numa.h>
39#include <xen/rcupdate.h>
40#include <xen/version.h>
41#include <acm/acm_hooks.h>
42#include <public/version.h>
43#include <asm/mpic.h>
44#include <asm/processor.h>
45#include <asm/desc.h>
46#include <asm/cache.h>
47#include <asm/debugger.h>
48#include <asm/delay.h>
49#include <asm/percpu.h>
50#include <asm/io.h>
51#include "exceptions.h"
52#include "of-devtree.h"
53#include "oftree.h"
54#include "rtas.h"
55
56#define DEBUG
57
58/* opt_noht: If true, Hyperthreading is ignored. */
59int opt_noht = 0;
60boolean_param("noht", opt_noht);
61
62int opt_earlygdb = 0;
63boolean_param("earlygdb", opt_earlygdb);
64
65/* opt_nosmp: If true, secondary processors are ignored. */
66static int opt_nosmp = 0;
67boolean_param("nosmp", opt_nosmp);
68
69/* maxcpus: maximum number of CPUs to activate. */
70static unsigned int max_cpus = NR_CPUS;
71integer_param("maxcpus", max_cpus);
72
73u32 tlbflush_clock = 1U;
74DEFINE_PER_CPU(u32, tlbflush_time);
75
76unsigned int watchdog_on;
77unsigned long wait_init_idle;
78ulong oftree;
79ulong oftree_len;
80ulong oftree_end;
81
82uint cpu_hard_id[NR_CPUS] __initdata;
83cpumask_t cpu_present_map;
84
85/* XXX get this from ISA node in device tree */
86char *vgabase;
87ulong isa_io_base;
88struct ns16550_defaults ns16550;
89
90extern char __per_cpu_start[], __per_cpu_data_end[], __per_cpu_end[];
91
92static struct domain *idle_domain;
93
94volatile struct processor_area * volatile global_cpu_table[NR_CPUS];
95
96static void __init do_initcalls(void)
97{
98    initcall_t *call;
99    for (call = &__initcall_start; call < &__initcall_end; call++) {
100        (*call)();
101    }
102}
103
104
105void noinline __attn(void)
106{
107    /* To continue the probe will step over the ATTN instruction.  The
108     * NOP is there to make sure there is something sane to "step
109     * over" to. */
110    console_start_sync();
111    asm volatile(".long 0x200;nop");
112    console_end_sync();
113}
114
115static void key_hw_probe_attn(unsigned char key)
116{
117    __attn();
118}
119
120static void key_ofdump(unsigned char key)
121{
122    printk("ofdump:\n");
123    /* make sure the OF devtree is good */
124    ofd_walk((void *)oftree, "devtree", OFD_ROOT,
125             ofd_dump_props, OFD_DUMP_ALL);
126}
127
128static void percpu_init_areas(void)
129{
130    unsigned int i, data_size = __per_cpu_data_end - __per_cpu_start;
131
132    BUG_ON(data_size > PERCPU_SIZE);
133
134    for ( i = 1; i < NR_CPUS; i++ )
135        memcpy(__per_cpu_start + (i << PERCPU_SHIFT),
136               __per_cpu_start,
137               data_size);
138}
139
140static void percpu_free_unused_areas(void)
141{
142    unsigned int i, first_unused;
143
144    /* Find first unused CPU number. */
145    for ( i = 0; i < NR_CPUS; i++ )
146        if ( !cpu_online(i) )
147            break;
148    first_unused = i;
149
150    /* Check that there are no holes in cpu_online_map. */
151    for ( ; i < NR_CPUS; i++ )
152        BUG_ON(cpu_online(i));
153
154    init_xenheap_pages((ulong)__per_cpu_start + (first_unused << PERCPU_SHIFT),
155                       (ulong)__per_cpu_end);
156}
157
158static void __init start_of_day(void)
159{
160    init_IRQ();
161
162    scheduler_init();
163
164    /* create idle domain */
165    idle_domain = domain_create(IDLE_DOMAIN_ID, 0, 0);
166    if ((idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL))
167        BUG();
168    set_current(idle_domain->vcpu[0]);
169    idle_vcpu[0] = current;
170
171    initialize_keytable();
172    /* Register another key that will allow for the the Harware Probe
173     * to be contacted, this works with RiscWatch probes and should
174     * work with Chronos and FSPs */
175    register_keyhandler('^', key_hw_probe_attn, "Trap to Hardware Probe");
176
177    /* allow the dumping of the devtree */
178    register_keyhandler('D', key_ofdump , "Dump OF Devtree");
179
180    timer_init();
181    rcu_init();
182    serial_init_postirq();
183    do_initcalls();
184}
185
186void startup_cpu_idle_loop(void)
187{
188    struct vcpu *v = current;
189
190    ASSERT(is_idle_vcpu(v));
191    cpu_set(smp_processor_id(), v->domain->domain_dirty_cpumask);
192    cpu_set(smp_processor_id(), v->vcpu_dirty_cpumask);
193
194    /* Finally get off the boot stack. */
195    reset_stack_and_jump(idle_loop);
196}
197
198/* The boot_pa is enough "parea" for the boot CPU to get thru
199 * initialization, it will ultimately get replaced later */
200static __init void init_boot_cpu(void)
201{
202    static struct processor_area boot_pa;
203    boot_pa.whoami = 0;
204    parea = &boot_pa;
205}   
206
207static void init_parea(int cpuid)
208{
209    /* Be careful not to shadow the global variable.  */
210    volatile struct processor_area *pa;
211    void *stack;
212
213    pa = xmalloc(struct processor_area);
214    if (pa == NULL)
215        panic("%s: failed to allocate parea for cpu #%d\n", __func__, cpuid);
216
217    stack = alloc_xenheap_pages(STACK_ORDER);
218    if (stack == NULL)
219        panic("%s: failed to allocate stack (order %d) for cpu #%d\n", 
220              __func__, STACK_ORDER, cpuid);
221
222    pa->whoami = cpuid;
223    pa->hard_id = cpu_hard_id[cpuid];
224    pa->hyp_stack_base = (void *)((ulong)stack + STACK_SIZE);
225    mb();
226
227    /* This store has the effect of invoking secondary_cpu_init.  */
228    global_cpu_table[cpuid] = pa;
229    mb();
230}
231
232static int kick_secondary_cpus(int maxcpus)
233{
234    int cpuid;
235
236    for_each_present_cpu(cpuid) {
237        int threads;
238        int i;
239       
240        threads = cpu_threads(cpuid);
241        for (i = 0; i < threads; i++)
242            cpu_set(i, cpu_sibling_map[cpuid]);
243
244        /* For now everything is single core */
245        cpu_set(cpuid, cpu_core_map[cpuid]);
246
247        rcu_online_cpu(cpuid);
248
249        numa_set_node(cpuid, 0);
250        numa_add_cpu(cpuid);
251
252        if (cpuid == 0)
253            continue;
254        if (cpuid >= maxcpus)
255            break;
256        init_parea(cpuid);
257        smp_generic_give_timebase();
258
259        /* wait for it */
260        while (!cpu_online(cpuid))
261            cpu_relax();
262    }
263
264    return 0;
265}
266
267/* This is the first C code that secondary processors invoke.  */
268void secondary_cpu_init(int cpuid, unsigned long r4)
269{
270    struct vcpu *vcpu;
271
272    cpu_initialize(cpuid);
273    smp_generic_take_timebase();
274
275    /* If we are online, we must be able to ACK IPIs.  */
276    mpic_setup_this_cpu();
277    cpu_set(cpuid, cpu_online_map);
278
279    vcpu = alloc_vcpu(idle_domain, cpuid, cpuid);
280    BUG_ON(vcpu == NULL);
281
282    set_current(idle_domain->vcpu[cpuid]);
283    idle_vcpu[cpuid] = current;
284    startup_cpu_idle_loop();
285
286    panic("should never get here\n");
287}
288
289static void __init __start_xen(multiboot_info_t *mbi)
290{
291    char *cmdline;
292    module_t *mod = (module_t *)((ulong)mbi->mods_addr);
293    ulong dom0_start, dom0_len;
294    ulong initrd_start, initrd_len;
295
296    memcpy(0, exception_vectors, exception_vectors_end - exception_vectors);
297    synchronize_caches(0, exception_vectors_end - exception_vectors);
298
299    ticks_per_usec = timebase_freq / 1000000ULL;
300
301    /* Parse the command-line options. */
302    if ((mbi->flags & MBI_CMDLINE) && (mbi->cmdline != 0))
303        cmdline_parse(__va((ulong)mbi->cmdline));
304
305    /* we need to be able to identify this CPU early on */
306    init_boot_cpu();
307
308    /* We initialise the serial devices very early so we can get debugging. */
309    ns16550.io_base = 0x3f8;
310    ns16550_init(0, &ns16550);
311    ns16550.io_base = 0x2f8;
312    ns16550_init(1, &ns16550);
313    serial_init_preirq();
314
315    init_console();
316    /* let synchronize until we really get going */
317    console_start_sync();
318
319    /* Check that we have at least one Multiboot module. */
320    if (!(mbi->flags & MBI_MODULES) || (mbi->mods_count == 0)) {
321        panic("FATAL ERROR: Require at least one Multiboot module.\n");
322    }
323
324    /* OF dev tree is the last module */
325    oftree = mod[mbi->mods_count-1].mod_start;
326    oftree_end = mod[mbi->mods_count-1].mod_end;
327    oftree_len = oftree_end - oftree;
328
329    /* remove it from consideration */
330    mod[mbi->mods_count-1].mod_start = 0;
331    mod[mbi->mods_count-1].mod_end = 0;
332    --mbi->mods_count;
333
334    if (rtas_entry) {
335        rtas_init((void *)oftree);
336        /* remove rtas module from consideration */
337        mod[mbi->mods_count-1].mod_start = 0;
338        mod[mbi->mods_count-1].mod_end = 0;
339        --mbi->mods_count;
340    }
341    memory_init(mod, mbi->mods_count);
342
343#ifdef OF_DEBUG
344    key_ofdump(0);
345#endif
346    percpu_init_areas();
347
348    init_parea(0);
349    cpu_initialize(0);
350
351#ifdef CONFIG_GDB
352    initialise_gdb();
353    if (opt_earlygdb)
354        debugger_trap_immediate();
355#endif
356
357    start_of_day();
358
359    mpic_setup_this_cpu();
360
361    /* Deal with secondary processors.  */
362    if (opt_nosmp || ofd_boot_cpu == -1) {
363        printk("nosmp: leaving secondary processors spinning forever\n");
364    } else {
365        printk("spinning up at most %d total processors ...\n", max_cpus);
366        kick_secondary_cpus(max_cpus);
367    }
368
369    /* This cannot be called before secondary cpus are marked online.  */
370    percpu_free_unused_areas();
371
372    /* Create initial domain 0. */
373    dom0 = domain_create(0, 0, DOM0_SSIDREF);
374    if (dom0 == NULL)
375        panic("Error creating domain 0\n");
376
377    /* The Interrupt Controller will route everything to CPU 0 so we
378     * need to make sure Dom0's vVCPU 0 is pinned to the CPU */
379    dom0->vcpu[0]->cpu_affinity = cpumask_of_cpu(0);
380
381    dom0->is_privileged = 1;
382
383    cmdline = (char *)(mod[0].string ? __va((ulong)mod[0].string) : NULL);
384
385    /* scrub_heap_pages() requires IRQs enabled, and we're post IRQ setup... */
386    local_irq_enable();
387    /* Scrub RAM that is still free and so may go to an unprivileged domain. */
388    scrub_heap_pages();
389
390    dom0_start = mod[0].mod_start;
391    dom0_len = mod[0].mod_end - mod[0].mod_start;
392    if (mbi->mods_count > 1) {
393        initrd_start = mod[1].mod_start;
394        initrd_len = mod[1].mod_end - mod[1].mod_start;
395    } else {
396        initrd_start = 0;
397        initrd_len = 0;
398    }
399    if (construct_dom0(dom0, dom0_start, dom0_len,
400                       initrd_start, initrd_len,
401                       cmdline) != 0) {
402        panic("Could not set up DOM0 guest OS\n");
403    }
404
405    init_xenheap_pages(ALIGN_UP(dom0_start, PAGE_SIZE),
406                       ALIGN_DOWN(dom0_start + dom0_len, PAGE_SIZE));
407    if (initrd_start)
408        init_xenheap_pages(ALIGN_UP(initrd_start, PAGE_SIZE),
409                           ALIGN_DOWN(initrd_start + initrd_len, PAGE_SIZE));
410
411    init_trace_bufs();
412
413    console_endboot();
414
415    /* Hide UART from DOM0 if we're using it */
416    serial_endboot();
417
418    console_end_sync();
419
420    domain_unpause_by_systemcontroller(dom0);
421#ifdef DEBUG_IPI
422    ipi_torture_test();
423#endif
424    startup_cpu_idle_loop();
425}
426
427void __init __start_xen_ppc(
428    ulong r3, ulong r4, ulong r5, ulong r6, ulong r7, ulong orig_msr)
429{
430    multiboot_info_t *mbi = NULL;
431
432    /* clear bss */
433    memset(__bss_start, 0, (ulong)_end - (ulong)__bss_start);
434
435    if (r5 > 0) {
436        /* we were booted by OpenFirmware */
437        mbi = boot_of_init(r3, r4, r5, r6, r7, orig_msr);
438
439    } else {
440        /* booted by someone else that hopefully has a trap handler */
441        __builtin_trap();
442    }
443
444    __start_xen(mbi);
445
446}
447
448extern void arch_get_xen_caps(xen_capabilities_info_t *info);
449void arch_get_xen_caps(xen_capabilities_info_t *info)
450{
451    /* Interface name is always xen-3.0-* for Xen-3.x. */
452    int major = 3, minor = 0;
453    char s[32];
454
455    (*info)[0] = '\0';
456
457    snprintf(s, sizeof(s), "xen-%d.%d-powerpc64 ", major, minor);
458    safe_strcat(*info, s);
459}
460
461
462
463/*
464 * Local variables:
465 * mode: C
466 * c-set-style: "BSD"
467 * c-basic-offset: 4
468 * tab-width: 4
469 * indent-tabs-mode: nil
470 * End:
471 */
Note: See TracBrowser for help on using the repository browser.