[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Merge
# HG changeset patch # User Ian Jackson <Ian.Jackson@xxxxxxxxxxxxx> # Date 1331652521 0 # Node ID d54cf3fa7ee6d57acf7500cd53da135e0c584948 # Parent 703a339e11abf1ea14ee528f4194b308fcb3ea88 # Parent 773d0367087212c43faf8cdcc21cf443b1ea0046 Merge --- diff -r 703a339e11ab -r d54cf3fa7ee6 xen/arch/arm/Makefile --- a/xen/arch/arm/Makefile Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/arch/arm/Makefile Tue Mar 13 15:28:41 2012 +0000 @@ -13,6 +13,7 @@ obj-y += kernel.o obj-y += mm.o obj-y += p2m.o +obj-y += percpu.o obj-y += guestcopy.o obj-y += setup.o obj-y += time.o diff -r 703a339e11ab -r d54cf3fa7ee6 xen/arch/arm/domain.c --- a/xen/arch/arm/domain.c Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/arch/arm/domain.c Tue Mar 13 15:28:41 2012 +0000 @@ -31,12 +31,14 @@ { for ( ; ; ) { - /* TODO - if ( cpu_is_offline(smp_processor_id()) ) - play_dead(); - (*pm_idle)(); - BUG(); - */ + if ( cpu_is_offline(smp_processor_id()) ) + stop_cpu(); + + local_irq_disable(); + if ( cpu_is_haltable(smp_processor_id()) ) + asm volatile ("dsb; wfi"); + local_irq_enable(); + do_tasklet(); do_softirq(); } diff -r 703a339e11ab -r d54cf3fa7ee6 xen/arch/arm/dummy.S --- a/xen/arch/arm/dummy.S Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/arch/arm/dummy.S Tue Mar 13 15:28:41 2012 +0000 @@ -7,14 +7,10 @@ x: mov pc, lr /* SMP support */ -DUMMY(__cpu_die); -DUMMY(__cpu_disable); -DUMMY(__cpu_up); DUMMY(per_cpu__cpu_core_mask); DUMMY(per_cpu__cpu_sibling_mask); DUMMY(node_online_map); DUMMY(smp_send_state_dump); -DUMMY(__per_cpu_offset); /* PIRQ support */ DUMMY(alloc_pirq_struct); @@ -62,5 +58,4 @@ DUMMY(hypercall_create_continuation); DUMMY(send_timer_event); DUMMY(share_xen_page_with_privileged_guests); -DUMMY(__udelay); DUMMY(wallclock_time); diff -r 703a339e11ab -r d54cf3fa7ee6 xen/arch/arm/gic.c --- a/xen/arch/arm/gic.c Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/arch/arm/gic.c Tue Mar 13 15:28:41 2012 +0000 @@ -224,7 +224,9 @@ { int i; - /* Disable all PPI and enable all SGI */ + /* The first 32 interrupts (PPI and SGI) are banked per-cpu, so + * even though they are controlled with GICD registers, they must + * be set up here with the other per-cpu state. */ GICD[GICD_ICENABLER] = 0xffff0000; /* Disable all PPI */ GICD[GICD_ISENABLER] = 0x0000ffff; /* Enable all SGI */ /* Set PPI and SGI priorities */ @@ -237,20 +239,29 @@ GICC[GICC_CTLR] = GICC_CTL_ENABLE|GICC_CTL_EOI; /* Turn on delivery */ } +static void gic_cpu_disable(void) +{ + GICC[GICC_CTLR] = 0; +} + static void __cpuinit gic_hyp_init(void) { uint32_t vtr; vtr = GICH[GICH_VTR]; nr_lrs = (vtr & GICH_VTR_NRLRGS) + 1; - printk("GICH: %d list registers available\n", nr_lrs); GICH[GICH_HCR] = GICH_HCR_EN; GICH[GICH_MISR] = GICH_MISR_EOI; } +static void __cpuinit gic_hyp_disable(void) +{ + GICH[GICH_HCR] = 0; +} + /* Set up the GIC */ -void gic_init(void) +int __init gic_init(void) { /* XXX FIXME get this from devicetree */ gic.dbase = GIC_BASE_ADDRESS + GIC_DR_OFFSET; @@ -272,6 +283,26 @@ gic_hyp_init(); spin_unlock(&gic.lock); + + return gic.cpus; +} + +/* Set up the per-CPU parts of the GIC for a secondary CPU */ +void __cpuinit gic_init_secondary_cpu(void) +{ + spin_lock(&gic.lock); + gic_cpu_init(); + gic_hyp_init(); + spin_unlock(&gic.lock); +} + +/* Shut down the per-CPU GIC interface */ +void gic_disable_cpu(void) +{ + spin_lock(&gic.lock); + gic_cpu_disable(); + gic_hyp_disable(); + spin_unlock(&gic.lock); } void gic_route_irqs(void) diff -r 703a339e11ab -r d54cf3fa7ee6 xen/arch/arm/gic.h --- a/xen/arch/arm/gic.h Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/arch/arm/gic.h Tue Mar 13 15:28:41 2012 +0000 @@ -138,8 +138,12 @@ /* Accept an interrupt from the GIC and dispatch its handler */ extern void gic_interrupt(struct cpu_user_regs *regs, int is_fiq); -/* Bring up the interrupt controller */ -extern void gic_init(void); +/* Bring up the interrupt controller, and report # cpus attached */ +extern int gic_init(void); +/* Bring up a secondary CPU's per-CPU GIC interface */ +extern void gic_init_secondary_cpu(void); +/* Take down a CPU's per-CPU GIC interface */ +extern void gic_disable_cpu(void); /* setup the gic virtual interface for a guest */ extern void gicv_setup(struct domain *d); #endif diff -r 703a339e11ab -r d54cf3fa7ee6 xen/arch/arm/head.S --- a/xen/arch/arm/head.S Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/arch/arm/head.S Tue Mar 13 15:28:41 2012 +0000 @@ -62,22 +62,36 @@ #endif /* Are we the boot CPU? */ + mov r12, #0 /* r12 := CPU ID */ mrc CP32(r0, MPIDR) tst r0, #(1<<31) /* Multiprocessor extension supported? */ beq boot_cpu tst r0, #(1<<30) /* Uniprocessor system? */ bne boot_cpu - bics r0, r0, #(0xff << 24) /* Ignore flags */ - beq boot_cpu /* If all other fields are 0, we win */ + bics r12, r0, #(0xff << 24) /* Mask out flags to get CPU ID */ + beq boot_cpu /* If we're CPU 0, boot now */ -1: wfi - b 1b - + /* Non-boot CPUs wait here to be woken up one at a time. + * This is basically an open-coded spin-lock to serialize. */ + ldr r0, =boot_gate /* VA of gate */ + add r0, r0, r10 /* PA of gate */ + mov r1, #1 /* (1 == locked) */ +1: wfe + ldrex r2, [r0] /* Linked read of current value */ + teq r2, #0 /* (0 == unlocked) */ + strexeq r2, r1, [r0] /* Matching update -> locked */ + teq r2, #0 /* (0 == succeeded) */ + bne 1b + boot_cpu: #ifdef EARLY_UART_ADDRESS - /* Say hello */ ldr r11, =EARLY_UART_ADDRESS /* r11 := UART base address */ - bl init_uart + teq r12, #0 /* CPU 0 sets up the UART too */ + bleq init_uart + PRINT("- CPU ") + mov r0, r12 + bl putn + PRINT(" booting -\r\n") #endif /* Check that this CPU has Hyp mode */ @@ -85,7 +99,6 @@ and r0, r0, #0xf000 /* Bits 12-15 define virt extensions */ teq r0, #0x1000 /* Must == 0x1 or may be incompatible */ beq 1f - bl putn PRINT("- CPU doesn't support the virtualization extensions -\r\n") b fail 1: @@ -185,6 +198,10 @@ mov r5, #0 /* r4:r5 is paddr (xen_pagetable) */ mcrr CP64(r4, r5, HTTBR) + /* Non-boot CPUs don't need to rebuild the pagetable */ + teq r12, #0 + bne pt_ready + /* Build the baseline idle pagetable's first-level entries */ ldr r1, =xen_second add r1, r1, r10 /* r1 := paddr (xen_second) */ @@ -226,6 +243,7 @@ add r4, r4, #8 strd r2, r3, [r1, r4] /* Map it in the early boot slot */ +pt_ready: PRINT("- Turning on paging -\r\n") ldr r1, =paging /* Explicit vaddr, not RIP-relative */ @@ -238,7 +256,7 @@ paging: #ifdef EARLY_UART_ADDRESS - /* Recover the UART address in the new address space */ + /* Recover the UART address in the new address space. */ lsl r11, #11 lsr r11, #11 /* UART base's offset from 2MB base */ adr r0, start @@ -246,15 +264,66 @@ add r11, r11, r0 /* r11 := vaddr (UART base address) */ #endif - PRINT("- Entering C -\r\n") + PRINT("- Ready -\r\n") - ldr sp, =init_stack /* Supply a stack */ + /* The boot CPU should go straight into C now */ + teq r12, #0 + beq launch + + /* Signal the next non-boot CPU to come and join us here */ + ldr r0, =boot_gate /* VA of gate */ + add r0, r0, r10 /* PA of gate */ + mov r1, #0 /* (0 == unlocked) */ + str r1, [r0] + dsb + isb + sev + + /* Move on to the relocated pagetables */ + mov r0, #0 + ldr r4, =boot_httbr /* VA of HTTBR value stashed by CPU 0 */ + add r4, r4, r10 /* PA of it */ + ldrd r4, r5, [r4] /* Actual value */ + mcrr CP64(r4, r5, HTTBR) + mcr CP32(r0, TLBIALLH) /* Flush hypervisor TLB */ + mcr CP32(r0, BPIALL) /* Flush branch predictor */ + dsb /* Ensure completion of TLB+BP flush */ + isb + /* Now, the UART is in its proper fixmap address */ + ldrne r11, =FIXMAP_ADDR(FIXMAP_CONSOLE) + + /* Non-boot CPUs report that they've got this far */ + ldr r0, =ready_cpus +1: ldrex r1, [r0] /* { read # of ready CPUs } */ + add r1, r1, #1 /* Atomically { ++ } */ + strex r2, r1, [r0] /* { writeback } */ + teq r2, #0 + bne 1b + dsb + + /* Here, the non-boot CPUs must wait again -- they're now running on + * the boot CPU's pagetables so it's safe for the boot CPU to + * overwrite the non-relocated copy of Xen. Once it's done that, + * and brought up the memory allocator, non-boot CPUs can get their + * own stacks and enter C. */ +1: wfe + dsb + ldr r0, =smp_up_cpu + ldr r1, [r0] /* Which CPU is being booted? */ + teq r1, r12 /* Is it us? */ + bne 1b + +launch: + ldr r0, =init_stack /* Find the boot-time stack */ + ldr sp, [r0] add sp, #STACK_SIZE /* (which grows down from the top). */ sub sp, #CPUINFO_sizeof /* Make room for CPU save record */ mov r0, r10 /* Marshal args: - phys_offset */ mov r1, r7 /* - machine type */ mov r2, r8 /* - ATAG address */ - b start_xen /* and disappear into the land of C */ + movs r3, r12 /* - CPU ID */ + beq start_xen /* and disappear into the land of C */ + b start_secondary /* (to the appropriate entry point) */ /* Fail-stop * r0: string explaining why */ @@ -288,7 +357,7 @@ tst r2, #0x8 /* Check BUSY bit */ bne puts /* Wait for the UART to be ready */ ldrb r2, [r0], #1 /* Load next char */ - teq r2, #0 /* Exit on nul*/ + teq r2, #0 /* Exit on nul */ moveq pc, lr str r2, [r11] /* -> UARTDR (Data Register) */ b puts @@ -308,10 +377,8 @@ lsl r0, #4 /* Roll it through one nybble at a time */ subs r3, r3, #1 bne 1b - adr r0, crlf /* Finish with a newline */ - b puts + mov pc, lr -crlf: .asciz "\r\n" hex: .ascii "0123456789abcdef" .align 2 diff -r 703a339e11ab -r d54cf3fa7ee6 xen/arch/arm/mm.c --- a/xen/arch/arm/mm.c Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/arch/arm/mm.c Tue Mar 13 15:28:41 2012 +0000 @@ -36,6 +36,9 @@ static lpae_t xen_fixmap[LPAE_ENTRIES] __attribute__((__aligned__(4096))); static lpae_t xen_xenmap[LPAE_ENTRIES] __attribute__((__aligned__(4096))); +/* Non-boot CPUs use this to find the correct pagetables. */ +uint64_t boot_httbr; + /* Limits of the Xen heap */ unsigned long xenheap_mfn_start, xenheap_mfn_end; unsigned long xenheap_virt_end; @@ -45,6 +48,8 @@ unsigned long max_page; +extern char __init_begin[], __init_end[]; + /* Map a 4k page in a fixmap entry */ void set_fixmap(unsigned map, unsigned long mfn, unsigned attributes) { @@ -156,14 +161,6 @@ lpae_t pte, *p; int i; - if ( boot_phys_offset != 0 ) - { - /* Remove the old identity mapping of the boot paddr */ - pte.bits = 0; - dest_va = (unsigned long)_start + boot_phys_offset; - write_pte(xen_second + second_linear_offset(dest_va), pte); - } - xen_paddr = device_tree_get_xen_paddr(); /* Map the destination in the boot misc area. */ @@ -186,11 +183,18 @@ for ( i = 0; i < 4; i++) p[i].pt.base += (phys_offset - boot_phys_offset) >> PAGE_SHIFT; p = (void *) xen_second + dest_va - (unsigned long) _start; + if ( boot_phys_offset != 0 ) + { + /* Remove the old identity mapping of the boot paddr */ + unsigned long va = (unsigned long)_start + boot_phys_offset; + p[second_linear_offset(va)].bits = 0; + } for ( i = 0; i < 4 * LPAE_ENTRIES; i++) if ( p[i].pt.valid ) p[i].pt.base += (phys_offset - boot_phys_offset) >> PAGE_SHIFT; /* Change pagetables to the copy in the relocated Xen */ + boot_httbr = (unsigned long) xen_pgtable + phys_offset; asm volatile ( STORE_CP64(0, HTTBR) /* Change translation base */ "dsb;" /* Ensure visibility of HTTBR update */ @@ -198,22 +202,12 @@ STORE_CP32(0, BPIALL) /* Flush branch predictor */ "dsb;" /* Ensure completion of TLB+BP flush */ "isb;" - : : "r" ((unsigned long) xen_pgtable + phys_offset) : "memory"); + : : "r" (boot_httbr) : "memory"); /* Undo the temporary map */ pte.bits = 0; write_pte(xen_second + second_table_offset(dest_va), pte); - /* - * Have removed a mapping previously used for .text. Flush everything - * for safety. - */ - asm volatile ( - "dsb;" /* Ensure visibility of PTE write */ - STORE_CP32(0, TLBIALLH) /* Flush hypervisor TLB */ - STORE_CP32(0, BPIALL) /* Flush branch predictor */ - "dsb;" /* Ensure completion of TLB+BP flush */ - "isb;" - : : "r" (i /*dummy*/) : "memory"); + flush_xen_text_tlb(); /* Link in the fixmap pagetable */ pte = mfn_to_xen_entry((((unsigned long) xen_fixmap) + phys_offset) @@ -249,18 +243,19 @@ pte.pt.table = 1; write_pte(xen_second + second_linear_offset(XEN_VIRT_START), pte); /* Have changed a mapping used for .text. Flush everything for safety. */ - asm volatile ( - "dsb;" /* Ensure visibility of PTE write */ - STORE_CP32(0, TLBIALLH) /* Flush hypervisor TLB */ - STORE_CP32(0, BPIALL) /* Flush branch predictor */ - "dsb;" /* Ensure completion of TLB+BP flush */ - "isb;" - : : "r" (i /*dummy*/) : "memory"); + flush_xen_text_tlb(); /* From now on, no mapping may be both writable and executable. */ WRITE_CP32(READ_CP32(HSCTLR) | SCTLR_WXN, HSCTLR); } +/* MMU setup for secondary CPUS (which already have paging enabled) */ +void __cpuinit mmu_init_secondary_cpu(void) +{ + /* From now on, no mapping may be both writable and executable. */ + WRITE_CP32(READ_CP32(HSCTLR) | SCTLR_WXN, HSCTLR); +} + /* Create Xen's mappings of memory. * Base and virt must be 32MB aligned and size a multiple of 32MB. */ static void __init create_mappings(unsigned long virt, @@ -319,6 +314,64 @@ frametable_virt_end = FRAMETABLE_VIRT_START + (nr_pages * sizeof(struct page_info)); } +enum mg { mg_clear, mg_ro, mg_rw, mg_rx }; +static void set_pte_flags_on_range(const char *p, unsigned long l, enum mg mg) +{ + lpae_t pte; + int i; + + ASSERT(is_kernel(p) && is_kernel(p + l)); + + /* Can only guard in page granularity */ + ASSERT(!((unsigned long) p & ~PAGE_MASK)); + ASSERT(!(l & ~PAGE_MASK)); + + for ( i = (p - _start) / PAGE_SIZE; + i < (p + l - _start) / PAGE_SIZE; + i++ ) + { + pte = xen_xenmap[i]; + switch ( mg ) + { + case mg_clear: + pte.pt.valid = 0; + break; + case mg_ro: + pte.pt.valid = 1; + pte.pt.pxn = 1; + pte.pt.xn = 1; + pte.pt.ro = 1; + break; + case mg_rw: + pte.pt.valid = 1; + pte.pt.pxn = 1; + pte.pt.xn = 1; + pte.pt.ro = 0; + break; + case mg_rx: + pte.pt.valid = 1; + pte.pt.pxn = 0; + pte.pt.xn = 0; + pte.pt.ro = 1; + break; + } + write_pte(xen_xenmap + i, pte); + } + flush_xen_text_tlb(); +} + +/* Release all __init and __initdata ranges to be reused */ +void free_init_memory(void) +{ + paddr_t pa = virt_to_maddr(__init_begin); + unsigned long len = __init_end - __init_begin; + set_pte_flags_on_range(__init_begin, len, mg_rw); + memset(__init_begin, 0xcc, len); + set_pte_flags_on_range(__init_begin, len, mg_clear); + init_domheap_pages(pa, pa + len); + printk("Freed %ldkB init memory.\n", (long)(__init_end-__init_begin)>>10); +} + void arch_dump_shared_mem_info(void) { } diff -r 703a339e11ab -r d54cf3fa7ee6 xen/arch/arm/percpu.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/arm/percpu.c Tue Mar 13 15:28:41 2012 +0000 @@ -0,0 +1,85 @@ +#include <xen/config.h> +#include <xen/percpu.h> +#include <xen/cpu.h> +#include <xen/init.h> +#include <xen/mm.h> +#include <xen/rcupdate.h> + +unsigned long __per_cpu_offset[NR_CPUS]; +#define INVALID_PERCPU_AREA (-(long)__per_cpu_start) +#define PERCPU_ORDER (get_order_from_bytes(__per_cpu_data_end-__per_cpu_start)) + +void __init percpu_init_areas(void) +{ + unsigned int cpu; + for ( cpu = 1; cpu < NR_CPUS; cpu++ ) + __per_cpu_offset[cpu] = INVALID_PERCPU_AREA; +} + +static int init_percpu_area(unsigned int cpu) +{ + char *p; + if ( __per_cpu_offset[cpu] != INVALID_PERCPU_AREA ) + return -EBUSY; + if ( (p = alloc_xenheap_pages(PERCPU_ORDER, 0)) == NULL ) + return -ENOMEM; + memset(p, 0, __per_cpu_data_end - __per_cpu_start); + __per_cpu_offset[cpu] = p - __per_cpu_start; + return 0; +} + +struct free_info { + unsigned int cpu; + struct rcu_head rcu; +}; +static DEFINE_PER_CPU(struct free_info, free_info); + +static void _free_percpu_area(struct rcu_head *head) +{ + struct free_info *info = container_of(head, struct free_info, rcu); + unsigned int cpu = info->cpu; + char *p = __per_cpu_start + __per_cpu_offset[cpu]; + free_xenheap_pages(p, PERCPU_ORDER); + __per_cpu_offset[cpu] = INVALID_PERCPU_AREA; +} + +static void free_percpu_area(unsigned int cpu) +{ + struct free_info *info = &per_cpu(free_info, cpu); + info->cpu = cpu; + call_rcu(&info->rcu, _free_percpu_area); +} + +static int cpu_percpu_callback( + struct notifier_block *nfb, unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + int rc = 0; + + switch ( action ) + { + case CPU_UP_PREPARE: + rc = init_percpu_area(cpu); + break; + case CPU_UP_CANCELED: + case CPU_DEAD: + free_percpu_area(cpu); + break; + default: + break; + } + + return !rc ? NOTIFY_DONE : notifier_from_errno(rc); +} + +static struct notifier_block cpu_percpu_nfb = { + .notifier_call = cpu_percpu_callback, + .priority = 100 /* highest priority */ +}; + +static int __init percpu_presmp_init(void) +{ + register_cpu_notifier(&cpu_percpu_nfb); + return 0; +} +presmp_initcall(percpu_presmp_init); diff -r 703a339e11ab -r d54cf3fa7ee6 xen/arch/arm/setup.c --- a/xen/arch/arm/setup.c Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/arch/arm/setup.c Tue Mar 13 15:28:41 2012 +0000 @@ -38,22 +38,14 @@ #include <asm/setup.h> #include "gic.h" -/* maxcpus: maximum number of CPUs to activate. */ -static unsigned int __initdata max_cpus = NR_CPUS; - -/* Xen stack for bringing up the first CPU. */ -unsigned char __initdata init_stack[STACK_SIZE] __attribute__((__aligned__(STACK_SIZE))); - -extern char __init_begin[], __init_end[], __bss_start[]; +/* Spinlock for serializing CPU bringup */ +unsigned long __initdata boot_gate = 1; +/* Number of non-boot CPUs ready to enter C */ +unsigned long __initdata ready_cpus = 0; static __attribute_used__ void init_done(void) { - /* TODO: free (or page-protect) the init areas. - memset(__init_begin, 0xcc, __init_end - __init_begin); - free_xen_data(__init_begin, __init_end); - */ - printk("Freed %ldkB init memory.\n", (long)(__init_end-__init_begin)>>10); - + free_init_memory(); startup_cpu_idle_loop(); } @@ -151,14 +143,17 @@ end_boot_allocator(); } +/* C entry point for boot CPU */ void __init start_xen(unsigned long boot_phys_offset, unsigned long arm_type, - unsigned long atag_paddr) - + unsigned long atag_paddr, + unsigned long cpuid) { void *fdt; size_t fdt_size; - int i; + int cpus, i; + paddr_t gate_pa; + unsigned long *gate; fdt = (void *)BOOT_MISC_VIRT_START + (atag_paddr & ((1 << SECOND_SHIFT) - 1)); @@ -174,15 +169,29 @@ console_init_preirq(); #endif + percpu_init_areas(); + set_processor_id(0); /* needed early, for smp_processor_id() */ + + cpus = gic_init(); + + printk("Waiting for %i other CPUs to be ready\n", cpus - 1); + /* Bring the other CPUs up to paging before the original + * copy of .text gets overwritten. We need to use the unrelocated + * copy of boot_gate as that's the one the others can see. */ + gate_pa = ((unsigned long) &boot_gate) + boot_phys_offset; + gate = map_domain_page(gate_pa >> PAGE_SHIFT) + (gate_pa & ~PAGE_MASK); + *gate = 0; + unmap_domain_page(gate); + /* Now send an event to wake the first non-boot CPU */ + asm volatile("dsb; isb; sev"); + /* And wait for them all to be ready. */ + while ( ready_cpus + 1 < cpus ) + smp_rmb(); + __set_current((struct vcpu *)0xfffff000); /* debug sanity */ idle_vcpu[0] = current; - set_processor_id(0); /* needed early, for smp_processor_id() */ - /* TODO: smp_prepare_boot_cpu(void) */ - cpumask_set_cpu(smp_processor_id(), &cpu_online_map); - cpumask_set_cpu(smp_processor_id(), &cpu_present_map); - - smp_prepare_cpus(max_cpus); + smp_prepare_cpus(cpus); init_xen_time(); @@ -208,8 +217,6 @@ init_IRQ(); - gic_init(); - gic_route_irqs(); init_maintenance_interrupt(); @@ -231,7 +238,7 @@ for_each_present_cpu ( i ) { - if ( (num_online_cpus() < max_cpus) && !cpu_online(i) ) + if ( (num_online_cpus() < cpus) && !cpu_online(i) ) { int ret = cpu_up(i); if ( ret != 0 ) @@ -269,7 +276,11 @@ domain_unpause_by_systemcontroller(dom0); - reset_stack_and_jump(init_done); + /* Switch on to the dynamically allocated stack for the idle vcpu + * since the static one we're running on is about to be freed. */ + memcpy(idle_vcpu[0]->arch.cpu_info, get_cpu_info(), + sizeof(struct cpu_info)); + switch_stack_and_jump(idle_vcpu[0]->arch.cpu_info, init_done); } void arch_get_xen_caps(xen_capabilities_info_t *info) diff -r 703a339e11ab -r d54cf3fa7ee6 xen/arch/arm/shutdown.c --- a/xen/arch/arm/shutdown.c Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/arch/arm/shutdown.c Tue Mar 13 15:28:41 2012 +0000 @@ -1,18 +1,64 @@ #include <xen/config.h> +#include <xen/console.h> +#include <xen/cpu.h> +#include <xen/delay.h> #include <xen/lib.h> +#include <xen/mm.h> +#include <xen/smp.h> + +static void raw_machine_reset(void) +{ + /* XXX get this from device tree */ +#ifdef SP810_ADDRESS + /* Use the SP810 system controller to force a reset */ + volatile uint32_t *sp810; + set_fixmap(FIXMAP_MISC, SP810_ADDRESS >> PAGE_SHIFT, DEV_SHARED); + sp810 = ((uint32_t *) + (FIXMAP_ADDR(FIXMAP_MISC) + (SP810_ADDRESS & ~PAGE_MASK))); + sp810[0] = 0x3; /* switch to slow mode */ + dsb(); isb(); + sp810[1] = 0x1; /* writing any value to SCSYSSTAT reg will reset system */ + dsb(); isb(); + clear_fixmap(FIXMAP_MISC); +#endif +} + +static void halt_this_cpu(void *arg) +{ + __cpu_disable(); + stop_cpu(); +} void machine_halt(void) { - /* TODO: halt */ - while(1) ; + watchdog_disable(); + console_start_sync(); + local_irq_enable(); + smp_call_function(halt_this_cpu, NULL, 0); + halt_this_cpu(NULL); } void machine_restart(unsigned int delay_millisecs) { - /* TODO: restart */ - printk("Cannot restart yet\n"); - while(1); + int timeout = 10; + + local_irq_enable(); + smp_call_function(halt_this_cpu, NULL, 0); + local_irq_disable(); + + mdelay(delay_millisecs); + + /* Wait at most another 10ms for all other CPUs to go offline. */ + while ( (num_online_cpus() > 1) && (timeout-- > 0) ) + mdelay(1); + + while ( 1 ) + { + raw_machine_reset(); + mdelay(100); + } } + /* * Local variables: * mode: C diff -r 703a339e11ab -r d54cf3fa7ee6 xen/arch/arm/smpboot.c --- a/xen/arch/arm/smpboot.c Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/arch/arm/smpboot.c Tue Mar 13 15:28:41 2012 +0000 @@ -16,9 +16,16 @@ * GNU General Public License for more details. */ +#include <xen/cpu.h> #include <xen/cpumask.h> +#include <xen/delay.h> +#include <xen/errno.h> +#include <xen/init.h> +#include <xen/mm.h> +#include <xen/sched.h> #include <xen/smp.h> -#include <xen/init.h> +#include <xen/softirq.h> +#include "gic.h" cpumask_t cpu_online_map; EXPORT_SYMBOL(cpu_online_map); @@ -27,19 +34,142 @@ cpumask_t cpu_possible_map; EXPORT_SYMBOL(cpu_possible_map); +/* Xen stack for bringing up the first CPU. */ +static unsigned char __initdata cpu0_boot_stack[STACK_SIZE] + __attribute__((__aligned__(STACK_SIZE))); + +/* Pointer to the stack, used by head.S when entering C */ +unsigned char *init_stack = cpu0_boot_stack; + void __init smp_prepare_cpus (unsigned int max_cpus) { - set_processor_id(0); /* needed early, for smp_processor_id() */ + int i; + set_processor_id(0); /* needed early, for smp_processor_id() */ - cpumask_clear(&cpu_online_map); - cpumask_clear(&cpu_present_map); - cpumask_clear(&cpu_possible_map); - cpumask_set_cpu(0, &cpu_online_map); - cpumask_set_cpu(0, &cpu_present_map); - cpumask_set_cpu(0, &cpu_possible_map); - return; + cpumask_clear(&cpu_online_map); + cpumask_set_cpu(0, &cpu_online_map); + + cpumask_clear(&cpu_possible_map); + for ( i = 0; i < max_cpus; i++ ) + cpumask_set_cpu(i, &cpu_possible_map); + cpumask_copy(&cpu_present_map, &cpu_possible_map); } + +/* Shared state for coordinating CPU bringup */ +unsigned long smp_up_cpu = 0; +static bool_t cpu_is_dead = 0; + +/* Boot the current CPU */ +void __cpuinit start_secondary(unsigned long boot_phys_offset, + unsigned long arm_type, + unsigned long atag_paddr, + unsigned long cpuid) +{ + memset(get_cpu_info(), 0, sizeof (struct cpu_info)); + + /* TODO: handle boards where CPUIDs are not contiguous */ + set_processor_id(cpuid); + + /* Setup Hyp vector base */ + WRITE_CP32((uint32_t) hyp_traps_vector, HVBAR); + + dprintk(XENLOG_DEBUG, "CPU %li awake.\n", cpuid); + + mmu_init_secondary_cpu(); + gic_init_secondary_cpu(); + + set_current(idle_vcpu[cpuid]); + this_cpu(curr_vcpu) = current; + + /* Run local notifiers */ + notify_cpu_starting(cpuid); + wmb(); + + /* Now report this CPU is up */ + cpumask_set_cpu(cpuid, &cpu_online_map); + wmb(); + + local_irq_enable(); + + dprintk(XENLOG_DEBUG, "CPU %li booted.\n", cpuid); + + startup_cpu_idle_loop(); +} + +/* Shut down the current CPU */ +void __cpu_disable(void) +{ + unsigned int cpu = get_processor_id(); + + local_irq_disable(); + gic_disable_cpu(); + /* Allow any queued timer interrupts to get serviced */ + local_irq_enable(); + mdelay(1); + local_irq_disable(); + + /* It's now safe to remove this processor from the online map */ + cpumask_clear_cpu(cpu, &cpu_online_map); + + if ( cpu_disable_scheduler(cpu) ) + BUG(); + mb(); + + /* Return to caller; eventually the IPI mechanism will unwind and the + * scheduler will drop to the idle loop, which will call stop_cpu(). */ +} + +void stop_cpu(void) +{ + local_irq_disable(); + cpu_is_dead = 1; + /* Make sure the write happens before we sleep forever */ + dsb(); + isb(); + while ( 1 ) + asm volatile("wfi"); +} + +/* Bring up a remote CPU */ +int __cpu_up(unsigned int cpu) +{ + /* Tell the remote CPU which stack to boot on. */ + init_stack = idle_vcpu[cpu]->arch.stack; + + /* Unblock the CPU. It should be waiting in the loop in head.S + * for an event to arrive when smp_up_cpu matches its cpuid. */ + smp_up_cpu = cpu; + asm volatile("dsb; isb; sev"); + + while ( !cpu_online(cpu) ) + { + cpu_relax(); + process_pending_softirqs(); + } + + return 0; +} + +/* Wait for a remote CPU to die */ +void __cpu_die(unsigned int cpu) +{ + unsigned int i = 0; + + while ( !cpu_is_dead ) + { + mdelay(100); + cpu_relax(); + process_pending_softirqs(); + if ( (++i % 10) == 0 ) + printk(KERN_ERR "CPU %u still not dead...\n", cpu); + mb(); + } + cpu_is_dead = 0; + mb(); +} + + /* * Local variables: * mode: C diff -r 703a339e11ab -r d54cf3fa7ee6 xen/arch/arm/time.c --- a/xen/arch/arm/time.c Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/arch/arm/time.c Tue Mar 13 15:28:41 2012 +0000 @@ -171,6 +171,16 @@ request_irq(30, timer_interrupt, 0, "phytimer", NULL); } +/* Wait a set number of microseconds */ +void udelay(unsigned long usecs) +{ + s_time_t deadline = get_s_time() + 1000 * (s_time_t) usecs; + while ( get_s_time() - deadline < 0 ) + ; + dsb(); + isb(); +} + /* * Local variables: * mode: C diff -r 703a339e11ab -r d54cf3fa7ee6 xen/include/asm-arm/config.h --- a/xen/include/asm-arm/config.h Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/include/asm-arm/config.h Tue Mar 13 15:28:41 2012 +0000 @@ -119,6 +119,9 @@ #define GIC_CR_OFFSET 0x2000 #define GIC_HR_OFFSET 0x4000 /* Guess work http://lists.infradead.org/pipermail/linux-arm-kernel/2011-September/064219.html */ #define GIC_VR_OFFSET 0x6000 /* Virtual Machine CPU interface) */ +/* Board-specific: base address of system controller */ +#define SP810_ADDRESS 0x1C020000 + #endif /* __ARM_CONFIG_H__ */ /* diff -r 703a339e11ab -r d54cf3fa7ee6 xen/include/asm-arm/current.h --- a/xen/include/asm-arm/current.h Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/include/asm-arm/current.h Tue Mar 13 15:28:41 2012 +0000 @@ -40,17 +40,19 @@ #define get_current() (this_cpu(curr_vcpu)) #define __set_current(vcpu) (this_cpu(curr_vcpu) = (vcpu)) #define set_current(vcpu) do { \ - vcpu->arch.cpu_info->processor_id = get_processor_id(); \ + int cpu = get_processor_id(); \ + vcpu->arch.cpu_info->processor_id = cpu; \ + vcpu->arch.cpu_info->per_cpu_offset = __per_cpu_offset[cpu]; \ __set_current(vcpu); \ } while (0) #define current (get_current()) #define guest_cpu_user_regs() (&get_cpu_info()->guest_cpu_user_regs) -#define reset_stack_and_jump(__fn) \ - __asm__ __volatile__ ( \ - "mov sp,%0; b "STR(__fn) \ - : : "r" (guest_cpu_user_regs()) : "memory" ) +#define switch_stack_and_jump(stack, fn) \ + asm volatile ("mov sp,%0; b " STR(fn) : : "r" (stack) : "memory" ) + +#define reset_stack_and_jump(fn) switch_stack_and_jump(get_cpu_info(), fn) #endif diff -r 703a339e11ab -r d54cf3fa7ee6 xen/include/asm-arm/delay.h --- a/xen/include/asm-arm/delay.h Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/include/asm-arm/delay.h Tue Mar 13 15:28:41 2012 +0000 @@ -1,8 +1,7 @@ #ifndef _ARM_DELAY_H #define _ARM_DELAY_H -extern void __udelay(unsigned long usecs); -#define udelay(n) __udelay(n) +extern void udelay(unsigned long usecs); #endif /* defined(_ARM_DELAY_H) */ /* diff -r 703a339e11ab -r d54cf3fa7ee6 xen/include/asm-arm/mm.h --- a/xen/include/asm-arm/mm.h Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/include/asm-arm/mm.h Tue Mar 13 15:28:41 2012 +0000 @@ -136,6 +136,8 @@ /* Boot-time pagetable setup */ extern void setup_pagetables(unsigned long boot_phys_offset); +/* MMU setup for seccondary CPUS (which already have paging enabled) */ +extern void __cpuinit mmu_init_secondary_cpu(void); /* Set up the xenheap: up to 1GB of contiguous, always-mapped memory. * Base must be 32MB aligned and size a multiple of 32MB. */ extern void setup_xenheap_mappings(unsigned long base_mfn, unsigned long nr_mfns); @@ -276,6 +278,10 @@ #define memguard_guard_stack(_p) ((void)0) #define memguard_guard_range(_p,_l) ((void)0) #define memguard_unguard_range(_p,_l) ((void)0) + +/* Release all __init and __initdata ranges to be reused */ +void free_init_memory(void); + int guest_physmap_mark_populate_on_demand(struct domain *d, unsigned long gfn, unsigned int order); diff -r 703a339e11ab -r d54cf3fa7ee6 xen/include/asm-arm/page.h --- a/xen/include/asm-arm/page.h Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/include/asm-arm/page.h Tue Mar 13 15:28:41 2012 +0000 @@ -203,6 +203,22 @@ } /* + * Flush all hypervisor mappings from the TLB and branch predictor. + * This is needed after changing Xen code mappings. + */ +static inline void flush_xen_text_tlb(void) +{ + register unsigned long r0 asm ("r0"); + asm volatile ( + "dsb;" /* Ensure visibility of PTE writes */ + STORE_CP32(0, TLBIALLH) /* Flush hypervisor TLB */ + STORE_CP32(0, BPIALL) /* Flush branch predictor */ + "dsb;" /* Ensure completion of TLB+BP flush */ + "isb;" + : : "r" (r0) /*dummy*/ : "memory"); +} + +/* * Flush all hypervisor mappings from the data TLB. This is not * sufficient when changing code mappings or for self modifying code. */ diff -r 703a339e11ab -r d54cf3fa7ee6 xen/include/asm-arm/percpu.h --- a/xen/include/asm-arm/percpu.h Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/include/asm-arm/percpu.h Tue Mar 13 15:28:41 2012 +0000 @@ -12,8 +12,11 @@ __attribute__((__section__(".bss.percpu" #suffix))) \ __typeof__(type) per_cpu_##name -#define per_cpu(var, cpu) ((&per_cpu__##var)[cpu?0:0]) -#define __get_cpu_var(var) per_cpu__##var + +#define per_cpu(var, cpu) \ + (*RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu])) +#define __get_cpu_var(var) \ + (*RELOC_HIDE(&per_cpu__##var, get_cpu_info()->per_cpu_offset)) #define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name diff -r 703a339e11ab -r d54cf3fa7ee6 xen/include/asm-arm/smp.h --- a/xen/include/asm-arm/smp.h Tue Mar 13 15:23:35 2012 +0000 +++ b/xen/include/asm-arm/smp.h Tue Mar 13 15:28:41 2012 +0000 @@ -14,6 +14,8 @@ #define raw_smp_processor_id() (get_processor_id()) +extern void stop_cpu(void); + #endif /* * Local variables: _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |