From: Julien Grall <julien.grall@linaro.org>
To: Ian Campbell <ian.campbell@citrix.com>
Cc: julien.grall@citrix.com, stefano.stabellini@eu.citrix.com,
tim@xen.org, xen-devel@lists.xen.org
Subject: Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
Date: Tue, 17 Sep 2013 17:18:20 +0100 [thread overview]
Message-ID: <523880CC.7020703@linaro.org> (raw)
In-Reply-To: <1379382050-11821-5-git-send-email-ian.campbell@citrix.com>
On 09/17/2013 02:40 AM, Ian Campbell wrote:
> This is unfortunately a rather large monolithic patch.
>
> Rather than bringing up all CPUs in lockstep as we setup paging and relocate
> Xen instead create a simplified set of dedicated boot time pagetables.
>
> This allows secondary CPUs to remain powered down or in the firmware until we
> actually want to enable them. The bringup is now done later on in C and can be
> driven by DT etc. I have included code for the vexpress platform, but other
> platforms will need to be added.
>
> The mechanism for deciding how to bring up a CPU differs between arm32 and
> arm64. On arm32 it is essentially a per-platform property, with the exception
> of PSCI which can be implemented globally (but isn't here). On arm64 there is a
> per-cpu property in the device tree.
>
> Secondary CPUs are brought up directly into the relocated Xen image, instead of
> relying on being able to launch on the unrelocated Xen and hoping that it
> hasn't been clobbered.
>
> As part of this change drop support for switching from secure mode to NS HYP as
> well as the early CPU kick. Xen now requires that it is launched in NS HYP
> mode and that firmware configure things such that secondary CPUs can be woken
> up by a primarly CPU in HYP mode. This may require fixes to bootloaders or the
> use of a boot wrapper.
>
> The changes done here (re)exposed an issue with relocating Xen and the compiler
> spilling values to the stack between the copy and the actual switch to the
> relocaed copy of Xen in setup_pagetables. Therefore switch to doing the copy
> and switch in a single asm function where we can control precisely what gets
> spilled to the stack etc.
>
> Since we now have a separate set of boot pagetables it is much easier to build
> the real Xen pagetables inplace before relocating rather than the more complex
> approach of rewriting the pagetables in the relocated copy before switching.
>
> This will also enable Xen to be loaded above the 4GB boundary on 64-bit.
> Still TODO:
> - integrate with Julien's "Dissociate logical and hardware CPU ID"
> - cpu initialisation for other platforms
>
> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
> ---
> xen/arch/arm/arm32/Makefile | 2 +-
> xen/arch/arm/arm32/head.S | 349 ++++++++++++++++++-----------
> xen/arch/arm/arm32/mode_switch.S | 158 -------------
> xen/arch/arm/arm32/smpboot.c | 24 ++
> xen/arch/arm/arm64/Makefile | 2 +-
> xen/arch/arm/arm64/head.S | 367 ++++++++++++++++++++++---------
> xen/arch/arm/arm64/mode_switch.S | 89 --------
> xen/arch/arm/arm64/smpboot.c | 80 +++++++
> xen/arch/arm/mm.c | 184 +++++++++-------
> xen/arch/arm/platform.c | 18 ++
> xen/arch/arm/platforms/vexpress.c | 39 ++++
> xen/arch/arm/setup.c | 1 -
> xen/arch/arm/smpboot.c | 51 ++---
> xen/include/asm-arm/platform.h | 9 +
> xen/include/asm-arm/platforms/exynos5.h | 14 --
> xen/include/asm-arm/platforms/vexpress.h | 11 -
> xen/include/asm-arm/smp.h | 12 +-
> 17 files changed, 786 insertions(+), 624 deletions(-)
> delete mode 100644 xen/arch/arm/arm32/mode_switch.S
> create mode 100644 xen/arch/arm/arm32/smpboot.c
> delete mode 100644 xen/arch/arm/arm64/mode_switch.S
> create mode 100644 xen/arch/arm/arm64/smpboot.c
>
> diff --git a/xen/arch/arm/arm32/Makefile b/xen/arch/arm/arm32/Makefile
> index 18522dc..aacdcb9 100644
> --- a/xen/arch/arm/arm32/Makefile
> +++ b/xen/arch/arm/arm32/Makefile
> @@ -1,11 +1,11 @@
> subdir-y += lib
>
> obj-y += entry.o
> -obj-y += mode_switch.o
> obj-y += proc-v7.o
>
> obj-y += traps.o
> obj-y += domain.o
> obj-y += vfp.o
> +obj-y += smpboot.o
>
> obj-$(EARLY_PRINTK) += debug.o
> diff --git a/xen/arch/arm/arm32/head.S b/xen/arch/arm/arm32/head.S
> index b8334e2..abaacfd 100644
> --- a/xen/arch/arm/arm32/head.S
> +++ b/xen/arch/arm/arm32/head.S
> @@ -37,6 +37,25 @@
> #include EARLY_PRINTK_INC
> #endif
>
> +/*
> + * Common register usage in this file:
> + * r0 -
> + * r1 -
> + * r2 -
> + * r3 -
> + * r4 -
> + * r5 -
> + * r6 -
> + * r7 - CPUID
> + * r8 - DTB address (boot CPU only)
> + * r9 - paddr(start)
> + * r10 - phys offset
> + * r11 - UART address
> + * r12 - !!is_boot_cpu
> + * r13 - SP
> + * r14 - LR
> + * r15 - PC
> + */
> /* Macro to print a string to the UART, if there is one.
> * Clobbers r0-r3. */
> #ifdef EARLY_PRINTK
> @@ -77,7 +96,6 @@ past_zImage:
> cpsid aif /* Disable all interrupts */
>
> /* Save the bootloader arguments in less-clobberable registers */
> - mov r5, r1 /* r5: ARM-linux machine type */
> mov r8, r2 /* r8 := DTB base address */
>
> /* Find out where we are */
> @@ -91,53 +109,39 @@ past_zImage:
> add r8, r10 /* r8 := paddr(DTB) */
> #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 r12, r0, #(0xff << 24) /* Mask out flags to get CPU ID */
> - beq boot_cpu /* If we're CPU 0, boot now */
> -
> - /* Non-boot CPUs wait here to be woken up one at a time. */
> -1: dsb
> - ldr r0, =smp_up_cpu /* VA of gate */
> - add r0, r0, r10 /* PA of gate */
> - ldr r1, [r0] /* Which CPU is being booted? */
> - teq r1, r12 /* Is it us? */
> - wfene
> - bne 1b
> + mov r12, #0 /* r12 := !!is_boot_cpu */
Do you mean !is_boot_cpu?
> +
> + b common_start
> +
> +GLOBAL(init_secondary)
> + cpsid aif /* Disable all interrupts */
> +
> + /* Find out where we are */
> + ldr r0, =start
> + adr r9, start /* r9 := paddr (start) */
> + sub r10, r9, r0 /* r10 := phys-offset */
> +
> + mov r12, #1 /* r12 := !!is_boot_cpu */
Same here.
> +
> +common_start:
> + mov r7, #0 /* r13 := CPU ID */
> + mrc CP32(r1, MPIDR)
> + tst r1, #(1<<31) /* Multiprocessor extension supported? */
> + beq 1f
> + tst r1, #(1<<30) /* Uniprocessor system? */
> + bne 1f
> + bic r7, r1, #(0xff << 24) /* Mask out flags to get CPU ID */
> +1:
>
> -boot_cpu:
> #ifdef EARLY_PRINTK
> ldr r11, =EARLY_UART_BASE_ADDRESS /* r11 := UART base address */
> - teq r12, #0 /* CPU 0 sets up the UART too */
> + teq r12, #0 /* Boot CPU sets up the UART too */
> bleq init_uart
> PRINT("- CPU ")
> - mov r0, r12
> + mov r0, r7
> bl putn
> PRINT(" booting -\r\n")
> #endif
> - /* Secondary CPUs doesn't have machine ID
> - * - Store machine ID on boot CPU
> - * - Load machine ID on secondary CPUs
> - * Machine ID is needed in kick_cpus and enter_hyp_mode */
> - ldr r0, =machine_id /* VA of machine_id */
> - add r0, r0, r10 /* PA of machine_id */
> - teq r12, #0
> - streq r5, [r0] /* On boot CPU save machine ID */
> - ldrne r5, [r0] /* If non boot cpu r5 := machine ID */
> -
> - /* Wake up secondary cpus */
> - teq r12, #0
> - bleq kick_cpus
> -
> - PRINT("- Machine ID ")
> - mov r0, r5
> - bl putn
> - PRINT(" -\r\n")
>
> /* Check that this CPU has Hyp mode */
> mrc CP32(r0, ID_PFR1)
> @@ -146,29 +150,19 @@ boot_cpu:
> beq 1f
> PRINT("- CPU doesn't support the virtualization extensions -\r\n")
> b fail
> -1:
> - /* Check if we're already in it */
> - mrs r0, cpsr
> +
> + /* Check that we're already in Hyp mode */
> +1: mrs r0, cpsr
> and r0, r0, #0x1f /* Mode is in the low 5 bits of CPSR */
> teq r0, #0x1a /* Hyp Mode? */
> - bne 1f
> - PRINT("- Started in Hyp mode -\r\n")
> - b hyp
> -1:
> - /* Otherwise, it must have been Secure Supervisor mode */
> - mrc CP32(r0, SCR)
> - tst r0, #0x1 /* Not-Secure bit set? */
> - beq 1f
> - PRINT("- CPU is not in Hyp mode or Secure state -\r\n")
> + beq hyp
> +
> + /* OK, we're boned. */
> + PRINT("- Xen must be entered in NS Hyp mode -\r\n" \
> + "- Please update the bootloader -\r\n")
> b fail
> -1:
> - /* OK, we're in Secure state. */
> - PRINT("- Started in Secure state -\r\n- Entering Hyp mode -\r\n")
> - ldr r0, =enter_hyp_mode /* VA of function */
> - adr lr, hyp /* Set return address for call */
> - add pc, r0, r10 /* Call PA of function */
>
> -hyp:
> +hyp: PRINT("- Xen starting in Hyp mode -\r\n")
>
> /* Zero BSS On the boot CPU to avoid nasty surprises */
> teq r12, #0
> @@ -242,18 +236,12 @@ cpu_init_done:
> ldr r0, =(HSCTLR_BASE|SCTLR_A)
> mcr CP32(r0, HSCTLR)
>
> - /* Write Xen's PT's paddr into the HTTBR */
> - ldr r4, =boot_pgtable
> - add r4, r4, r10 /* r4 := paddr (xen_pagetable) */
> - 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
> -
> /* console fixmap */
> #if defined(EARLY_PRINTK)
> + /* Non-boot CPUs don't need to rebuild the fixmap */
> + teq r12, #0
> + bne 1f
> +
> ldr r1, =xen_fixmap
> add r1, r1, r10 /* r1 := paddr (xen_fixmap) */
> mov r3, #0
> @@ -262,48 +250,77 @@ cpu_init_done:
> orr r2, r2, #PT_UPPER(DEV_L3)
> orr r2, r2, #PT_LOWER(DEV_L3) /* r2:r3 := 4K dev map including UART */
> strd r2, r3, [r1, #(FIXMAP_CONSOLE*8)] /* Map it in the first fixmap's slot */
> +1:
> #endif
>
> - /* Build the baseline idle pagetable's first-level entries */
> - ldr r1, =xen_second
> - add r1, r1, r10 /* r1 := paddr (xen_second) */
> + /*
> + * Rebuild the boot pagetable's first-level entries. The structure
> + * is described in mm.c.
> + *
> + * After the CPU enables paging it will add the fixmap mapping
> + * to these page tables, however this may clash with the 1:1
> + * mapping. So each CPU must rebuild the page tables here with
> + * the 1:1 in place.
> + */
> +
> + /* Write Xen's PT's paddr into the HTTBR */
> + ldr r4, =boot_pgtable
> + add r4, r4, r10 /* r4 := paddr (xen_pagetable) */
s/xen_pagetable/boot_pgtable/?
> + mov r5, #0 /* r4:r5 is paddr (xen_pagetable) */
Same here.
> + mcrr CP64(r4, r5, HTTBR)
> +
> + /* Setup boot_pgtable: */
> + ldr r1, =boot_second
> + add r1, r1, r10 /* r1 := paddr (boot_second) */
> mov r3, #0x0
> +
> + /* ... map boot_second in boot_pgtable[0] */
> orr r2, r1, #PT_UPPER(PT) /* r2:r3 := table map of xen_second */
s/xen_second/boot_second/?
> orr r2, r2, #PT_LOWER(PT) /* (+ rights for linear PT) */
> strd r2, r3, [r4, #0] /* Map it in slot 0 */
> - add r2, r2, #0x1000
> - strd r2, r3, [r4, #8] /* Map 2nd page in slot 1 */
> - add r2, r2, #0x1000
> - strd r2, r3, [r4, #16] /* Map 3rd page in slot 2 */
> - add r2, r2, #0x1000
> - strd r2, r3, [r4, #24] /* Map 4th page in slot 3 */
> -
> - /* Now set up the second-level entries */
> +
> + /* ... map of paddr(start) in boot_pgtable */
> + lsrs r1, r9, #30 /* Offset of base paddr in boot_pgtable */
> + beq 1f /* If it is in slot 0 then map in xen_second
Same here.
> + * later on */
> + lsl r2, r1, #30 /* Base address for 1GB mapping */
> + orr r2, r2, #PT_UPPER(MEM) /* r2:r3 := section map */
> + orr r2, r2, #PT_LOWER(MEM)
> + lsl r1, r1, #3 /* r1 := Slot offset */
> + strd r2, r3, [r4, r1] /* Mapping of paddr(start) */
> +
> +1: /* Setup boot_second: */
> + ldr r4, =boot_second
> + add r4, r4, r10 /* r1 := paddr (xen_second) */
Same here.
> +
> + lsr r2, r9, #20 /* Base address for 2MB mapping */
> + lsl r2, r2, #20
> + orr r2, r2, #PT_UPPER(MEM) /* r2:r3 := section map */
> + orr r2, r2, #PT_LOWER(MEM)
> +
> + /* ... map of vaddr(start) in boot_second */
> + ldr r1, =start
> + lsr r1, #18 /* Slot for vaddr(start) */
> + strd r2, r3, [r4, r1] /* Map vaddr(start) */
> +
> + /* ... map of paddr(start) in boot_second */
> orr r2, r9, #PT_UPPER(MEM)
> orr r2, r2, #PT_LOWER(MEM) /* r2:r3 := 2MB normal map of Xen */
> - mov r4, r9, lsr #18 /* Slot for paddr(start) */
> - strd r2, r3, [r1, r4] /* Map Xen there */
> - ldr r4, =start
> - lsr r4, #18 /* Slot for vaddr(start) */
> - strd r2, r3, [r1, r4] /* Map Xen there too */
>
> - /* xen_fixmap pagetable */
> - ldr r2, =xen_fixmap
> - add r2, r2, r10 /* r2 := paddr (xen_fixmap) */
> - orr r2, r2, #PT_UPPER(PT)
> - orr r2, r2, #PT_LOWER(PT) /* r2:r3 := table map of xen_fixmap */
> - add r4, r4, #8
> - strd r2, r3, [r1, r4] /* Map it in the fixmap's slot */
> + lsrs r1, r9, #30 /* Base paddr */
> + bne 1f /* If paddr(start) is not in slot 0
> + * then the mapping was done in
> + * boot_pgtable above */
>
> - mov r3, #0x0
> - lsr r2, r8, #21
> - lsl r2, r2, #21 /* 2MB-aligned paddr of DTB */
> - orr r2, r2, #PT_UPPER(MEM)
> - orr r2, r2, #PT_LOWER(MEM) /* r2:r3 := 2MB RAM incl. DTB */
> - add r4, r4, #8
> - strd r2, r3, [r1, r4] /* Map it in the early boot slot */
> + mov r1, r9, lsr #18 /* Slot for paddr(start) */
> + strd r2, r3, [r4, r1] /* Map Xen there */
> +
> + /* Defer fixmap and dtb mapping until after paging enabled, to
> + * avoid them clashing with the 1:1 mapping.
> + */
> +
> +1: /* boot pagetable setup complete */
>
> -pt_ready:
> PRINT("- Turning on paging -\r\n")
>
> ldr r1, =paging /* Explicit vaddr, not RIP-relative */
> @@ -315,22 +332,47 @@ pt_ready:
> mov pc, r1 /* Get a proper vaddr into PC */
> paging:
>
> -
> -#ifdef EARLY_PRINTK
> + /* Now we can install the fixmap and dtb mappings, since we
> + * don't need the 1:1 map any more */
> + dsb sy
> + ldr r1, =boot_second
> +#if defined(EARLY_PRINTK)
> + /* xen_fixmap pagetable */
Can you add a comment to explain why we don't need to map the fixmap
when early printk is not enabled?
> + ldr r2, =xen_fixmap
> + add r2, r2, r10 /* r2 := paddr (xen_fixmap) */
> + orr r2, r2, #PT_UPPER(PT)
> + orr r2, r2, #PT_LOWER(PT) /* r2:r3 := table map of xen_fixmap */
> + ldr r4, =FIXMAP_ADDR(0)
> + mov r4, r4, lsr #18 /* r4 := Slot for FIXMAP(0) */
> + strd r2, r3, [r1, r4] /* Map it in the fixmap's slot */
> /* Use a virtual address to access the UART. */
> ldr r11, =FIXMAP_ADDR(FIXMAP_CONSOLE)
> #endif
> + /* Map the DTB in the boot misc slot */
> + teq r12, #0 /* Only on boot CPU */
> + bne 1f
> +
> + mov r3, #0x0
> + lsr r2, r8, #21
> + lsl r2, r2, #21 /* r2: 2MB-aligned paddr of DTB */
> + orr r2, r2, #PT_UPPER(MEM)
> + orr r2, r2, #PT_LOWER(MEM) /* r2:r3 := 2MB RAM incl. DTB */
> + ldr r4, =BOOT_MISC_VIRT_START
> + mov r4, r4, lsr #18 /* Slot for BOOT_MISC_VIRT_START */
> + strd r2, r3, [r1, r4] /* Map it in the early boot slot */
> + dsb sy
>
> - PRINT("- Ready -\r\n")
> +1: PRINT("- Ready -\r\n")
>
> /* The boot CPU should go straight into C now */
> teq r12, #0
> beq launch
>
> - /* Non-boot CPUs need to move on to the relocated pagetables */
> - mov r0, #0
> - ldr r4, =boot_ttbr /* VA of HTTBR value stashed by CPU 0 */
> - add r4, r4, r10 /* PA of it */
> + /* Non-boot CPUs need to move on to proper pagetables,
> + * temporarily use cpu0's table and switch to our own in
> + * mmu_init_secondary_cpu.
> + */
> + ldr r4, =init_ttbr /* VA of HTTBR value stashed by CPU 0 */
> ldrd r4, r5, [r4] /* Actual value */
> dsb
> mcrr CP64(r4, r5, HTTBR)
> @@ -353,18 +395,6 @@ paging:
> mcr CP32(r0, DCCMVAC) /* flush D-Cache */
> 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]
> @@ -372,7 +402,7 @@ launch:
> sub sp, #CPUINFO_sizeof /* Make room for CPU save record */
> mov r0, r10 /* Marshal args: - phys_offset */
> mov r1, r8 /* - DTB address */
> - movs r2, r12 /* - CPU ID */
> + movs r2, r7 /* - CPU ID */
> beq start_xen /* and disappear into the land of C */
> b start_secondary /* (to the appropriate entry point) */
>
> @@ -382,6 +412,82 @@ fail: PRINT("- Boot failed -\r\n")
> 1: wfe
> b 1b
>
> +/*
> + * Copy Xen to new location and switch TTBR
> + * r1:r0 ttbr
> + * r2 source address
> + * r3 destination address
> + * [sp]=>r4 length
> + *
> + * Source and destination must be word aligned, length is rounded up
> + * to a 16 byte boundary.
> + *
> + * MUST BE VERY CAREFUL when saving things to RAM over the copy
> + */
> +ENTRY(relocate_xen)
> + push {r4,r5,r6,r7,r8,r9,r10,r11}
> +
> + ldr r4, [sp, #8*4] /* Get 4th argument from stack */
> +
> + /* Copy 16 bytes at a time using:
> + * r5: counter
> + * r6: data
> + * r7: data
> + * r8: data
> + * r9: data
> + * r10: source
> + * r11: destination
> + */
> + mov r5, r4
> + mov r10, r2
> + mov r11, r3
> +1: ldmia r10!, {r6, r7, r8, r9}
> + stmia r11!, {r6, r7, r8, r9}
> +
> + subs r5, r5, #16
> + bgt 1b
> +
> + /* Flush destination from dcache using:
> + * r5: counter
> + * r6: step
> + * r7: vaddr
> + */
> + dsb sy /* So the CPU issues all writes to the range */
> +
> + mov r5, r4
> + ldr r6, =cacheline_bytes /* r6 := step */
> + ldr r6, [r6]
> + mov r7, r3
> +
> +1: mcr CP32(r7, DCCMVAC)
> +
> + add r7, r7, r6
> + subs r5, r5, r6
> + bgt 1b
> +
> + dsb sy /* So we know the flushes happen before continuing */
> +
> + isb /* Ensure synchronization with previous changes to text */
> + mcr CP32(r0, TLBIALLH) /* Flush hypervisor TLB */
> + mcr CP32(r0, ICIALLU) /* Flush I-cache */
> + mcr CP32(r0, BPIALL) /* Flush branch predictor */
> + dsb /* Ensure completion of TLB+BP flush */
> + isb
> +
> + mcrr CP64(r0, r1, HTTBR)
> +
> + dsb sy /* ensure memory accesses do not cross over the TTBR0 write */
> +
> + isb /* Ensure synchronization with previous changes to text */
> + mcr CP32(r0, TLBIALLH) /* Flush hypervisor TLB */
> + mcr CP32(r0, ICIALLU) /* Flush I-cache */
> + mcr CP32(r0, BPIALL) /* Flush branch predictor */
> + dsb /* Ensure completion of TLB+BP flush */
> + isb
> +
> + pop {r4, r5,r6,r7,r8,r9,r10,r11}
> +
> + mov pc, lr
>
> #ifdef EARLY_PRINTK
> /* Bring up the UART.
> @@ -438,9 +544,6 @@ putn: mov pc, lr
>
> #endif /* !EARLY_PRINTK */
>
> -/* Place holder for machine ID */
> -machine_id: .word 0x0
> -
> /*
> * Local variables:
> * mode: ASM
> diff --git a/xen/arch/arm/arm32/mode_switch.S b/xen/arch/arm/arm32/mode_switch.S
> deleted file mode 100644
> index 2cd5888..0000000
> --- a/xen/arch/arm/arm32/mode_switch.S
> +++ /dev/null
> @@ -1,158 +0,0 @@
> -/*
> - * xen/arch/arm/mode_switch.S
> - *
> - * Start-of day code to take a CPU from Secure mode to Hyp mode.
> - *
> - * Tim Deegan <tim@xen.org>
> - * Copyright (c) 2011-2012 Citrix Systems.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - */
> -
> -#include <asm/config.h>
> -#include <asm/page.h>
> -#include <asm/platforms/vexpress.h>
> -#include <asm/platforms/exynos5.h>
> -#include <asm/asm_defns.h>
> -#include <asm/gic.h>
> -
> -/* Wake up secondary cpus
> - * This code relies on Machine ID and only works for Vexpress and the Arndale
> - * TODO: Move this code either later (via platform specific desc) or in a bootwrapper
> - * r5: Machine ID
> - * Clobber r0 r2 */
> -GLOBAL(kick_cpus)
> - ldr r0, =MACH_TYPE_SMDK5250
> - teq r5, r0 /* Are we running on the arndale? */
> - beq kick_cpus_arndale
> - /* otherwise versatile express */
> - /* write start paddr to v2m sysreg FLAGSSET register */
> - ldr r0, =(V2M_SYS_MMIO_BASE) /* base V2M sysreg MMIO address */
> - dsb
> - mov r2, #0xffffffff
> - str r2, [r0, #(V2M_SYS_FLAGSCLR)]
> - dsb
> - ldr r2, =start
> - add r2, r2, r10
> - str r2, [r0, #(V2M_SYS_FLAGSSET)]
> - dsb
> - ldr r2, =V2M_GIC_BASE_ADDRESS /* r2 := VE gic base address */
> - b kick_cpus_sgi
> -kick_cpus_arndale:
> - /* write start paddr to CPU 1 sysreg register */
> - ldr r0, =(S5P_PA_SYSRAM)
> - ldr r2, =start
> - add r2, r2, r10
> - str r2, [r0]
> - dsb
> - ldr r2, =EXYNOS5_GIC_BASE_ADDRESS /* r2 := Exynos5 gic base address */
> -kick_cpus_sgi:
> - /* send an interrupt */
> - ldr r0, =GIC_DR_OFFSET /* GIC distributor offset */
> - add r0, r2 /* r0 := r0 + gic base address */
> - mov r2, #0x1
> - str r2, [r0, #(GICD_CTLR * 4)] /* enable distributor */
> - mov r2, #0xfe0000
> - str r2, [r0, #(GICD_SGIR * 4)] /* send IPI to everybody, SGI0 = Event check */
> - dsb
> - str r2, [r0, #(GICD_CTLR * 4)] /* disable distributor */
> - mov pc, lr
> -
> -
> -/* Get up a CPU into Hyp mode. Clobbers r0-r3.
> - *
> - * r5: Machine ID
> - * r12: CPU number
> - *
> - * This code is specific to the VE model/Arndale, and not intended to be used
> - * on production systems. As such it's a bit hackier than the main
> - * boot code in head.S. In future it will be replaced by better
> - * integration with the bootloader/firmware so that Xen always starts
> - * in Hyp mode.
> - * Clobber r0 - r4 */
> -GLOBAL(enter_hyp_mode)
> - mov r3, lr /* Put return address in non-banked reg */
> - cpsid aif, #0x16 /* Enter Monitor mode */
> - mrc CP32(r0, SCR)
> - orr r0, r0, #0x100 /* Set HCE */
> - orr r0, r0, #0xb1 /* Set SCD, AW, FW and NS */
> - bic r0, r0, #0xe /* Clear EA, FIQ and IRQ */
> - mcr CP32(r0, SCR)
> -
> - ldr r2, =MACH_TYPE_SMDK5250 /* r4 := Arndale machine ID */
> - /* By default load Arndale defaults values */
> - ldr r0, =EXYNOS5_TIMER_FREQUENCY /* r0 := timer's frequency */
> - ldr r1, =EXYNOS5_GIC_BASE_ADDRESS /* r1 := GIC base address */
> - /* If it's not the Arndale machine ID, load VE values */
> - teq r5, r2
> - ldrne r0, =V2M_TIMER_FREQUENCY
> - ldrne r1, =V2M_GIC_BASE_ADDRESS
> -
> - /* Ugly: the system timer's frequency register is only
> - * programmable in Secure state. Since we don't know where its
> - * memory-mapped control registers live, we can't find out the
> - * right frequency. */
> - mcr CP32(r0, CNTFRQ)
> -
> - mrc CP32(r0,NSACR)
> - ldr r4, =0x3fff /* Allow access to all co-processors in NS mode */
> - orr r0, r0, r4
> - orr r0, r0, #(1<<18) /* CA7/CA15: Allow access to ACTLR.SMP in NS mode */
> - mcr CP32(r0, NSACR)
> -
> - add r0, r1, #GIC_DR_OFFSET
> - /* Disable the GIC distributor, on the boot CPU only */
> - mov r4, #0
> - teq r12, #0 /* Is this the boot CPU? */
> - streq r4, [r0]
> - /* Continuing ugliness: Set up the GIC so NS state owns interrupts,
> - * The first 32 interrupts (SGIs & PPIs) must be configured on all
> - * CPUs while the remainder are SPIs and only need to be done one, on
> - * the boot CPU. */
> - add r0, r0, #0x80 /* GICD_IGROUP0 */
> - mov r2, #0xffffffff /* All interrupts to group 1 */
> - str r2, [r0] /* Interrupts 0-31 (SGI & PPI) */
> - teq r12, #0 /* Boot CPU? */
> - bne skip_spis /* Don't route SPIs on secondary CPUs */
> -
> - add r4, r1, #GIC_DR_OFFSET
> - ldr r4, [r4, #4] /* r4 := Interrupt Controller Type Reg */
> - and r4, r4, #GICD_TYPE_LINES /* r4 := number of SPIs */
> -1: teq r4, #0
> - beq skip_spis
> - add r0, r0, #4 /* Go to the new group */
> - str r2, [r0] /* Update the group */
> - sub r4, r4, #1
> - b 1b
> -skip_spis:
> - /* Disable the GIC CPU interface on all processors */
> - add r0, r1, #GIC_CR_OFFSET
> - mov r1, #0
> - str r1, [r0]
> - /* Must drop priority mask below 0x80 before entering NS state */
> - ldr r1, =0xff
> - str r1, [r0, #0x4] /* -> GICC_PMR */
> - /* Reset a few config registers */
> - mov r0, #0
> - mcr CP32(r0, FCSEIDR)
> - mcr CP32(r0, CONTEXTIDR)
> -
> - mrs r0, cpsr /* Copy the CPSR */
> - add r0, r0, #0x4 /* 0x16 (Monitor) -> 0x1a (Hyp) */
> - msr spsr_cxsf, r0 /* into the SPSR */
> - movs pc, r3 /* Exception-return into Hyp mode */
> -
> -/*
> - * Local variables:
> - * mode: ASM
> - * indent-tabs-mode: nil
> - * End:
> - */
> diff --git a/xen/arch/arm/arm32/smpboot.c b/xen/arch/arm/arm32/smpboot.c
> new file mode 100644
> index 0000000..5eb1028
> --- /dev/null
> +++ b/xen/arch/arm/arm32/smpboot.c
> @@ -0,0 +1,24 @@
> +#include <xen/device_tree.h>
> +#include <xen/init.h>
> +#include <xen/smp.h>
> +#include <asm/platform.h>
> +
> +void __init arch_cpu_init(int cpu, struct dt_device_node *dn)
> +{
> + /* TODO: look for compatible = arm,psci etc and initialise psci */
> + platform_cpu_init(cpu);
> +}
> +
> +int __init arch_cpu_up(int cpu)
> +{
> + return platform_cpu_up(cpu);
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile
> index e06a0a9..5d28bad 100644
> --- a/xen/arch/arm/arm64/Makefile
> +++ b/xen/arch/arm/arm64/Makefile
> @@ -1,10 +1,10 @@
> subdir-y += lib
>
> obj-y += entry.o
> -obj-y += mode_switch.o
>
> obj-y += traps.o
> obj-y += domain.o
> obj-y += vfp.o
> +obj-y += smpboot.o
>
> obj-$(EARLY_PRINTK) += debug.o
> diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
> index 21b7e4d..6406562 100644
> --- a/xen/arch/arm/arm64/head.S
> +++ b/xen/arch/arm/arm64/head.S
> @@ -33,6 +33,41 @@
> #include EARLY_PRINTK_INC
> #endif
>
> +/*
> + * Common register usage in this file:
> + * x0 -
> + * x1 -
> + * x2 -
> + * x3 -
> + * x4 -
> + * x5 -
> + * x6 -
> + * x7 -
> + * x8 -
> + * x9 -
> + * x10 -
> + * x11 -
> + * x12 -
> + * x13 -
> + * x14 -
> + * x15 -
> + * x16 -
> + * x17 -
> + * x18 -
> + * x19 - paddr(start)
> + * x20 - phys offset
> + * x21 - DTB address (boot cpu only)
> + * x22 - !!is_boot_cpu
> + * x23 - UART address
> + * x24 - cpuid
> + * x25 -
> + * x26 -
> + * x27 -
> + * x28 -
> + * x29 -
> + * x30 - lr
> + */
> +
> /* Macro to print a string to the UART, if there is one.
> * Clobbers x0-x3. */
> #ifdef EARLY_PRINTK
> @@ -91,36 +126,36 @@ real_start:
> add x21, x21, x20 /* x21 := paddr(DTB) */
> #endif
>
> - /* Are we the boot CPU? */
> - mov x22, #0 /* x22 := CPU ID */
> + mov x22, #0 /* x22 := !!is_boot_cpu */
> +
> + b common_start
> +
> +GLOBAL(init_secondary)
> + msr DAIFSet, 0xf /* Disable all interrupts */
> +
> + /* Find out where we are */
> + ldr x0, =start
> + adr x19, start /* x19 := paddr (start) */
> + sub x20, x19, x0 /* x20 := phys-offset */
> +
> + mov x22, #1 /* x22 := !!is_boot_cpu */
> +
> +common_start:
> + mov x24, #0 /* x24 := CPU ID */
> mrs x0, mpidr_el1
> - tbz x0, 31, boot_cpu /* Multiprocessor extension supported? */
> - tbnz x0, 30, boot_cpu /* Uniprocessor system? */
> + tbz x0, 31, 1f /* Multiprocessor extension not supported? */
> + tbnz x0, 30, 1f /* Uniprocessor system? */
>
> mov x13, #(0xff << 24)
> - bics x22, x0, x13 /* Mask out flags to get CPU ID */
> - b.eq boot_cpu /* If we're CPU 0, boot now */
> -
> - /* Non-boot CPUs wait here to be woken up one at a time. */
> -1: dsb sy
> - ldr x0, =smp_up_cpu /* VA of gate */
> - add x0, x0, x20 /* PA of gate */
> - ldr x1, [x0] /* Which CPU is being booted? */
> - cmp x1, x22 /* Is it us? */
> - b.eq 2f
> - wfe
> - b 1b
> -2:
> + bic x24, x0, x13 /* Mask out flags to get CPU ID */
> +1:
>
> -boot_cpu:
> #ifdef EARLY_PRINTK
> ldr x23, =EARLY_UART_BASE_ADDRESS /* x23 := UART base address */
> cbnz x22, 1f
> -#ifdef EARLY_PRINTK_INIT_UART
> - bl init_uart /* CPU 0 sets up the UART too */
> -#endif
> + bl init_uart /* Boot CPU sets up the UART too */
> 1: PRINT("- CPU ")
> - mov x0, x22
> + mov x0, x24
> bl putn
> PRINT(" booting -\r\n")
> #endif
> @@ -130,30 +165,18 @@ boot_cpu:
> bl putn
> PRINT(" -\r\n")
>
> - /* Are we in EL3 */
> - mrs x0, CurrentEL
> - cmp x0, #PSR_MODE_EL3t
> - ccmp x0, #PSR_MODE_EL3h, #0x4, ne
> - b.eq 1f /* Yes */
> -
> /* Are we in EL2 */
> cmp x0, #PSR_MODE_EL2t
> - ccmp x0, #PSR_MODE_EL2h, #0x4, ne
> - b.eq 2f /* Yes */
> -
> - /* Otherwise, it must have been EL0 or EL1 */
> - PRINT("- CPU is not in EL3 or EL2 -\r\n")
> - b fail
> + ccmp x0, #PSR_MODE_EL2h, #0x4, eq
> + b.eq el2 /* Yes */
>
> -1: PRINT("- Started in EL3 -\r\n- Entering EL2 -\r\n")
> - ldr x1, =enter_el2_mode /* VA of function */
> - add x1, x1, x20 /* PA of function */
> - adr x30, el2 /* Set return address for call */
> - br x1 /* Call function */
> + /* OK, we're boned. */
> + PRINT("- Xen must be entered in NS EL2 mode -\r\n" \
> + "- Please update the bootloader -\r\n")
> + b fail
>
> -2: PRINT("- Started in EL2 mode -\r\n")
> +el2: PRINT("- Xen starting at EL2 -\r\n")
>
> -el2:
> /* Zero BSS On the boot CPU to avoid nasty surprises */
> cbnz x22, skip_bss
>
> @@ -168,9 +191,10 @@ el2:
> b.lo 1b
>
> skip_bss:
> -
> PRINT("- Setting up control registers -\r\n")
>
> + /* XXXX call PROCINFO_cpu_init here */
> +
> /* Set up memory attribute type tables */
> ldr x0, =MAIRVAL
> msr mair_el2, x0
> @@ -184,7 +208,7 @@ skip_bss:
> ldr x0, =0x80802500
> msr tcr_el2, x0
>
> - /* Set up the HSCTLR:
> + /* Set up the SCTLR_EL2:
> * Exceptions in LE ARM,
> * Low-latency IRQs disabled,
> * Write-implies-XN disabled (for now),
> @@ -195,23 +219,11 @@ skip_bss:
> ldr x0, =(HSCTLR_BASE|SCTLR_A)
> msr SCTLR_EL2, x0
>
> - /* Write Xen's PT's paddr into the HTTBR */
> - ldr x4, =boot_pgtable
> - add x4, x4, x20 /* x4 := paddr (xen_pagetable) */
> - msr TTBR0_EL2, x4
> -
> - /* Non-boot CPUs don't need to rebuild the pagetable */
> - cbnz x22, pt_ready
> -
> - ldr x1, =boot_first
> - add x1, x1, x20 /* x1 := paddr (xen_first) */
> - mov x3, #PT_PT /* x2 := table map of xen_first */
> - orr x2, x1, x3 /* (+ rights for linear PT) */
> - str x2, [x4, #0] /* Map it in slot 0 */
> -
> - mov x4, x1 /* Next level into xen_first */
> + /* console fixmap */
> +#if defined(EARLY_PRINTK)
> + /* Non-boot CPUs don't need to rebuild the fixmap */
> + cbnz x22, 1f
>
> - /* console fixmap */
> ldr x1, =xen_fixmap
> add x1, x1, x20 /* x1 := paddr (xen_fixmap) */
> lsr x2, x23, #12
> @@ -219,45 +231,98 @@ skip_bss:
> mov x3, #PT_DEV_L3
> orr x2, x2, x3 /* x2 := 4K dev map including UART */
> str x2, [x1, #(FIXMAP_CONSOLE*8)] /* Map it in the first fixmap's slot */
> +1:
> +#endif
> +
> + /*
> + * Rebuild the boot pagetable's first-level entries. The structure
> + * is described in mm.c.
> + *
> + * After the CPU enables paging it will add the fixmap mapping
> + * to these page tables, however this may clash with the 1:1
> + * mapping. So each CPU must rebuild the page tables here with
> + * the 1:1 in place.
> + */
> +
> + /* Write Xen's PT's paddr into TTBR0_EL2 */
> + ldr x4, =boot_pgtable
> + add x4, x4, x20 /* x4 := paddr (boot_pagetable) */
> + msr TTBR0_EL2, x4
>
> - /* Build the baseline idle pagetable's first-level entries */
> - ldr x1, =xen_second
> - add x1, x1, x20 /* x1 := paddr (xen_second) */
> - mov x3, #PT_PT /* x2 := table map of xen_second */
> - orr x2, x1, x3 /* (+ rights for linear PT) */
> + /* Setup boot_pgtable: */
> + ldr x1, =boot_first
> + add x1, x1, x20 /* x1 := paddr (boot_first) */
> +
> + /* ... map boot_first in boot_pgtable[0] */
> + mov x3, #PT_PT /* x2 := table map of boot_first */
> + orr x2, x1, x3 /* + rights for linear PT */
> str x2, [x4, #0] /* Map it in slot 0 */
> - add x2, x2, #0x1000
> - str x2, [x4, #8] /* Map 2nd page in slot 1 */
> - add x2, x2, #0x1000
> - str x2, [x4, #16] /* Map 3rd page in slot 2 */
> - add x2, x2, #0x1000
> - str x2, [x4, #24] /* Map 4th page in slot 3 */
> -
> - /* Now set up the second-level entries */
> - mov x3, #PT_MEM
> - orr x2, x19, x3 /* x2 := 2MB normal map of Xen */
> - orr x4, xzr, x19, lsr #18
> - str x2, [x1, x4] /* Map Xen there */
> - ldr x4, =start
> - lsr x4, x4, #18 /* Slot for vaddr(start) */
> - str x2, [x1, x4] /* Map Xen there too */
>
> - /* xen_fixmap pagetable */
> - ldr x2, =xen_fixmap
> - add x2, x2, x20 /* x2 := paddr (xen_fixmap) */
> - mov x3, #PT_PT
> - orr x2, x2, x3 /* x2 := table map of xen_fixmap */
> - add x4, x4, #8
> - str x2, [x1, x4] /* Map it in the fixmap's slot */
> + /* ... map of paddr(start) in boot_pgtable */
> + lsr x1, x19, #39 /* Offset of base paddr in boot_pgtable */
> + cbz x1, 1f /* It's in slot 0, map in boot_first
> + * or boot_second later on */
>
> - lsr x2, x21, #21
> - lsl x2, x2, #21 /* 2MB-aligned paddr of DTB */
> - mov x3, #PT_MEM /* x2 := 2MB RAM incl. DTB */
> + lsl x2, x1, #39 /* Base address for 512GB mapping */
> + mov x3, #PT_MEM /* x2 := Section mapping */
> + orr x2, x2, x3
> + lsl x1, x1, #3 /* x1 := Slot offset */
> + str x2, [x4, x1] /* Mapping of paddr(start)*/
> +
> +1: /* Setup boot_first: */
> + ldr x4, =boot_first /* Next level into boot_first */
> + add x4, x4, x20 /* x4 := paddr(boot_first) */
> +
> + /* ... map boot_second in boot_first[0] */
> + ldr x1, =boot_second
> + add x1, x1, x20 /* x1 := paddr(boot_second) */
> + mov x3, #PT_PT /* x2 := table map of boot_first */
> + orr x2, x1, x3 /* + rights for linear PT */
> + str x2, [x4, #0] /* Map it in slot 0 */
> +
> + /* ... map of paddr(start) in boot_first */
> + lsr x2, x19, #30 /* x2 := Offset of base paddr in boot_first */
> + and x1, x2, 0x1ff /* x1 := Slot to use */
> + cbz x1, 1f /* It's in slot 0, map in boot_second */
> +
> + lsl x2, x2, #30 /* Base address for 1GB mapping */
> + mov x3, #PT_MEM /* x2 := Section map */
> orr x2, x2, x3
> - add x4, x4, #8
> - str x2, [x1, x4] /* Map it in the early boot slot */
> + lsl x1, x1, #3 /* x1 := Slot offset */
> + str x2, [x4, x1] /* Create mapping of paddr(start)*/
> +
> +1: /* Setup boot_second: */
> + ldr x4, =boot_second
> + add x4, x4, x20 /* x4 := paddr (boot_second) */
> +
> + lsr x2, x19, #20 /* Base address for 2MB mapping */
> + lsl x2, x2, #20
> + mov x3, #PT_MEM /* x2 := Section map */
> + orr x2, x2, x3
> +
> + /* ... map of vaddr(start) in boot_second */
> + ldr x1, =start
> + lsr x1, x1, #18 /* Slot for vaddr(start) */
> + str x2, [x4, x1] /* Map vaddr(start) */
> +
> + /* ... map of paddr(start) in boot_second */
> + mov x3, #PT_PT /* x2 := table map of boot_second */
> + orr x2, x1, x3 /* + rights for linear PT */
> +
> + lsr x1, x19, #30 /* Base paddr */
> + cbnz x1, 1f /* If paddr(start) is not in slot 0
> + * then the mapping was done in
> + * boot_pgtable or boot_first above */
> +
> + lsr x1, x19, #18 /* Slot for paddr(start) */
> + str x2, [x4, x1] /* Map Xen there */
> +
> + /* Defer fixmap and dtb mapping until after paging enabled, to
> + * avoid them clashing with the 1:1 mapping.
> + */
> +
> +1: /* boot pagetable setup complete */
>
> -pt_ready:
> PRINT("- Turning on paging -\r\n")
>
> ldr x1, =paging /* Explicit vaddr, not RIP-relative */
> @@ -270,17 +335,44 @@ pt_ready:
> br x1 /* Get a proper vaddr into PC */
> paging:
>
> + /* Now we can install the fixmap and dtb mappings, since we
> + * don't need the 1:1 map any more */
> + dsb sy
> + ldr x4, =boot_second
> +#if defined(EARLY_PRINTK)
> + /* xen_fixmap pagetable */
> + ldr x2, =xen_fixmap
> + add x2, x2, x20 /* x2 := paddr (xen_fixmap) */
> + mov x3, #PT_PT
> + orr x2, x2, x3 /* x2 := table map of xen_fixmap */
> + ldr x1, =FIXMAP_ADDR(0)
> + lsr x1, x1, #18 /* x1 := Slot for FIXMAP(0) */
> + str x2, [x4, x1] /* Map it in the fixmap's slot */
> +
> /* Use a virtual address to access the UART. */
> ldr x23, =FIXMAP_ADDR(FIXMAP_CONSOLE)
> +#endif
>
> - PRINT("- Ready -\r\n")
> + /* Map the DTB in the boot misc slot */
> + cbnz x22, 1f /* Only on boot CPU */
> +
> + lsr x2, x21, #21
> + lsl x2, x2, #21 /* x2 := 2MB-aligned paddr of DTB */
> + mov x3, #PT_MEM /* x2 := 2MB RAM incl. DTB */
> + orr x2, x2, x3
> + ldr x1, =BOOT_MISC_VIRT_START
> + lsr x1, x1, #18 /* x4 := Slot for BOOT_MISC_VIRT_START */
> + str x2, [x4, x1] /* Map it in the early boot slot */
> + dsb sy
> +
> +1: PRINT("- Ready -\r\n")
>
> /* The boot CPU should go straight into C now */
> cbz x22, launch
>
> - /* Non-boot CPUs need to move on to the relocated pagetables */
> - ldr x4, =boot_ttbr /* VA of TTBR0_EL2 stashed by CPU 0 */
> - add x4, x4, x20 /* PA of it */
> + /* Non-boot CPUs need to move on to the relocated pagetables,
> + temporarily use cpu0's table and switch */
> + ldr x4, =init_ttbr /* VA of TTBR0_EL2 stashed by CPU 0 */
> ldr x4, [x4] /* Actual value */
> dsb sy
> msr TTBR0_EL2, x4
> @@ -300,18 +392,6 @@ paging:
> dc cvac, x0 /* Flush D-Cache */
> dsb sy
>
> - /* 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 sy
> - ldr x0, =smp_up_cpu
> - ldr x1, [x0] /* Which CPU is being booted? */
> - cmp x1, x22 /* Is it us? */
> - b.ne 1b
> -
> launch:
> ldr x0, =init_stack /* Find the boot-time stack */
> ldr x0, [x0]
> @@ -321,7 +401,7 @@ launch:
>
> mov x0, x20 /* Marshal args: - phys_offset */
> mov x1, x21 /* - FDT */
> - mov x2, x22 /* - CPU ID */
> + mov x2, x24 /* - CPU ID */
> cbz x22, start_xen /* and disappear into the land of C */
> b start_secondary /* (to the appropriate entry point) */
>
> @@ -331,13 +411,80 @@ fail: PRINT("- Boot failed -\r\n")
> 1: wfe
> b 1b
>
> -#ifdef EARLY_PRINTK
> +/*
> + * Copy Xen to new location and switch TTBR
> + * x0 ttbr
> + * x1 source address
> + * x2 destination address
> + * x3 length
> + *
> + * Source and destination must be word aligned, length is rounded up
> + * to a 16 byte boundary.
> + *
> + * MUST BE VERY CAREFUL when saving things to RAM over the copy
> + */
> +ENTRY(relocate_xen)
> + /* Copy 16 bytes at a time using:
> + * x9: counter
> + * x10: data
> + * x11: data
> + * x12: source
> + * x13: destination
> + */
> + mov x9, x3
> + mov x12, x1
> + mov x13, x2
> +
> +1: ldp x10, x11, [x12], #16
> + stp x10, x11, [x13], #16
> +
> + subs x9, x9, #16
> + bgt 1b
> +
> + /* Flush destination from dcache using:
> + * x9: counter
> + * x10: step
> + * x11: vaddr
> + */
> + dsb sy /* So the CPU issues all writes to the range */
> +
> + mov x9, x3
> + ldr x10, =cacheline_bytes /* x10 := step */
> + ldr x10, [x10]
> + mov x11, x2
>
> +1: dc cvac, x11
> +
> + add x11, x11, x10
> + subs x9, x9, x10
> + bgt 1b
> +
> + dsb sy /* So we know the flushes happen before continuing */
> +
> + isb /* Ensure synchronization with previous changes to text */
> + tlbi alle2 /* Flush hypervisor TLB */
> + ic iallu /* Flush I-cache */
> + dsb sy /* Ensure completion of TLB flush */
> + isb
> +
> + msr TTBR0_EL2, x0
> +
> + isb /* Ensure synchronization with previous changes to text */
> + tlbi alle2 /* Flush hypervisor TLB */
> + ic iallu /* Flush I-cache */
> + dsb sy /* Ensure completion of TLB flush */
> + isb
> +
> + ret
> +
> +#ifdef EARLY_PRINTK
> /* Bring up the UART.
> * x23: Early UART base address
> * Clobbers x0-x1 */
> init_uart:
> +#ifdef EARLY_PRINTK_INIT_UART
> early_uart_init x23, 0
> +#endif
> adr x0, 1f
> b puts
> 1: .asciz "- UART enabled -\r\n"
> diff --git a/xen/arch/arm/arm64/mode_switch.S b/xen/arch/arm/arm64/mode_switch.S
> deleted file mode 100644
> index ea64f22..0000000
> --- a/xen/arch/arm/arm64/mode_switch.S
> +++ /dev/null
> @@ -1,89 +0,0 @@
> -/*
> - * xen/arch/arm/arm64/mode_switch.S
> - *
> - * Start-of day code to take a CPU from EL3 to EL2. Largely taken from
> - * bootwrapper.
> - *
> - * Ian Campbell <ian.campbell@citrix.com>
> - * Copyright (c) 2012 Citrix Systems.
> - *
> - * This program is free software; you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation; either version 2 of the License, or
> - * (at your option) any later version.
> - *
> - * This program is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - */
> -
> -#include <asm/config.h>
> -#include <asm/page.h>
> -#include <asm/asm_defns.h>
> -#include <asm/platforms/vexpress.h>
> -
> -/* Get up a CPU into EL2. Clobbers x0-x3.
> - *
> - * Expects x22 == CPU number
> - * Expects x30 == EL2 entry point
> - *
> - * This code is specific to the VE model, and not intended to be used
> - * on production systems. As such it's a bit hackier than the main
> - * boot code in head.S. In future it will be replaced by better
> - * integration with the bootloader/firmware so that Xen always starts
> - * at EL2.
> - */
> -GLOBAL(enter_el2_mode)
> - mov x0, #0x30 // RES1
> - orr x0, x0, #(1 << 0) // Non-secure EL1
> - orr x0, x0, #(1 << 8) // HVC enable
> - orr x0, x0, #(1 << 10) // 64-bit EL2
> - msr scr_el3, x0
> -
> - msr cptr_el3, xzr // Disable copro. traps to EL3
> -
> - ldr x0, =0x01800000 // 24Mhz
> - msr cntfrq_el0, x0
> -
> - /*
> - * Check for the primary CPU to avoid a race on the distributor
> - * registers.
> - */
> - cbnz x22, 1f
> -
> - ldr x1, =(V2M_GIC_BASE_ADDRESS+GIC_DR_OFFSET) // GICD_CTLR
> - mov w0, #3 // EnableGrp0 | EnableGrp1
> - str w0, [x1]
> -
> -1: ldr x1, =(V2M_GIC_BASE_ADDRESS+GIC_DR_OFFSET+0x80) // GICD_IGROUPR
> - mov w0, #~0 // Grp1 interrupts
> - str w0, [x1], #4
> - b.ne 2f // Only local interrupts for secondary CPUs
> - str w0, [x1], #4
> - str w0, [x1], #4
> -
> -2: ldr x1, =(V2M_GIC_BASE_ADDRESS+GIC_CR_OFFSET) // GICC_CTLR
> - ldr w0, [x1]
> - mov w0, #3 // EnableGrp0 | EnableGrp1
> - str w0, [x1]
> -
> - mov w0, #1 << 7 // allow NS access to GICC_PMR
> - str w0, [x1, #4] // GICC_PMR
> -
> - msr sctlr_el2, xzr
> -
> - /*
> - * Prepare the switch to the EL2_SP1 mode from EL3
> - */
> - msr elr_el3, x30 // Return to desired function
> - mov x1, #0x3c9 // EL2_SP1 | D | A | I | F
> - msr spsr_el3, x1
> - eret
> -
> -/*
> - * Local variables:
> - * mode: ASM
> - * indent-tabs-mode: nil
> - * End:
> - */
> diff --git a/xen/arch/arm/arm64/smpboot.c b/xen/arch/arm/arm64/smpboot.c
> new file mode 100644
> index 0000000..4d1b7f8
> --- /dev/null
> +++ b/xen/arch/arm/arm64/smpboot.c
> @@ -0,0 +1,80 @@
> +#include <xen/cpu.h>
> +#include <xen/lib.h>
> +#include <xen/init.h>
> +#include <xen/errno.h>
> +#include <xen/mm.h>
> +#include <xen/smp.h>
> +
> +struct smp_enable_ops {
> +// const char *name;
> +// int (*init_cpu)(struct dt_device_node *, int);
> + int (*prepare_cpu)(int);
> +};
> +
> +static paddr_t cpu_release_addr[NR_CPUS];
> +static struct smp_enable_ops smp_enable_ops[NR_CPUS];
> +
> +static int __init smp_spin_table_cpu_up(int cpu)
> +{
> + paddr_t *release;
> +
> + if (!cpu_release_addr[cpu])
> + {
> + printk("CPU%d: No release addr\n", cpu);
> + return -ENODEV;
> + }
> +
> + release = __va(cpu_release_addr[cpu]);
> +
> + release[0] = __pa(init_secondary);
> + flush_xen_data_tlb_range_va((vaddr_t)release, sizeof(*release));
> +
> + sev();
> + return 0;
> +}
> +
> +static void __init smp_spin_table_init(int cpu, struct dt_device_node *dn)
> +{
> + if ( !dt_property_read_u64(dn, "cpu-release-addr", &cpu_release_addr[cpu]) )
> + {
> + printk("CPU%d has no cpu-release-addr\n", cpu);
> + return;
> + }
> +
> + smp_enable_ops[cpu].prepare_cpu = smp_spin_table_cpu_up;
> +}
> +
> +void __init arch_cpu_init(int cpu, struct dt_device_node *dn)
> +{
> + const char *enable_method;
> +
> + enable_method = dt_get_property(dn, "enable-method", NULL);
> + if (!enable_method)
> + {
> + printk("CPU%d has no enable method\n", cpu);
> + return;
> + }
> +
> + if ( !strcmp(enable_method, "spin-table") )
> + smp_spin_table_init(cpu, dn);
> + /* TODO: method "psci" */
> + else
> + printk("CPU%d has unknown enable method \"%s\"\n", cpu, enable_method);
> +}
> +
> +int __init arch_cpu_up(int cpu)
> +{
> + if ( !smp_enable_ops[cpu].prepare_cpu )
> + return -ENODEV;
> +
> + return smp_enable_ops[cpu].prepare_cpu(cpu);
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index cdd5cba..efac619 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -43,40 +43,70 @@
>
> struct domain *dom_xen, *dom_io, *dom_cow;
>
> -/* Static start-of-day pagetables that we use before the
> - * allocators are up. These go on to become the boot CPU's real pagetables.
> +/* Static start-of-day pagetables that we use before the allocators
> + * are up. These are used by all CPUs during bringup before switching
> + * to the CPUs own pagetables.
> + *
> + * These pagetables have a very simple structure. They include:
> + * - a 2MB mapping of xen at XEN_VIRT_START, boot_first and
> + * boot_second are used to populate the trie down to that mapping.
> + * - a 1:1 mapping of xen at its current physical address. This uses a
> + * section mapping at whichever of boot_{pgtable,first,second}
> + * covers that physical address.
> + *
> + * For the boot CPU these mappings point to the address where Xen was
> + * loaded by the bootloader. For secondary CPUs they point to the
> + * relocated copy of Xen for the benefit of secondary CPUs.
> + *
> + * In addition to the above for the boot CPU the device-tree is
> + * initially mapped in the boot misc slot. This mapping is not present
> + * for secondary CPUs.
> + *
> + * Finally, if EARLY_PRINTK is enabled then xen_fixmap will be mapped
> + * by the CPU once it has moved off the 1:1 mapping.
> */
> lpae_t boot_pgtable[LPAE_ENTRIES] __attribute__((__aligned__(4096)));
> #ifdef CONFIG_ARM_64
> lpae_t boot_first[LPAE_ENTRIES] __attribute__((__aligned__(4096)));
> -/* The first page of the first level mapping of the xenheap. The
> - * subsequent xenheap first level pages are dynamically allocated, but
> - * we need this one to bootstrap ourselves. */
> -lpae_t xenheap_first_first[LPAE_ENTRIES] __attribute__((__aligned__(4096)));
> -/* The zeroeth level slot which uses xenheap_first_first. Used because
> - * setup_xenheap_mappings otherwise relies on mfn_to_virt which isn't
> - * valid for a non-xenheap mapping. */
> -static __initdata int xenheap_first_first_slot = -1;
> #endif
> +lpae_t boot_second[LPAE_ENTRIES] __attribute__((__aligned__(4096)));
> +
> +/* Main runtime page tables */
>
> /*
> - * xen_pgtable and xen_dommap are per-PCPU and are allocated before
> - * bringing up each CPU. On 64-bit a first level table is also allocated.
> + * For arm32 xen_pgtable and xen_dommap are per-PCPU and are allocated before
> + * bringing up each CPU. For arm64 xen_pgtable is common to all PCPUs.
> *
> - * xen_second, xen_fixmap and xen_xenmap are shared between all PCPUs.
> + * xen_second, xen_fixmap and xen_xenmap are always shared between all
> + * PCPUs.
> */
>
> #ifdef CONFIG_ARM_64
> -#define THIS_CPU_PGTABLE boot_pgtable
> +lpae_t xen_pgtable[LPAE_ENTRIES] __attribute__((__aligned__(4096)));
> +lpae_t xen_first[LPAE_ENTRIES] __attribute__((__aligned__(4096)));
> +#define THIS_CPU_PGTABLE xen_pgtable
> #else
> /* Per-CPU pagetable pages */
> /* xen_pgtable == root of the trie (zeroeth level on 64-bit, first on 32-bit) */
> static DEFINE_PER_CPU(lpae_t *, xen_pgtable);
> #define THIS_CPU_PGTABLE this_cpu(xen_pgtable)
> /* xen_dommap == pages used by map_domain_page, these pages contain
> - * the second level pagetables which mapp the domheap region
> + * the second level pagetables which map the domheap region
> * DOMHEAP_VIRT_START...DOMHEAP_VIRT_END in 2MB chunks. */
> static DEFINE_PER_CPU(lpae_t *, xen_dommap);
> +/* Root of the trie for cpu0 */
> +lpae_t cpu0_pgtable[LPAE_ENTRIES] __attribute__((__aligned__(4096)));
> +#endif
> +
> +#ifdef CONFIG_ARM_64
> +/* The first page of the first level mapping of the xenheap. The
> + * subsequent xenheap first level pages are dynamically allocated, but
> + * we need this one to bootstrap ourselves. */
> +lpae_t xenheap_first_first[LPAE_ENTRIES] __attribute__((__aligned__(4096)));
> +/* The zeroeth level slot which uses xenheap_first_first. Used because
> + * setup_xenheap_mappings otherwise relies on mfn_to_virt which isn't
> + * valid for a non-xenheap mapping. */
> +static __initdata int xenheap_first_first_slot = -1;
> #endif
>
> /* Common pagetable leaves */
> @@ -104,9 +134,8 @@ lpae_t xen_fixmap[LPAE_ENTRIES] __attribute__((__aligned__(4096)));
> * as appropriate. */
> static lpae_t xen_xenmap[LPAE_ENTRIES] __attribute__((__aligned__(4096)));
>
> -
> /* Non-boot CPUs use this to find the correct pagetables. */
> -uint64_t boot_ttbr;
> +uint64_t init_ttbr;
>
> static paddr_t phys_offset;
>
> @@ -131,6 +160,12 @@ static inline void check_memory_layout_alignment_constraints(void) {
> BUILD_BUG_ON(BOOT_MISC_VIRT_START & ~SECOND_MASK);
> /* 1GB aligned regions */
> BUILD_BUG_ON(XENHEAP_VIRT_START & ~FIRST_MASK);
> + /* Page table structure constraints */
> +#ifdef CONFIG_ARM_64
> + BUILD_BUG_ON(zeroeth_table_offset(XEN_VIRT_START));
> +#endif
> + BUILD_BUG_ON(first_table_offset(XEN_VIRT_START));
> + BUILD_BUG_ON(second_linear_offset(XEN_VIRT_START) >= LPAE_ENTRIES);
> #ifdef CONFIG_DOMAIN_PAGE
> BUILD_BUG_ON(DOMHEAP_VIRT_START & ~FIRST_MASK);
> #endif
> @@ -361,16 +396,6 @@ void __cpuinit setup_virt_paging(void)
> WRITE_SYSREG32(0x80002558, VTCR_EL2); isb();
> }
>
> -/* This needs to be a macro to stop the compiler spilling to the stack
> - * which will change when we change pagetables */
> -#define WRITE_TTBR(ttbr) \
> - flush_xen_text_tlb(); \
> - WRITE_SYSREG64(ttbr, TTBR0_EL2); \
> - dsb(); /* ensure memory accesses do not cross over the TTBR0 write */ \
> - /* flush_xen_text_tlb contains an initial isb which ensures the \
> - * write to TTBR0 has completed. */ \
> - flush_xen_text_tlb()
> -
> static inline lpae_t pte_of_xenaddr(vaddr_t va)
> {
> paddr_t ma = va + phys_offset;
> @@ -378,69 +403,67 @@ static inline lpae_t pte_of_xenaddr(vaddr_t va)
> return mfn_to_xen_entry(mfn);
> }
>
> +extern void relocate_xen(uint64_t ttbr, void *src, void *dst, size_t len);
> +
> /* Boot-time pagetable setup.
> * Changes here may need matching changes in head.S */
> void __init setup_pagetables(unsigned long boot_phys_offset, paddr_t xen_paddr)
> {
> + uint64_t ttbr;
> unsigned long dest_va;
> lpae_t pte, *p;
> int i;
>
> - /* Map the destination in the boot misc area. */
> - dest_va = BOOT_MISC_VIRT_START;
> - pte = mfn_to_xen_entry(xen_paddr >> PAGE_SHIFT);
> - write_pte(xen_second + second_table_offset(dest_va), pte);
> - flush_xen_data_tlb_range_va(dest_va, SECOND_SIZE);
> -
> /* Calculate virt-to-phys offset for the new location */
> phys_offset = xen_paddr - (unsigned long) _start;
>
> - /* Copy */
> - memcpy((void *) dest_va, _start, _end - _start);
> -
> - /* Beware! Any state we modify between now and the PT switch may be
> - * discarded when we switch over to the copy. */
> -
> - /* Update the copy of boot_pgtable to use the new paddrs */
> - p = (void *) boot_pgtable + dest_va - (unsigned long) _start;
> #ifdef CONFIG_ARM_64
> - p[0].pt.base += (phys_offset - boot_phys_offset) >> PAGE_SHIFT;
> - p = (void *) boot_first + dest_va - (unsigned long) _start;
> + p = (void *) xen_pgtable;
> + p[0] = pte_of_xenaddr((uintptr_t)xen_first);
> + p[0].pt.table = 1;
> + p[0].pt.xn = 0;
> + p = (void *) xen_first;
> +#else
> + p = (void *) cpu0_pgtable;
> #endif
> - 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 )
> + /* Initialise first level entries, to point to second level entries */
> + for ( i = 0; i < 4; i++)
> {
> - /* Remove the old identity mapping of the boot paddr */
> - vaddr_t va = (vaddr_t)_start + boot_phys_offset;
> - p[second_linear_offset(va)].bits = 0;
> + p[i] = pte_of_xenaddr((uintptr_t)(xen_second+i*LPAE_ENTRIES));
> + p[i].pt.table = 1;
> + p[i].pt.xn = 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_ttbr = (uintptr_t) boot_pgtable + phys_offset;
> - flush_xen_dcache(boot_ttbr);
> - flush_xen_dcache_va_range((void*)dest_va, _end - _start);
> + /* Initialise xen second level entries ... */
> + /* ... Xen's text etc */
>
> - WRITE_TTBR(boot_ttbr);
> -
> - /* Undo the temporary map */
> - pte.bits = 0;
> - write_pte(xen_second + second_table_offset(dest_va), pte);
> - flush_xen_text_tlb();
> + pte = mfn_to_xen_entry(xen_paddr>>PAGE_SHIFT);
> + pte.pt.xn = 0;/* Contains our text mapping! */
> + xen_second[second_table_offset(XEN_VIRT_START)] = pte;
>
> - /* Link in the fixmap pagetable */
> + /* ... Fixmap */
> pte = pte_of_xenaddr((vaddr_t)xen_fixmap);
> pte.pt.table = 1;
> - write_pte(xen_second + second_table_offset(FIXMAP_ADDR(0)), pte);
> - /*
> - * No flush required here. Individual flushes are done in
> - * set_fixmap as entries are used.
> - */
> + xen_second[second_table_offset(FIXMAP_ADDR(0))] = pte;
> +
> + /* Map the destination in the boot misc area. */
> + dest_va = BOOT_MISC_VIRT_START;
> + pte = mfn_to_xen_entry(xen_paddr >> PAGE_SHIFT);
> + write_pte(boot_second + second_table_offset(dest_va), pte);
> + flush_xen_data_tlb_range_va(dest_va, SECOND_SIZE);
> +#ifdef CONFIG_ARM_64
> + ttbr = (uintptr_t) xen_pgtable + phys_offset;
> +#else
> + ttbr = (uintptr_t) cpu0_pgtable + phys_offset;
> +#endif
> +
> + relocate_xen(ttbr, _start, (void*)dest_va, _end - _start);
> +
> + /* Clear the copy of the boot pagetables. Each secondary CPU
> + * rebuilds these itself (see head.S) */
> + memset(boot_pgtable, 0x0, PAGE_SIZE);
> + memset(boot_second, 0x0, PAGE_SIZE);
>
> /* Break up the Xen mapping into 4k pages and protect them separately. */
> for ( i = 0; i < LPAE_ENTRIES; i++ )
> @@ -461,6 +484,7 @@ void __init setup_pagetables(unsigned long boot_phys_offset, paddr_t xen_paddr)
> write_pte(xen_xenmap + i, pte);
> /* No flush required here as page table is not hooked in yet. */
> }
> +
> pte = pte_of_xenaddr((vaddr_t)xen_xenmap);
> pte.pt.table = 1;
> write_pte(xen_second + second_linear_offset(XEN_VIRT_START), pte);
> @@ -472,7 +496,7 @@ void __init setup_pagetables(unsigned long boot_phys_offset, paddr_t xen_paddr)
> flush_xen_text_tlb();
>
> #ifdef CONFIG_ARM_32
> - per_cpu(xen_pgtable, 0) = boot_pgtable;
> + per_cpu(xen_pgtable, 0) = cpu0_pgtable;
> per_cpu(xen_dommap, 0) = xen_second +
> second_linear_offset(DOMHEAP_VIRT_START);
>
> @@ -482,7 +506,13 @@ void __init setup_pagetables(unsigned long boot_phys_offset, paddr_t xen_paddr)
> flush_xen_dcache_va_range(this_cpu(xen_dommap),
> DOMHEAP_SECOND_PAGES*PAGE_SIZE);
> #endif
> +
> + /* All cpus start on boot page tables, then switch to cpu0's (both
> + * in head.S), finally onto their own in mmu_init_secondary_cpu. */
> + init_ttbr = (uintptr_t) THIS_CPU_PGTABLE + phys_offset;
> + flush_xen_dcache(init_ttbr);
> }
> +
> #ifdef CONFIG_ARM_64
> int init_secondary_pagetables(int cpu)
> {
> @@ -507,7 +537,7 @@ int init_secondary_pagetables(int cpu)
> }
>
> /* Initialise root pagetable from root of boot tables */
> - memcpy(first, boot_pgtable, PAGE_SIZE);
> + memcpy(first, cpu0_pgtable, PAGE_SIZE);
>
> /* Ensure the domheap has no stray mappings */
> memset(domheap, 0, DOMHEAP_SECOND_PAGES*PAGE_SIZE);
> @@ -538,7 +568,13 @@ void __cpuinit mmu_init_secondary_cpu(void)
>
> /* Change to this CPU's pagetables */
> ttbr = (uintptr_t)virt_to_maddr(THIS_CPU_PGTABLE);
> - WRITE_TTBR(ttbr);
> +
> + flush_xen_text_tlb();
> + WRITE_SYSREG64(ttbr, TTBR0_EL2);
> + dsb(); /* ensure memory accesses do not cross over the TTBR0 write */
> + /* flush_xen_text_tlb contains an initial isb which ensures the
> + * write to TTBR0 has completed. */
> + flush_xen_text_tlb();
>
> /* From now on, no mapping may be both writable and executable. */
> WRITE_SYSREG32(READ_SYSREG32(SCTLR_EL2) | SCTLR_WXN, SCTLR_EL2);
> @@ -612,7 +648,7 @@ void __init setup_xenheap_mappings(unsigned long base_mfn,
> while ( base_mfn < end_mfn )
> {
> int slot = zeroeth_table_offset(vaddr);
> - lpae_t *p = &boot_pgtable[slot];
> + lpae_t *p = &xen_pgtable[slot];
>
> if ( p->pt.valid )
> {
> @@ -679,7 +715,7 @@ void __init setup_frametable_mappings(paddr_t ps, paddr_t pe)
> {
> pte = mfn_to_xen_entry(second_base + i);
> pte.pt.table = 1;
> - write_pte(&boot_first[first_table_offset(FRAMETABLE_VIRT_START)+i], pte);
> + write_pte(&xen_first[first_table_offset(FRAMETABLE_VIRT_START)+i], pte);
> }
> create_32mb_mappings(second, 0, base_mfn, frametable_size >> PAGE_SHIFT);
> #else
> diff --git a/xen/arch/arm/platform.c b/xen/arch/arm/platform.c
> index afda302..0060b8a 100644
> --- a/xen/arch/arm/platform.c
> +++ b/xen/arch/arm/platform.c
> @@ -105,6 +105,24 @@ int __init platform_specific_mapping(struct domain *d)
> return res;
> }
>
> +#ifdef CONFIG_ARM_32
> +int platform_cpu_up(int cpu)
> +{
> + if ( platform && platform->cpu_up )
> + return platform->cpu_up(cpu);
> +
> + return -EAGAIN;
> +}
> +
> +int platform_cpu_init(int cpu)
> +{
> + if ( platform && platform->cpu_init )
> + return platform->cpu_init(cpu);
> +
> + return 0;
> +}
> +#endif
> +
> void platform_reset(void)
> {
> if ( platform && platform->reset )
> diff --git a/xen/arch/arm/platforms/vexpress.c b/xen/arch/arm/platforms/vexpress.c
> index 6f7dc2c..2d8d905 100644
> --- a/xen/arch/arm/platforms/vexpress.c
> +++ b/xen/arch/arm/platforms/vexpress.c
> @@ -21,6 +21,7 @@
> #include <asm/platform.h>
> #include <xen/mm.h>
> #include <xen/vmap.h>
> +#include <asm/gic.h>
>
> #define DCC_SHIFT 26
> #define FUNCTION_SHIFT 20
> @@ -119,6 +120,41 @@ static void vexpress_reset(void)
> iounmap(sp810);
> }
>
> +#ifdef CONFIG_ARM_32
> +static int vexpress_cpu_up(int cpu)
> +{
> + static int have_set_sysflags = 0;
> +
> + /* XXX separate init hook? */
> + if ( !have_set_sysflags )
> + {
> + void __iomem *sysflags;
> +
> + sysflags = ioremap_nocache(V2M_SYS_MMIO_BASE, PAGE_SIZE);
> + if ( !sysflags )
> + {
> + dprintk(XENLOG_ERR, "Unable to map vexpress MMIO\n");
> + return -EFAULT;
> + }
> +
> + printk("Set SYS_FLAGS to %"PRIpaddr" (%p)\n",
> + __pa(init_secondary), init_secondary);
> + iowritel(sysflags + V2M_SYS_FLAGSCLR, ~0);
> + iowritel(sysflags + V2M_SYS_FLAGSSET,
> + __pa(init_secondary));
> +
> + iounmap(sysflags);
> +
> + have_set_sysflags = 1;
> + }
> +
> + printk("Waking CPU%d\n", cpu);
> + send_SGI_mask(cpumask_of(cpu), GIC_SGI_EVENT_CHECK);
> +
> + return 0;
> +}
> +#endif
> +
> static const char * const vexpress_dt_compat[] __initdata =
> {
> "arm,vexpress",
> @@ -127,6 +163,9 @@ static const char * const vexpress_dt_compat[] __initdata =
>
> PLATFORM_START(vexpress, "VERSATILE EXPRESS")
> .compatible = vexpress_dt_compat,
> +#ifdef CONFIG_ARM_32
> + .cpu_up = vexpress_cpu_up,
> +#endif
> .reset = vexpress_reset,
> PLATFORM_END
>
> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
> index 94b1362..3a3c360 100644
> --- a/xen/arch/arm/setup.c
> +++ b/xen/arch/arm/setup.c
> @@ -548,7 +548,6 @@ void __init start_xen(unsigned long boot_phys_offset,
> init_xen_time();
>
> gic_init();
> - make_cpus_ready(cpus, boot_phys_offset);
>
> set_current((struct vcpu *)0xfffff000); /* debug sanity */
> idle_vcpu[0] = current;
> diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
> index b6aea63..40e48a1 100644
> --- a/xen/arch/arm/smpboot.c
> +++ b/xen/arch/arm/smpboot.c
> @@ -49,8 +49,7 @@ static unsigned char __initdata cpu0_boot_stack[STACK_SIZE]
> /* Pointer to the stack, used by head.S when entering C */
> unsigned char *init_stack = cpu0_boot_stack;
>
> -/* Shared state for coordinating CPU bringup */
> -unsigned long smp_up_cpu = 0;
> +/* Shared state for coordinating CPU teardown */
> static bool_t cpu_is_dead = 0;
>
> /* Number of non-boot CPUs ready to enter C */
> @@ -96,40 +95,20 @@ smp_get_max_cpus (void)
> return max_cpus;
> }
>
> -
> void __init
> smp_prepare_cpus (unsigned int max_cpus)
> {
> + struct dt_device_node *dn = NULL;
> + int cpu = 0;
> cpumask_copy(&cpu_present_map, &cpu_possible_map);
>
> setup_cpu_sibling_map(0);
> -}
>
> -void __init
> -make_cpus_ready(unsigned int max_cpus, unsigned long boot_phys_offset)
> -{
> - unsigned long *gate;
> - paddr_t gate_pa;
> - int i;
> -
> - printk("Waiting for %i other CPUs to be ready\n", max_cpus - 1);
> - /* We use the unrelocated copy of smp_up_cpu as that's the one the
> - * others can see. */
> - gate_pa = ((paddr_t) (unsigned long) &smp_up_cpu) + boot_phys_offset;
> - gate = map_domain_page(gate_pa >> PAGE_SHIFT) + (gate_pa & ~PAGE_MASK);
> - for ( i = 1; i < max_cpus; i++ )
> - {
> - /* Tell the next CPU to get ready */
> - /* TODO: handle boards where CPUIDs are not contiguous */
> - *gate = i;
> - flush_xen_dcache(*gate);
> - isb();
> - sev();
> - /* And wait for it to respond */
> - while ( ready_cpus < i )
> - smp_rmb();
> + while ((dn = dt_find_node_by_type(dn, "cpu"))) {
> + /* TODO: replace using code from Juliens MIDR parsing patch */
> + arch_cpu_init(cpu++, dn);
> }
> - unmap_domain_page(gate);
> +
> }
>
> /* Boot the current CPU */
> @@ -226,14 +205,13 @@ 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;
> - /* we need to make sure that the change to smp_up_cpu is visible to
> - * secondary cpus with D-cache off */
> - flush_xen_dcache(smp_up_cpu);
> - isb();
> - sev();
> + rc = arch_cpu_up(cpu);
> +
> + if ( rc < 0 )
> + {
> + printk("Failed to bring up CPU%d\n", cpu);
> + return rc;
> + }
>
> while ( !cpu_online(cpu) )
> {
> @@ -262,7 +240,6 @@ void __cpu_die(unsigned int cpu)
> mb();
> }
>
> -
> /*
> * Local variables:
> * mode: C
> diff --git a/xen/include/asm-arm/platform.h b/xen/include/asm-arm/platform.h
> index f460e9c..f616807 100644
> --- a/xen/include/asm-arm/platform.h
> +++ b/xen/include/asm-arm/platform.h
> @@ -14,6 +14,11 @@ struct platform_desc {
> /* Platform initialization */
> int (*init)(void);
> int (*init_time)(void);
> +#ifdef CONFIG_ARM_32
> + /* SMP */
> + int (*cpu_init)(int cpu);
I don't think a cpu_init callback is usefull. An smp_init callback would
be better.
This will allow you to move the sys_flags check for the versatile
express in smp_init.
> + int (*cpu_up)(int cpu);
> +#endif
> /* Specific mapping for dom0 */
> int (*specific_mapping)(struct domain *d);
> /* Platform reset */
> @@ -37,6 +42,10 @@ struct platform_desc {
> int __init platform_init(void);
> int __init platform_init_time(void);
> int __init platform_specific_mapping(struct domain *d);
> +#ifdef CONFIG_ARM_32
> +int platform_cpu_init(int cpu);
> +int platform_cpu_up(int cpu);
> +#endif
> void platform_reset(void);
> void platform_poweroff(void);
> bool_t platform_has_quirk(uint32_t quirk);
> diff --git a/xen/include/asm-arm/platforms/exynos5.h b/xen/include/asm-arm/platforms/exynos5.h
> index ee5bdfa..af30608 100644
> --- a/xen/include/asm-arm/platforms/exynos5.h
> +++ b/xen/include/asm-arm/platforms/exynos5.h
> @@ -14,20 +14,6 @@
>
> #define S5P_PA_SYSRAM 0x02020000
>
> -/* Constants below is only used in assembly because the DTS is not yet parsed */
> -#ifdef __ASSEMBLY__
> -
> -/* GIC Base Address */
> -#define EXYNOS5_GIC_BASE_ADDRESS 0x10480000
> -
> -/* Timer's frequency */
> -#define EXYNOS5_TIMER_FREQUENCY (24 * 1000 * 1000) /* 24 MHz */
> -
> -/* Arndale machine ID */
> -#define MACH_TYPE_SMDK5250 3774
> -
> -#endif /* __ASSEMBLY__ */
> -
> #endif /* __ASM_ARM_PLATFORMS_EXYNOS5_H */
> /*
> * Local variables:
> diff --git a/xen/include/asm-arm/platforms/vexpress.h b/xen/include/asm-arm/platforms/vexpress.h
> index 982a293..5cf3aba 100644
> --- a/xen/include/asm-arm/platforms/vexpress.h
> +++ b/xen/include/asm-arm/platforms/vexpress.h
> @@ -32,17 +32,6 @@
> int vexpress_syscfg(int write, int function, int device, uint32_t *data);
> #endif
>
> -/* Constants below is only used in assembly because the DTS is not yet parsed */
> -#ifdef __ASSEMBLY__
> -
> -/* GIC base address */
> -#define V2M_GIC_BASE_ADDRESS 0x2c000000
> -
> -/* Timer's frequency */
> -#define V2M_TIMER_FREQUENCY 0x5f5e100 /* 100 Mhz */
> -
> -#endif /* __ASSEMBLY__ */
> -
> #endif /* __ASM_ARM_PLATFORMS_VEXPRESS_H */
> /*
> * Local variables:
> diff --git a/xen/include/asm-arm/smp.h b/xen/include/asm-arm/smp.h
> index 1c2746b..d57a088 100644
> --- a/xen/include/asm-arm/smp.h
> +++ b/xen/include/asm-arm/smp.h
> @@ -4,6 +4,7 @@
> #ifndef __ASSEMBLY__
> #include <xen/config.h>
> #include <xen/cpumask.h>
> +#include <xen/device_tree.h>
> #include <asm/current.h>
> #endif
>
> @@ -16,15 +17,16 @@ DECLARE_PER_CPU(cpumask_var_t, cpu_core_mask);
>
> extern void stop_cpu(void);
>
> -/* Bring the non-boot CPUs up to paging and ready to enter C.
> - * Must be called after Xen is relocated but before the original copy of
> - * .text gets overwritten. */
> -extern void
> -make_cpus_ready(unsigned int max_cpus, unsigned long boot_phys_offset);
> +extern void arch_cpu_init(int cpu, struct dt_device_node *dn);
> +extern int arch_cpu_up(int cpu);
> +
> +/* Secondary CPU entry point */
> +extern void init_secondary(void);
>
> extern void smp_clear_cpu_maps (void);
> extern int smp_get_max_cpus (void);
> #endif
> +
> /*
> * Local variables:
> * mode: C
>
--
Julien Grall
next prev parent reply other threads:[~2013-09-17 16:18 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-09-17 1:37 [PATCH RFC 0/N] xen: arm: rework early bring up Ian Campbell
2013-09-17 1:40 ` [PATCH RFC 1/7] xen: arm: Load xen under 4GB on 32-bit Ian Campbell
2013-09-18 15:44 ` Julien Grall
2013-09-19 9:21 ` Tim Deegan
2013-09-17 1:40 ` [PATCH RFC 2/7] xen: arm: Log the raw MIDR on boot Ian Campbell
2013-09-17 12:05 ` Julien Grall
2013-09-19 9:21 ` Tim Deegan
2013-09-17 1:40 ` [PATCH RFC 3/7] xen: arm: make sure we stay within the memory bank during mm setup Ian Campbell
2013-09-17 12:19 ` Julien Grall
2013-09-19 9:27 ` Tim Deegan
2013-09-17 1:40 ` [PATCH RFC 4/7] xen: arm: add two new device tree helpers Ian Campbell
2013-09-17 13:05 ` Julien Grall
2013-09-18 17:11 ` Julien Grall
2013-09-18 17:14 ` Ian Campbell
2013-09-17 1:40 ` [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up Ian Campbell
2013-09-17 16:18 ` Julien Grall [this message]
2013-09-17 16:36 ` Ian Campbell
2013-09-17 16:55 ` Julien Grall
2013-09-17 18:30 ` Andre Przywara
2013-09-17 19:19 ` Ian Campbell
2013-09-18 13:57 ` Julien Grall
2013-09-18 15:12 ` Ian Campbell
2013-09-18 17:06 ` Julien Grall
2013-09-18 17:14 ` Ian Campbell
2013-09-19 11:36 ` Tim Deegan
2013-09-20 17:09 ` Ian Campbell
2013-09-20 17:16 ` Ian Campbell
2013-09-19 13:36 ` Tim Deegan
2013-09-17 1:40 ` [PATCH RFC 6/7] xen: arm: configure TCR_EL2 for 40 bit physical address space Ian Campbell
2013-09-18 15:50 ` Julien Grall
2013-09-19 13:42 ` Tim Deegan
2013-09-17 1:40 ` [PATCH RFC 7/7] xen: arm: split cpu0's domheap mapping PTs out from xen_second Ian Campbell
2013-09-19 13:47 ` Tim Deegan
2013-09-17 11:34 ` [PATCH RFC 0/N] xen: arm: rework early bring up Julien Grall
2013-09-17 12:43 ` Ian Campbell
2013-09-18 13:40 ` Julien Grall
2013-09-18 17:33 ` Julien Grall
2013-09-18 19:22 ` Ian Campbell
2013-09-18 19:24 ` Ian Campbell
2013-09-18 20:00 ` Julien Grall
2013-09-18 20:22 ` Ian Campbell
2013-09-18 21:14 ` Julien Grall
2013-09-18 21:28 ` Ian Campbell
2013-09-19 14:49 ` Julien Grall
2013-09-19 15:51 ` Ian Campbell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=523880CC.7020703@linaro.org \
--to=julien.grall@linaro.org \
--cc=ian.campbell@citrix.com \
--cc=julien.grall@citrix.com \
--cc=stefano.stabellini@eu.citrix.com \
--cc=tim@xen.org \
--cc=xen-devel@lists.xen.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).