ia64/xen-unstable

view xen/arch/powerpc/setup.c @ 12970:dbc7ea73f5b2

[XEN][POWERPC] secondary_cpu_init() does not return.
Signed-off-by: Jimi Xenidis <jimix@watson.ibm.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
author Jimi Xenidis <jimix@watson.ibm.com>
date Tue Nov 28 16:43:53 2006 -0500 (2006-11-28)
parents b4594f072a89
children a510c94ceaa3
line source
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 (C) IBM Corp. 2005, 2006
17 *
18 * Authors: Jimi Xenidis <jimix@watson.ibm.com>
19 * Amos Waterland <apw@us.ibm.com>
20 * Hollis Blanchard <hollisb@us.ibm.com>
21 */
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 <acm/acm_hooks.h>
39 #include <public/version.h>
40 #include <asm/mpic.h>
41 #include <asm/processor.h>
42 #include <asm/desc.h>
43 #include <asm/cache.h>
44 #include <asm/debugger.h>
45 #include <asm/delay.h>
46 #include <asm/percpu.h>
47 #include <asm/io.h>
48 #include "exceptions.h"
49 #include "of-devtree.h"
50 #include "oftree.h"
51 #include "rtas.h"
53 #define DEBUG
55 /* opt_noht: If true, Hyperthreading is ignored. */
56 int opt_noht = 0;
57 boolean_param("noht", opt_noht);
59 int opt_earlygdb = 0;
60 boolean_param("earlygdb", opt_earlygdb);
62 /* opt_nosmp: If true, secondary processors are ignored. */
63 static int opt_nosmp = 0;
64 boolean_param("nosmp", opt_nosmp);
66 /* maxcpus: maximum number of CPUs to activate. */
67 static unsigned int max_cpus = NR_CPUS;
68 integer_param("maxcpus", max_cpus);
70 u32 tlbflush_clock = 1U;
71 DEFINE_PER_CPU(u32, tlbflush_time);
73 unsigned int watchdog_on;
74 unsigned long wait_init_idle;
75 ulong oftree;
76 ulong oftree_len;
77 ulong oftree_end;
79 uint cpu_hard_id[NR_CPUS] __initdata;
80 cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
81 cpumask_t cpu_online_map; /* missing ifdef in schedule.c */
82 cpumask_t cpu_present_map;
83 cpumask_t cpu_possible_map;
85 /* XXX get this from ISA node in device tree */
86 char *vgabase;
87 ulong isa_io_base;
88 struct ns16550_defaults ns16550;
90 extern char __per_cpu_start[], __per_cpu_data_end[], __per_cpu_end[];
92 static struct domain *idle_domain;
94 volatile struct processor_area * volatile global_cpu_table[NR_CPUS];
96 int is_kernel_text(unsigned long addr)
97 {
98 if (addr >= (unsigned long) &_start &&
99 addr <= (unsigned long) &_etext)
100 return 1;
101 return 0;
102 }
104 unsigned long kernel_text_end(void)
105 {
106 return (unsigned long) &_etext;
107 }
109 static void __init do_initcalls(void)
110 {
111 initcall_t *call;
112 for (call = &__initcall_start; call < &__initcall_end; call++) {
113 (*call)();
114 }
115 }
118 void noinline __attn(void)
119 {
120 /* To continue the probe will step over the ATTN instruction. The
121 * NOP is there to make sure there is something sane to "step
122 * over" to. */
123 console_start_sync();
124 asm volatile(".long 0x200;nop");
125 console_end_sync();
126 }
128 static void key_hw_probe_attn(unsigned char key)
129 {
130 __attn();
131 }
133 static void key_ofdump(unsigned char key)
134 {
135 printk("ofdump:\n");
136 /* make sure the OF devtree is good */
137 ofd_walk((void *)oftree, "devtree", OFD_ROOT,
138 ofd_dump_props, OFD_DUMP_ALL);
139 }
141 static void percpu_init_areas(void)
142 {
143 unsigned int i, data_size = __per_cpu_data_end - __per_cpu_start;
145 BUG_ON(data_size > PERCPU_SIZE);
147 for ( i = 1; i < NR_CPUS; i++ )
148 memcpy(__per_cpu_start + (i << PERCPU_SHIFT),
149 __per_cpu_start,
150 data_size);
151 }
153 static void percpu_free_unused_areas(void)
154 {
155 unsigned int i, first_unused;
157 /* Find first unused CPU number. */
158 for ( i = 0; i < NR_CPUS; i++ )
159 if ( !cpu_online(i) )
160 break;
161 first_unused = i;
163 /* Check that there are no holes in cpu_online_map. */
164 for ( ; i < NR_CPUS; i++ )
165 BUG_ON(cpu_online(i));
167 init_xenheap_pages((ulong)__per_cpu_start + (first_unused << PERCPU_SHIFT),
168 (ulong)__per_cpu_end);
169 }
171 static void __init start_of_day(void)
172 {
173 init_IRQ();
175 scheduler_init();
177 /* create idle domain */
178 idle_domain = domain_create(IDLE_DOMAIN_ID, 0);
179 if ((idle_domain == NULL) || (alloc_vcpu(idle_domain, 0, 0) == NULL))
180 BUG();
181 set_current(idle_domain->vcpu[0]);
182 idle_vcpu[0] = current;
184 /* for some reason we need to set our own bit in the thread map */
185 cpu_set(0, cpu_sibling_map[0]);
187 initialize_keytable();
188 /* Register another key that will allow for the the Harware Probe
189 * to be contacted, this works with RiscWatch probes and should
190 * work with Chronos and FSPs */
191 register_keyhandler('^', key_hw_probe_attn, "Trap to Hardware Probe");
193 /* allow the dumping of the devtree */
194 register_keyhandler('D', key_ofdump , "Dump OF Devtree");
196 timer_init();
197 serial_init_postirq();
198 do_initcalls();
199 }
201 void startup_cpu_idle_loop(void)
202 {
203 struct vcpu *v = current;
205 ASSERT(is_idle_vcpu(v));
206 cpu_set(smp_processor_id(), v->domain->domain_dirty_cpumask);
207 cpu_set(smp_processor_id(), v->vcpu_dirty_cpumask);
209 /* Finally get off the boot stack. */
210 reset_stack_and_jump(idle_loop);
211 }
213 static void init_parea(int cpuid)
214 {
215 /* Be careful not to shadow the global variable. */
216 volatile struct processor_area *pa;
217 void *stack;
219 pa = xmalloc(struct processor_area);
220 if (pa == NULL)
221 panic("%s: failed to allocate parea for cpu #%d\n", __func__, cpuid);
223 stack = alloc_xenheap_pages(STACK_ORDER);
224 if (stack == NULL)
225 panic("%s: failed to allocate stack (order %d) for cpu #%d\n",
226 __func__, STACK_ORDER, cpuid);
228 pa->whoami = cpuid;
229 pa->hard_id = cpu_hard_id[cpuid];
230 pa->hyp_stack_base = (void *)((ulong)stack + STACK_SIZE);
231 mb();
233 /* This store has the effect of invoking secondary_cpu_init. */
234 global_cpu_table[cpuid] = pa;
235 mb();
236 }
238 static int kick_secondary_cpus(int maxcpus)
239 {
240 int cpuid;
242 for_each_present_cpu(cpuid) {
243 if (cpuid == 0)
244 continue;
245 if (cpuid >= maxcpus)
246 break;
247 init_parea(cpuid);
248 smp_generic_give_timebase();
250 /* wait for it */
251 while (!cpu_online(cpuid))
252 cpu_relax();
253 }
255 return 0;
256 }
258 /* This is the first C code that secondary processors invoke. */
259 void secondary_cpu_init(int cpuid, unsigned long r4)
260 {
261 struct vcpu *vcpu;
263 cpu_initialize(cpuid);
264 smp_generic_take_timebase();
266 /* If we are online, we must be able to ACK IPIs. */
267 mpic_setup_this_cpu();
268 cpu_set(cpuid, cpu_online_map);
270 vcpu = alloc_vcpu(idle_domain, cpuid, cpuid);
271 BUG_ON(vcpu == NULL);
273 set_current(idle_domain->vcpu[cpuid]);
274 idle_vcpu[cpuid] = current;
275 startup_cpu_idle_loop();
277 panic("should never get here\n");
278 }
280 static void __init __start_xen(multiboot_info_t *mbi)
281 {
282 char *cmdline;
283 module_t *mod = (module_t *)((ulong)mbi->mods_addr);
284 ulong dom0_start, dom0_len;
285 ulong initrd_start, initrd_len;
287 memcpy(0, exception_vectors, exception_vectors_end - exception_vectors);
288 synchronize_caches(0, exception_vectors_end - exception_vectors);
290 ticks_per_usec = timebase_freq / 1000000ULL;
292 /* Parse the command-line options. */
293 if ((mbi->flags & MBI_CMDLINE) && (mbi->cmdline != 0))
294 cmdline_parse(__va((ulong)mbi->cmdline));
296 /* We initialise the serial devices very early so we can get debugging. */
297 ns16550.io_base = 0x3f8;
298 ns16550_init(0, &ns16550);
299 ns16550.io_base = 0x2f8;
300 ns16550_init(1, &ns16550);
301 serial_init_preirq();
303 init_console();
304 /* let synchronize until we really get going */
305 console_start_sync();
307 /* Check that we have at least one Multiboot module. */
308 if (!(mbi->flags & MBI_MODULES) || (mbi->mods_count == 0)) {
309 panic("FATAL ERROR: Require at least one Multiboot module.\n");
310 }
312 /* OF dev tree is the last module */
313 oftree = mod[mbi->mods_count-1].mod_start;
314 oftree_end = mod[mbi->mods_count-1].mod_end;
315 oftree_len = oftree_end - oftree;
317 /* remove it from consideration */
318 mod[mbi->mods_count-1].mod_start = 0;
319 mod[mbi->mods_count-1].mod_end = 0;
320 --mbi->mods_count;
322 if (rtas_entry) {
323 rtas_init((void *)oftree);
324 /* remove rtas module from consideration */
325 mod[mbi->mods_count-1].mod_start = 0;
326 mod[mbi->mods_count-1].mod_end = 0;
327 --mbi->mods_count;
328 }
329 memory_init(mod, mbi->mods_count);
331 #ifdef OF_DEBUG
332 key_ofdump(0);
333 #endif
334 percpu_init_areas();
336 init_parea(0);
337 cpu_initialize(0);
339 #ifdef CONFIG_GDB
340 initialise_gdb();
341 if (opt_earlygdb)
342 debugger_trap_immediate();
343 #endif
345 start_of_day();
347 mpic_setup_this_cpu();
349 /* Deal with secondary processors. */
350 if (opt_nosmp || ofd_boot_cpu == -1) {
351 printk("nosmp: leaving secondary processors spinning forever\n");
352 } else {
353 printk("spinning up at most %d total processors ...\n", max_cpus);
354 kick_secondary_cpus(max_cpus);
355 }
357 /* Secondary processors must be online before we call this. */
358 schedulers_start();
360 /* This cannot be called before secondary cpus are marked online. */
361 percpu_free_unused_areas();
363 /* Create initial domain 0. */
364 dom0 = domain_create(0, 0);
365 if (dom0 == NULL)
366 panic("Error creating domain 0\n");
367 dom0->max_pages = ~0U;
368 if (0 > allocate_rma(dom0, cpu_default_rma_order_pages()))
369 panic("Error allocating domain 0 RMA\n");
370 if (NULL == alloc_vcpu(dom0, 0, 0))
371 panic("Error creating domain 0 vcpu 0\n");
373 /* The Interrupt Controller will route everything to CPU 0 so we
374 * need to make sure Dom0's vVCPU 0 is pinned to the CPU */
375 dom0->vcpu[0]->cpu_affinity = cpumask_of_cpu(0);
377 dom0->is_privileged = 1;
379 /* Post-create hook sets security label. */
380 acm_post_domain0_create(dom0->domain_id);
382 cmdline = (char *)(mod[0].string ? __va((ulong)mod[0].string) : NULL);
384 /* scrub_heap_pages() requires IRQs enabled, and we're post IRQ setup... */
385 local_irq_enable();
386 /* Scrub RAM that is still free and so may go to an unprivileged domain. */
387 scrub_heap_pages();
389 dom0_start = mod[0].mod_start;
390 dom0_len = mod[0].mod_end - mod[0].mod_start;
391 if (mbi->mods_count > 1) {
392 initrd_start = mod[1].mod_start;
393 initrd_len = mod[1].mod_end - mod[1].mod_start;
394 } else {
395 initrd_start = 0;
396 initrd_len = 0;
397 }
398 if (construct_dom0(dom0, dom0_start, dom0_len,
399 initrd_start, initrd_len,
400 cmdline) != 0) {
401 panic("Could not set up DOM0 guest OS\n");
402 }
404 init_xenheap_pages(ALIGN_UP(dom0_start, PAGE_SIZE),
405 ALIGN_DOWN(dom0_start + dom0_len, PAGE_SIZE));
406 if (initrd_start)
407 init_xenheap_pages(ALIGN_UP(initrd_start, PAGE_SIZE),
408 ALIGN_DOWN(initrd_start + initrd_len, PAGE_SIZE));
410 init_trace_bufs();
412 console_endboot();
414 /* Hide UART from DOM0 if we're using it */
415 serial_endboot();
417 console_end_sync();
419 domain_unpause_by_systemcontroller(dom0);
420 #ifdef DEBUG_IPI
421 ipi_torture_test();
422 #endif
423 startup_cpu_idle_loop();
424 }
426 void __init __start_xen_ppc(
427 ulong r3, ulong r4, ulong r5, ulong r6, ulong r7, ulong orig_msr)
428 {
429 multiboot_info_t *mbi = NULL;
431 /* clear bss */
432 memset(__bss_start, 0, (ulong)_end - (ulong)__bss_start);
434 if (r5 > 0) {
435 /* we were booted by OpenFirmware */
436 mbi = boot_of_init(r3, r4, r5, r6, r7, orig_msr);
438 } else {
439 /* booted by someone else that hopefully has a trap handler */
440 __builtin_trap();
441 }
443 __start_xen(mbi);
445 }
447 extern void arch_get_xen_caps(xen_capabilities_info_t info);
448 void arch_get_xen_caps(xen_capabilities_info_t info)
449 {
450 }
454 /*
455 * Local variables:
456 * mode: C
457 * c-set-style: "BSD"
458 * c-basic-offset: 4
459 * tab-width: 4
460 * indent-tabs-mode: nil
461 * End:
462 */