(v3) arm: SMP boot
PATCH 1/1 (v3) arm: SMP boot
This patch series implements SMP boot for arch/arm, as far as getting all CPUs up and running the idle loop.
Changes from v2:
- Fixed a bug in context switching in the percpu patch
- Added two new patches, not strictly for SMP boot, but related, and apply after this series:
- Poison, unmap and free the __init* areas after boot.
- Use 'WFI' to take the CPu to a low power state in the idle loop.
Changes from v1:
- moved barriers out of loop in udelay()
- dropped broken GIC change in favour of explanatory comment
- made the increment of ready_cpus atomic (I couldn't move the increment to before signalling the next CPU because the PT switch has to happen between them)
- Made secondary CPUs come up directly on the idle vcpus' stacks, avoiding the whole business of allocating and tracking boot stacks.
- Added a new patch to do late-boot MMU fixups on secondary CPUs.
Cheers,
Tim.
PATCH 1/1 arm: implement udelay()
# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331311595 0
# Node ID 2672314f141da3d9685257083723b2e512f00f02 # Parent 10c5ba0b5af2dd209d4f7d27649dea5827652d9c
arm: implement udelay()
xen/arch/arm/dummy.S +0 -1
@@ -62,5 +62,4 @@ DUMMY(gmfn_to_mfn); DUMMY(hypercall_create_continuation); DUMMY(send_timer_event); DUMMY(share_xen_page_with_privileged_guests); -DUMMY(__udelay); DUMMY(wallclock_time);
xen/arch/arm/time.c +10 -0
@@ -171,6 +171,16 @@ void __cpuinit init_timer_interrupt(voidrequest_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
xen/include/asm-arm/delay.h +1 -2
@@ -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) */ /*
PATCH 1/1 arm: Add a comment explaining the GICD writes in the GICC init function
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331311595 0
# Node ID ad97676f4dd1f69fba7fec4aa4ff5f1bfc02d254
# Parent 2672314f141da3d9685257083723b2e512f00f02
arm: Add a comment explaining the GICD writes in the GICC init function.
xen/arch/arm/gic.c +3 -1
@@ -224,7 +224,9 @@ static void __cpuinit gic_cpu_init(void) {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 */
PATCH 1/1 arm: More SMP bringup
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331311595 0
# Node ID 849c8e3ac74784039cc620ef4af46fe6874e6536 # Parent ad97676f4dd1f69fba7fec4aa4ff5f1bfc02d254
arm: More SMP bringup
Bring non-boot CPUs up as far as running on the relocated pagetables, one at a time, before the non-relocated copy of Xen gets reused for general memory pools.
Don't yet bring them up into C; that will happen later when stacks are allocated.
xen/arch/arm/gic.c +3 -1
@@ -252,7 +252,7 @@ static void __cpuinit gic_hyp_init(void) }/* 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 ;
@@ -274,6 +274,8 @@ void gic_init(void)gic_hyp_init ();spin_unlock (&gic.lock); + +return gic.cpus; }void gic_route_irqs (void )
xen/arch/arm/gic.h +2 -2
@@ -138,8 +138,8 @@ extern int gic_route_irq_to_guest(struct/* 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 );/* setup the gic virtual interface for a guest */ extern void gicv_setup (struct domain *d);#endif
xen/arch/arm/head.S +75 -14
154 lines not on this page · raw message
xen/arch/arm/mm.c +11 -9
@@ -36,6 +36,9 @@ lpae_t xen_second[LPAE_ENTRIES*4] __attr 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;
@@ -156,14 +159,6 @@ void __init setup_pagetables(unsigned lolpae_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 +181,18 @@ void __init setup_pagetables(unsigned lofor ( 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; asmvolatile ( STORE_CP64(0, HTTBR) /* Change translation base */ "dsb;" /* Ensure visibility of HTTBR update */
@@ -198,7 +200,7 @@ void __init setup_pagetables(unsigned lo 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 ;
xen/arch/arm/setup.c +28 -10
@@ -44,7 +44,12 @@ static unsigned int __initdata max_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[]; +extern const 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) {
@@ -151,14 +156,17 @@ static void __init setup_mm(unsigned lonend_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,14 +182,26 @@ void __init start_xen(unsigned long bootconsole_init_preirq ();#endif + 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 */ + asmvolatile ("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);init_xen_time ();
@@ -208,8 +228,6 @@ void __init start_xen(unsigned long bootinit_IRQ (); -gic_init (); -gic_route_irqs ();init_maintenance_interrupt ();
Re: [PATCH 03 of 11] arm: More SMP bringup
Quoted 9 lines · Tim Deegan
xen/arch/arm/head.S +9
-0+ /* 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 +
xen/arch/arm/head.S paging: · line 313
Quoted 10 lines
xen/arch/arm/head.S +9
-0+ /* 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 + b 1b + +launch: ldr sp, =init_stack /* Supply a stack */
This really confused me until I realised that the event to push a non-boot CPU out of that wfe loop would never come at this point in the series!
If I boot on a 4 way AEM model then my dom0 kernel hangs at "Calibrating delay loop". However I don't see this booting with this series on a 1 way model so I don't consider it a regression (yet).
I also get:
At 0x00000000, Error: Exclusive Access Into non-Normal memory
Access at VA = 0x80260014, TLB Entry =
CoreNum:0, Virtual base = 0x0, Physical base = 0x0, size = 0x0, tlb_index = 0x0
Global, ipa_base = 0x0000000000000000, Strongly Ordered/Device-nGnRnE outer-shareable AP = 011, domain = 10
Inner NonCacheable, Outer NonCacheable
Pagetable entry l1 = 0x00000000But I'm assuming this is the model being confused by the use of ldr/strex before enabling paging (although it would be worth checking that those instr aren't dependent on paging in some way?).
Anyway... I've committed all 11 patches in this series. Thanks!
Ian.
PATCH 1/1 arm: per-cpu areas
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331311595 0
# Node ID 5254b3d4015ee4ee9e1eb51c0329b2e88c6b64fc # Parent 849c8e3ac74784039cc620ef4af46fe6874e6536
arm: per-cpu areas
xen/arch/arm/Makefile +1 -0
@@ -13,6 +13,7 @@ obj-y += irq.o 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
xen/arch/arm/dummy.S +0 -1
@@ -14,7 +14,6 @@ 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);
xen/arch/arm/percpu.c new file +85 -0
85 lines not on this page · raw message
xen/arch/arm/setup.c +3 -1
@@ -182,6 +182,9 @@ void __init start_xen(unsigned long bootconsole_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 );
@@ -200,7 +203,6 @@ void __init start_xen(unsigned long boot__set_current ((struct vcpu *)0xfffff000 );/* debug sanity */ idle_vcpu[0 ] = current; -set_processor_id (0 );/* needed early, for smp_processor_id() */ smp_prepare_cpus (max_cpus);
xen/include/asm-arm/current.h +3 -1
@@ -40,7 +40,9 @@ static inline struct cpu_info *get_cpu_i#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())
xen/include/asm-arm/percpu.h +5 -2
@@ -12,8 +12,11 @@ void percpu_init_areas(void); __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
PATCH 1/1 arm: start plumbing in SMP bringup in C
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331311595 0
# Node ID 33d06f47c02a321572c3e5ba16f1f5be0a55cf2e # Parent 5254b3d4015ee4ee9e1eb51c0329b2e88c6b64fc
arm: start plumbing in SMP bringup in C
Still a noop, but no longer just a dummy symbol.
xen/arch/arm/dummy.S +0 -3
@@ -7,9 +7,6 @@ x: .word 0xe7f000f0 /* Undefined instruc 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);
xen/arch/arm/setup.c +2 -5
@@ -38,9 +38,6 @@#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)));
@@ -204,7 +201,7 @@ void __init start_xen(unsigned long boot__set_current ((struct vcpu *)0xfffff000 );/* debug sanity */ idle_vcpu[0 ] = current; -smp_prepare_cpus (max_cpus); +smp_prepare_cpus (cpus);init_xen_time ();
@@ -251,7 +248,7 @@ void __init start_xen(unsigned long bootfor_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 )
xen/arch/arm/smpboot.c +33 -8
55 lines not on this page · raw message
PATCH 1/1 arm: Boot secondary CPUs into C
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331311595 0
# Node ID 60f25ee4c640e6e66e600429bd9f2f307bacb9bc # Parent 33d06f47c02a321572c3e5ba16f1f5be0a55cf2e
arm: Boot secondary CPUs into C
Secondary CPUs come up directly onto the stack of the appropriate idle vcpu; the boot CPU starts on a statically allocated stack and switches over to the idle vcpu's one once the idle domain has been built.
xen/arch/arm/gic.c +9 -1
@@ -245,7 +245,6 @@ static void __cpuinit gic_hyp_init(void) 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 ;
@@ -278,6 +277,15 @@ int __init gic_init(void)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); +} +void gic_route_irqs (void ) {/* XXX should get these from DT */
xen/arch/arm/gic.h +2 -0
@@ -140,6 +140,8 @@ extern int gic_route_irq_to_guest(structextern void gic_interrupt (struct cpu_user_regs *regs,int is_fiq);/* 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 );/* setup the gic virtual interface for a guest */ extern void gicv_setup (struct domain *d);#endif
xen/arch/arm/head.S +10 -4
@@ -307,17 +307,23 @@ 1: ldrex r1, [r0] /* * and brought up the memory allocator, non-boot CPUs can get their * own stacks and enter C. */ 1: wfe - b 1b + dsb + ldr r0, =smp_up_cpu + ldr r1, [r0] /* Which CPU is being booted? */ + teq r1, r12 /* Is it us? */ + bne 1b launch: - ldr sp, =init_stack /* Supply a stack */ + 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 */ - mov r3, r12 /* - CPU ID */ - 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 */
xen/arch/arm/setup.c +5 -4
@@ -38,9 +38,6 @@#include <asm/setup.h> #include "gic.h" -/* Xen stack for bringing up the first CPU. */ -unsigned char __initdata init_stack[STACK_SIZE] __attribute__((__aligned__(STACK_SIZE))); -extern const char __init_begin[], __init_end[], __bss_start[];/* Spinlock for serializing CPU bringup */
@@ -286,7 +283,11 @@ void __init start_xen(unsigned long bootdomain_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)
xen/arch/arm/smpboot.c +70 -6
103 lines not on this page · raw message
xen/include/asm-arm/current.h +4 -4
@@ -49,10 +49,10 @@ static inline struct cpu_info *get_cpu_i#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
PATCH 1/1 arm: SMP CPU shutdown
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331311595 0
# Node ID 0bfd379d2501fc988d0228ab6a8bfb2bc4730b65 # Parent 60f25ee4c640e6e66e600429bd9f2f307bacb9bc
arm: SMP CPU shutdown
For completeness, also implelent the CPU shutdown path.
xen/arch/arm/domain.c +4 -6
@@ -31,12 +31,10 @@ void idle_loop(void) {for ( ; ; ) { -/* TODO -if ( cpu_is_offline(smp_processor_id()) ) -play_dead(); -(*pm_idle)(); -BUG(); -*/ +if (cpu_is_offline (smp_processor_id ()) ) +stop_cpu (); + +/* TODO: (*pm_idle)(); */ do_tasklet ();do_softirq (); }
xen/arch/arm/gic.c +19 -0
@@ -239,6 +239,11 @@ static void __cpuinit gic_cpu_init(void)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;
@@ -250,6 +255,11 @@ static void __cpuinit gic_hyp_init(void)GICH [GICH_MISR ] =GICH_MISR_EOI ; } +static void __cpuinit gic_hyp_disable (void ) +{ +GICH [GICH_HCR ] =0 ; +} +/* Set up the GIC */ int __init gic_init (void ) {
@@ -286,6 +296,15 @@ void __cpuinit gic_init_secondary_cpu(vospin_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 ) {/* XXX should get these from DT */
xen/arch/arm/gic.h +2 -0
@@ -142,6 +142,8 @@ extern void gic_interrupt(struct cpu_useextern 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
xen/arch/arm/smpboot.c +44 -4
72 lines not on this page · raw message
xen/include/asm-arm/smp.h +2 -0
@@ -14,6 +14,8 @@ DECLARE_PER_CPU(cpumask_var_t, cpu_core_#define raw_smp_processor_id () (get_processor_id()) +extern void stop_cpu (void ); +#endif /* * Local variables:
PATCH 1/1 arm: Shutdown and reboot
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331311595 0
# Node ID 9b746bfac6bbb3c2181fe14676d76aa55e7c748c # Parent 0bfd379d2501fc988d0228ab6a8bfb2bc4730b65
arm: Shutdown and reboot
Reboot runes grabbed from linux's SP810 reset function. Doesn't seem to work on the model, though.
xen/arch/arm/shutdown.c +51 -5
@@ -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
xen/include/asm-arm/config.h +3 -0
@@ -119,6 +119,9 @@ extern unsigned long frametable_virt_end#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__ */ /*
PATCH 1/1 arm: new hook for late MMU setup on secondary CPUs
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331311595 0
# Node ID 80b8756718af745fae2778c625a8eea6235974fe # Parent 9b746bfac6bbb3c2181fe14676d76aa55e7c748c
arm: new hook for late MMU setup on secondary CPUs
The boot CPU turns on W^X in setup_pagetables(). Do the same for other CPUs after they boot. If we go to per-CPU pagetables, this is where that will happen.
xen/arch/arm/mm.c +7 -0
@@ -263,6 +263,13 @@ void __init setup_pagetables(unsigned loWRITE_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,
xen/arch/arm/smpboot.c +1 -0
@@ -76,6 +76,7 @@ void __cpuinit start_secondary(unsigneddprintk (XENLOG_DEBUG ,"CPU %li awake.\n" , cpuid); +mmu_init_secondary_cpu ();gic_init_secondary_cpu ();set_current (idle_vcpu[cpuid]);
xen/include/asm-arm/mm.h +2 -0
@@ -136,6 +136,8 @@ extern unsigned long total_pages;/* 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);
PATCH 1/1 arm: Actually free __init/__initdata ranges on boot
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331311595 0
# Node ID ec6712d0af2786332af7dd6f6caab50878bc96d0 # Parent 80b8756718af745fae2778c625a8eea6235974fe
arm: Actually free __init/__initdata ranges on boot.
xen/arch/arm/mm.c +62 -18
@@ -48,6 +48,8 @@ unsigned long frametable_virt_end;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) {
@@ -205,17 +207,7 @@ void __init setup_pagetables(unsigned lo/* 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. -*/ - asmvolatile ( -"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)
@@ -251,13 +243,7 @@ void __init setup_pagetables(unsigned lo 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. */ - asmvolatile ( -"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 );
@@ -328,6 +314,64 @@ void __init setup_frametable_mappings(pa 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 ) { }
xen/arch/arm/setup.c +1 -8
@@ -38,8 +38,6 @@#include <asm/setup.h> #include "gic.h" -extern const 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 */
@@ -47,12 +45,7 @@ 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 (); }
xen/include/asm-arm/mm.h +4 -0
@@ -278,6 +278,10 @@ extern struct domain *dom_xen, *dom_io,#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);
xen/include/asm-arm/page.h +16 -0
@@ -203,6 +203,22 @@ static inline void write_pte(lpae_t *p, }/* +* 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 ) +{ + registerunsigned long r0 asm ("r0" ); + asmvolatile ( +"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. */
PATCH 1/1 arm: Put the CPU into a sleep state in the idle loop
In reply to Tim Deegan# HG changeset patch
# User Tim Deegan <[email protected]>
# Date 1331311596 0
# Node ID 258d71e6c048bcfda4fa35cd9addfe1f0c4461ef # Parent ec6712d0af2786332af7dd6f6caab50878bc96d0
arm: Put the CPU into a sleep state in the idle loop.
The ARM doesn't actually say that the WFI instruction will return immediately if CPSR.I is clear and an instruction is pending, but this seems to match up with how linux uses it.
xen/arch/arm/domain.c +5 -1
@@ -34,7 +34,11 @@ void idle_loop(void)if (cpu_is_offline (smp_processor_id ()) )stop_cpu (); -/* TODO: (*pm_idle)(); */ +local_irq_disable (); +if (cpu_is_haltable (smp_processor_id ()) ) + asmvolatile ("dsb; wfi" ); +local_irq_enable (); +do_tasklet ();do_softirq (); }