[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.