Hi, The following reworks early bring up on ARM to use a separate set of boot pagetables. This simplifies things by avoiding the need to bring up all CPUs in lock step, which in turn allows us to do secondary CPU bringup in C code. Unfortunately the main bulk of this change is a single large patch which is hard to decompose any further since it is basically pulling on the thread and then knitting a new jumper from it. With these changes Xen now absolutely requires that the bootloader calls the hypervisor in HYP mode, the previous workarounds have been removed. For use on models a bootwrapper is now required. See git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 I have implemented support for CPU bringup on the fastmodel vexpress platforms (v7and v8) here, I suppose it should work OK on a real vexpress too but I''ve not tried it. I''m hoping that those of you with access to other platforms will implement the required cpu_up platform hook, it should be pretty simple in each case, I think. It should now also be possible to implement PSCI, but I have not done so. Ian
We need to be able to use a 1:1 mapping during bring up. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/setup.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index 4b31623..d0220d9 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -258,6 +258,14 @@ static paddr_t __init get_xen_paddr(void) if ( !e ) continue; +#ifdef CONFIG_ARM_32 + /* Xen must be under 4GB */ + if ( e > 0x100000000ULL ) + e = 0x100000000ULL; + if ( e < bank->start ) + continue; +#endif + s = e - min_size; if ( s > paddr ) -- 1.8.3.2
Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index d0220d9..e58dbc6 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -83,8 +83,8 @@ static void __init processor_id(void) printk("Huh, cpu architecture %x, expected 0xf (defined by cpuid)\n", c->midr.architecture); - printk("Processor: \"%s\", variant: 0x%x, part 0x%03x, rev 0x%x\n", - implementer, c->midr.variant, c->midr.part_number, c->midr.revision); + printk("Processor: %08"PRIx32": \"%s\", variant: 0x%x, part 0x%03x, rev 0x%x\n", + c->midr.bits, implementer, c->midr.variant, c->midr.part_number, c->midr.revision); #if defined(CONFIG_ARM_64) printk("64-bit Execution:\n"); -- 1.8.3.2
Ian Campbell
2013-Sep-17 01:40 UTC
[PATCH RFC 3/7] xen: arm: make sure we stay within the memory bank during mm setup
Otherwise if there is a module in another bank we can run off the end. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/setup.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index e58dbc6..94b1362 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -223,8 +223,10 @@ static paddr_t __init next_module(paddr_t s, paddr_t *n) continue; if ( mod_s > lowest ) continue; + if ( mod_s > *n ) + continue; lowest = mod_s; - *n = mod_e; + *n = min(*n, mod_e); } return lowest; } @@ -450,6 +452,9 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) e = n = bank_end; } + if ( e > bank_end ) + e = bank_end; + setup_xenheap_mappings(s>>PAGE_SHIFT, (e-s)>>PAGE_SHIFT); xenheap_mfn_end = e; -- 1.8.3.2
Ian Campbell
2013-Sep-17 01:40 UTC
[PATCH RFC 4/7] xen: arm: add two new device tree helpers
- dt_property_read_u64 - dt_find_node_by_type Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/common/device_tree.c | 29 +++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 16 ++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 3a3c99c..74a82bc 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -589,6 +589,21 @@ bool_t dt_property_read_u32(const struct dt_device_node *np, return 1; } +bool_t dt_property_read_u64(const struct dt_device_node *np, + const char *name, u64 *out_value) +{ + u32 len; + const __be32 *val; + + val = dt_get_property(np, name, &len); + if ( !val || len < sizeof(*out_value) ) + return 0; + + *out_value = dt_read_number(val, 2); + + return 1; +} + bool_t dt_device_is_compatible(const struct dt_device_node *device, const char *compat) { @@ -637,6 +652,20 @@ struct dt_device_node *dt_find_node_by_name(struct dt_device_node *from, return np; } +struct dt_device_node *dt_find_node_by_type(struct dt_device_node *from, + const char *type) +{ + struct dt_device_node *np; + struct dt_device_node *dt; + + dt = from ? from->allnext : dt_host; + for_each_device_node(dt, np) + if ( np->type && (dt_node_cmp(np->type, type) == 0) ) + break; + + return np; +} + struct dt_device_node *dt_find_node_by_path(const char *path) { struct dt_device_node *np; diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 402cef2..3aa8452 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -315,6 +315,16 @@ const void *dt_get_property(const struct dt_device_node *np, */ bool_t dt_property_read_u32(const struct dt_device_node *np, const char *name, u32 *out_value); +/** + * dt_property_read_u64 - Helper to read a u64 property. + * @np: node to get the value + * @name: name of the property + * @out_value: pointer to return value + * + * Return true if get the desired value. + */ +bool_t dt_property_read_u64(const struct dt_device_node *np, + const char *name, u64 *out_value); /** * Checks if the given "compat" string matches one of the strings in @@ -347,6 +357,12 @@ struct dt_device_node *dt_find_node_by_name(struct dt_device_node *node, const char *name); /** + * dt_find_node_by_name - Find a node by its "name" property + */ +struct dt_device_node *dt_find_node_by_type(struct dt_device_node *from, + const char *type); + +/** * df_find_node_by_alias - Find a node matching an alias * @alias: The alias to match * -- 1.8.3.2
Ian Campbell
2013-Sep-17 01:40 UTC
[PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
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 */ + + 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 */ + +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) */ + mov r5, #0 /* r4:r5 is paddr (xen_pagetable) */ + 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 */ 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 + * 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) */ + + 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 */ + 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); + 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 -- 1.8.3.2
Ian Campbell
2013-Sep-17 01:40 UTC
[PATCH RFC 6/7] xen: arm: configure TCR_EL2 for 40 bit physical address space
Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/arm64/head.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S index 6406562..59cbcd8 100644 --- a/xen/arch/arm/arm64/head.S +++ b/xen/arch/arm/arm64/head.S @@ -200,12 +200,12 @@ skip_bss: msr mair_el2, x0 /* Set up the HTCR: - * PASize -- 4G + * PASize -- 40 bits / 1TB * Top byte is used * PT walks use Outer-Shareable accesses, * PT walks are write-back, write-allocate in both cache levels, * Full 64-bit address space goes through this table. */ - ldr x0, =0x80802500 + ldr x0, =0x80822500 msr tcr_el2, x0 /* Set up the SCTLR_EL2: -- 1.8.3.2
Ian Campbell
2013-Sep-17 01:40 UTC
[PATCH RFC 7/7] xen: arm: split cpu0''s domheap mapping PTs out from xen_second
Now that bringup has been rewritten we don''t need these 4 contiguous pages for the 1:1 map. So split them out and only allocate them for 32 bit Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/mm.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c index efac619..984c201 100644 --- a/xen/arch/arm/mm.c +++ b/xen/arch/arm/mm.c @@ -94,8 +94,11 @@ static DEFINE_PER_CPU(lpae_t *, xen_pgtable); * 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 */ +/* Root of the trie for cpu0, other CPU''s PTs are dynamically allocated */ lpae_t cpu0_pgtable[LPAE_ENTRIES] __attribute__((__aligned__(4096))); +/* cpu0''s domheap page tables */ +lpae_t cpu0_dommap[LPAE_ENTRIES*DOMHEAP_SECOND_PAGES] + __attribute__((__aligned__(4096*DOMHEAP_SECOND_PAGES))); #endif #ifdef CONFIG_ARM_64 @@ -115,19 +118,8 @@ static __initdata int xenheap_first_first_slot = -1; * The second-level table is 2 contiguous pages long, and covers all * addresses from 0 to 0x7fffffff. Offsets into it are calculated * with second_linear_offset(), not second_table_offset(). - * - * On 32bit addresses 0x80000000 to 0xffffffff are covered by the - * per-cpu xen_domheap mappings described above. We allocate 4 pages - * here for use in the boot page tables and the second two pages - * become the boot CPUs xen_dommap pages. - * - * On 64bit addresses 0x80000000 to 0xffffffff are unused. However we - * allocate 4 pages here for use while relocating Xen, which currently - * expects a second level page to exist for all addresses in the first - * 4GB. We need to keep these extra mappings in place for seconary CPU - * bring up too. For now we just leave them forever. */ -lpae_t xen_second[LPAE_ENTRIES*4] __attribute__((__aligned__(4096*4))); +lpae_t xen_second[LPAE_ENTRIES*2] __attribute__((__aligned__(4096*2))); /* First level page table used for fixmap */ lpae_t xen_fixmap[LPAE_ENTRIES] __attribute__((__aligned__(4096))); /* First level page table used to map Xen itself with the XN bit set @@ -428,13 +420,22 @@ void __init setup_pagetables(unsigned long boot_phys_offset, paddr_t xen_paddr) #endif /* Initialise first level entries, to point to second level entries */ - for ( i = 0; i < 4; i++) + for ( i = 0; i < 2; i++) { p[i] = pte_of_xenaddr((uintptr_t)(xen_second+i*LPAE_ENTRIES)); p[i].pt.table = 1; p[i].pt.xn = 0; } +#ifdef CONFIG_ARM_32 + for ( i = 0; i < DOMHEAP_SECOND_PAGES; i++ ) + { + p[first_table_offset(DOMHEAP_VIRT_START+i*FIRST_SIZE)] + = pte_of_xenaddr((uintptr_t)(cpu0_dommap+i*LPAE_ENTRIES)); + p[first_table_offset(DOMHEAP_VIRT_START+i*FIRST_SIZE)].pt.table = 1; + } +#endif + /* Initialise xen second level entries ... */ /* ... Xen''s text etc */ @@ -497,11 +498,9 @@ void __init setup_pagetables(unsigned long boot_phys_offset, paddr_t xen_paddr) #ifdef CONFIG_ARM_32 per_cpu(xen_pgtable, 0) = cpu0_pgtable; - per_cpu(xen_dommap, 0) = xen_second + - second_linear_offset(DOMHEAP_VIRT_START); + per_cpu(xen_dommap, 0) = cpu0_dommap; - /* Some of these slots may have been used during start of day and/or - * relocation. Make sure they are clear now. */ + /* Make sure it is clear */ memset(this_cpu(xen_dommap), 0, DOMHEAP_SECOND_PAGES*PAGE_SIZE); flush_xen_dcache_va_range(this_cpu(xen_dommap), DOMHEAP_SECOND_PAGES*PAGE_SIZE); -- 1.8.3.2
Adding Andre, On 09/17/2013 02:37 AM, Ian Campbell wrote:> Hi,Hi,> The following reworks early bring up on ARM to use a separate set of > boot pagetables. This simplifies things by avoiding the need to bring up > all CPUs in lock step, which in turn allows us to do secondary CPU > bringup in C code.Great ! I will give a try on different boards and see what happens.> Unfortunately the main bulk of this change is a single large patch which > is hard to decompose any further since it is basically pulling on the > thread and then knitting a new jumper from it.I think you can split the patch in: - Add the new platform callback - Fast model SMP code - ... We will have dead code for "few" commit in Xen, but it will be easier to read the patch series :).> With these changes Xen now absolutely requires that the bootloader calls > the hypervisor in HYP mode, the previous workarounds have been removed. > For use on models a bootwrapper is now required. See > git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 > git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 > > I have implemented support for CPU bringup on the fastmodel vexpress > platforms (v7and v8) here, I suppose it should work OK on a real > vexpress too but I''ve not tried it.Unfortunately on the versatile express there is 2 different ways to bring up CPUs. We can stick to this CPU bring up, as long as we ask the user to modify the board configuration.> I''m hoping that those of you with access to other platforms will > implement the required cpu_up platform hook, it should be pretty simple > in each case, I think. > > It should now also be possible to implement PSCI, but I have not done > so. > > Ian > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel >-- Julien Grall
Julien Grall
2013-Sep-17 12:05 UTC
Re: [PATCH RFC 2/7] xen: arm: Log the raw MIDR on boot.
On 09/17/2013 02:40 AM, Ian Campbell wrote:> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Julien Grall <julien.grall@linaro.org>> --- > xen/arch/arm/setup.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > index d0220d9..e58dbc6 100644 > --- a/xen/arch/arm/setup.c > +++ b/xen/arch/arm/setup.c > @@ -83,8 +83,8 @@ static void __init processor_id(void) > printk("Huh, cpu architecture %x, expected 0xf (defined by cpuid)\n", > c->midr.architecture); > > - printk("Processor: \"%s\", variant: 0x%x, part 0x%03x, rev 0x%x\n", > - implementer, c->midr.variant, c->midr.part_number, c->midr.revision); > + printk("Processor: %08"PRIx32": \"%s\", variant: 0x%x, part 0x%03x, rev 0x%x\n", > + c->midr.bits, implementer, c->midr.variant, c->midr.part_number, c->midr.revision); > > #if defined(CONFIG_ARM_64) > printk("64-bit Execution:\n"); >-- Julien Grall
Julien Grall
2013-Sep-17 12:19 UTC
Re: [PATCH RFC 3/7] xen: arm: make sure we stay within the memory bank during mm setup
On 09/17/2013 02:40 AM, Ian Campbell wrote:> Otherwise if there is a module in another bank we can run off the end. > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > --- > xen/arch/arm/setup.c | 7 ++++++- > 1 file changed, 6 insertions(+), 1 deletion(-) > > diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > index e58dbc6..94b1362 100644 > --- a/xen/arch/arm/setup.c > +++ b/xen/arch/arm/setup.c > @@ -223,8 +223,10 @@ static paddr_t __init next_module(paddr_t s, paddr_t *n) > continue; > if ( mod_s > lowest ) > continue; > + if ( mod_s > *n )I needed to look at the call-site to know the meaning of "n". Can you add a comment above the function to specify that n contains the end of the bank/RAM?> + continue; > lowest = mod_s; > - *n = mod_e; > + *n = min(*n, mod_e); > } > return lowest; > } > @@ -450,6 +452,9 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) > e = n = bank_end; > } > > + if ( e > bank_end ) > + e = bank_end; > + > setup_xenheap_mappings(s>>PAGE_SHIFT, (e-s)>>PAGE_SHIFT); > > xenheap_mfn_end = e; >-- Julien Grall
On Tue, 2013-09-17 at 12:34 +0100, Julien Grall wrote:> Adding Andre,Thanks, I meant to and forgot...> On 09/17/2013 02:37 AM, Ian Campbell wrote: > > Hi, > > Hi, > > > The following reworks early bring up on ARM to use a separate set of > > boot pagetables. This simplifies things by avoiding the need to bring up > > all CPUs in lock step, which in turn allows us to do secondary CPU > > bringup in C code. > > Great ! I will give a try on different boards and see what happens.Thanks.> > Unfortunately the main bulk of this change is a single large patch which > > is hard to decompose any further since it is basically pulling on the > > thread and then knitting a new jumper from it. > > I think you can split the patch in: > - Add the new platform callback > - Fast model SMP code > - ... > > We will have dead code for "few" commit in Xen, but it will be easier to > read the patch series :).yes, that''s a good idea. The main patch will still be massive though.> > With these changes Xen now absolutely requires that the bootloader calls > > the hypervisor in HYP mode, the previous workarounds have been removed. > > For use on models a bootwrapper is now required. See > > git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 > > git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 > > > > I have implemented support for CPU bringup on the fastmodel vexpress > > platforms (v7and v8) here, I suppose it should work OK on a real > > vexpress too but I''ve not tried it. > > Unfortunately on the versatile express there is 2 different ways to > bring up CPUs. > We can stick to this CPU bring up, as long as we ask the user to modify > the board configuration.Is it possible to determine programaticaly which method to use? In any case this series isn''t changing anything in this regard, so we must already be asking users to modify the boards configuration. Ian.
Julien Grall
2013-Sep-17 13:05 UTC
Re: [PATCH RFC 4/7] xen: arm: add two new device tree helpers
On 09/17/2013 02:40 AM, Ian Campbell wrote:> - dt_property_read_u64 > - dt_find_node_by_type > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > --- > xen/common/device_tree.c | 29 +++++++++++++++++++++++++++++ > xen/include/xen/device_tree.h | 16 ++++++++++++++++ > 2 files changed, 45 insertions(+) > > diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c > index 3a3c99c..74a82bc 100644 > --- a/xen/common/device_tree.c > +++ b/xen/common/device_tree.c > @@ -589,6 +589,21 @@ bool_t dt_property_read_u32(const struct dt_device_node *np, > return 1; > } > > +bool_t dt_property_read_u64(const struct dt_device_node *np, > + const char *name, u64 *out_value) > +{ > + u32 len; > + const __be32 *val; > + > + val = dt_get_property(np, name, &len); > + if ( !val || len < sizeof(*out_value) ) > + return 0; > + > + *out_value = dt_read_number(val, 2); > + > + return 1; > +} > + > bool_t dt_device_is_compatible(const struct dt_device_node *device, > const char *compat) > { > @@ -637,6 +652,20 @@ struct dt_device_node *dt_find_node_by_name(struct dt_device_node *from, > return np; > } > > +struct dt_device_node *dt_find_node_by_type(struct dt_device_node *from, > + const char *type) > +{ > + struct dt_device_node *np; > + struct dt_device_node *dt; > + > + dt = from ? from->allnext : dt_host; > + for_each_device_node(dt, np) > + if ( np->type && (dt_node_cmp(np->type, type) == 0) ) > + break; > + > + return np; > +} > + > struct dt_device_node *dt_find_node_by_path(const char *path) > { > struct dt_device_node *np; > diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h > index 402cef2..3aa8452 100644 > --- a/xen/include/xen/device_tree.h > +++ b/xen/include/xen/device_tree.h > @@ -315,6 +315,16 @@ const void *dt_get_property(const struct dt_device_node *np, > */ > bool_t dt_property_read_u32(const struct dt_device_node *np, > const char *name, u32 *out_value); > +/** > + * dt_property_read_u64 - Helper to read a u64 property. > + * @np: node to get the value > + * @name: name of the property > + * @out_value: pointer to return value > + * > + * Return true if get the desired value. > + */ > +bool_t dt_property_read_u64(const struct dt_device_node *np, > + const char *name, u64 *out_value); > > /** > * Checks if the given "compat" string matches one of the strings in > @@ -347,6 +357,12 @@ struct dt_device_node *dt_find_node_by_name(struct dt_device_node *node, > const char *name); > > /** > + * dt_find_node_by_name - Find a node by its "name" propertydt_find_node_by_type - Find a node by its "device_type" property Except this typo, Acked-by: Julien Grall <julien.grall@linaro.org>> + */ > +struct dt_device_node *dt_find_node_by_type(struct dt_device_node *from, > + const char *type); > + > +/** > * df_find_node_by_alias - Find a node matching an alias > * @alias: The alias to match > * >-- Julien Grall
Julien Grall
2013-Sep-17 16:18 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
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_secondSame 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
Ian Campbell
2013-Sep-17 16:36 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
On Tue, 2013-09-17 at 17:18 +0100, Julien Grall wrote:> > -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?I think I do. r12 == 0 on the boot and == 1 on secondaries.> > > + > > + 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.Right, and twice again the 64-bit version ;-)> > + /* 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.Ack.> > > + 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/?Yep.> > + /* 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?It''s covered by the overall description of the boot tables layout which is in mm.c and referenced elsewhere in this file. Is the suficient? [..]> > 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.I wondered if there might be platforms with differeing mbox addresses for different CPU. e.g. the armv8 stuff (which doesn''t use this path) makes provisions for this. But I''ll make the suggested change -- we can also refactor or add a second callback if such a platform shows up. You didn''t trim your quotes, I hope I didn''t miss any comments (I trimmed a bunch of the s/xen_/boot_/ ones... Will do a thorough sweep...) Ian.
Julien Grall
2013-Sep-17 16:55 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
On 09/17/2013 05:36 PM, Ian Campbell wrote:> On Tue, 2013-09-17 at 17:18 +0100, Julien Grall wrote: >>> + /* 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? > > It''s covered by the overall description of the boot tables layout which > is in mm.c and referenced elsewhere in this file. Is the suficient?I just saw the comment, I''m fine with it. It took me several minutes to find where :).> [..] >>> 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. > > I wondered if there might be platforms with differeing mbox addresses > for different CPU. e.g. the armv8 stuff (which doesn''t use this path) > makes provisions for this.I believe, it''s the case on midway. Andre, can you confirm? But, I think this code can be merge in cpu_up.> > But I''ll make the suggested change -- we can also refactor or add a > second callback if such a platform shows up. > > You didn''t trim your quotes, I hope I didn''t miss any comments (I > trimmed a bunch of the s/xen_/boot_/ ones... Will do a thorough > sweep...)You didn''t miss any comments, next time I will trim my quotes. -- Julien Grall
Andre Przywara
2013-Sep-17 18:30 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
On 09/17/2013 06:55 PM, Julien Grall wrote:> On 09/17/2013 05:36 PM, Ian Campbell wrote: >> On Tue, 2013-09-17 at 17:18 +0100, Julien Grall wrote: >>>> + /* 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? >> >> It''s covered by the overall description of the boot tables layout which >> is in mm.c and referenced elsewhere in this file. Is the suficient? > > I just saw the comment, I''m fine with it. It took me several minutes to > find where :). > >> [..] >>>> 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. >> >> I wondered if there might be platforms with differeing mbox addresses >> for different CPU. e.g. the armv8 stuff (which doesn''t use this path) >> makes provisions for this. > > I believe, it''s the case on midway. Andre, can you confirm?Yes, it is: 0x40 + cpunr * 0x10 This only matters if you use the native way of SMP booting, but actually on Midway you should be using PSCI (which is already supported by the firmware). So if PSCI support is just around the corner, this should be OK for the time being. Regards, Andre.> But, I think this code can be merge in cpu_up. > >> >> But I''ll make the suggested change -- we can also refactor or add a >> second callback if such a platform shows up. >> >> You didn''t trim your quotes, I hope I didn''t miss any comments (I >> trimmed a bunch of the s/xen_/boot_/ ones... Will do a thorough >> sweep...) > > You didn''t miss any comments, next time I will trim my quotes. >
Ian Campbell
2013-Sep-17 19:19 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
On Tue, 2013-09-17 at 20:30 +0200, Andre Przywara wrote:> Yes, it is: 0x40 + cpunr * 0x10 > This only matters if you use the native way of SMP booting, but actually > on Midway you should be using PSCI (which is already supported by the > firmware). > So if PSCI support is just around the corner, this should be OK for the > time being.For values of "around the corner" of "there shouldn''t be any blockers now" ;-) I think PSCI support ought to be pretty easy off the back of this series, but TBH I''ve not really thought about it that hard... Ian.
On 09/17/2013 01:43 PM, Ian Campbell wrote:> On Tue, 2013-09-17 at 12:34 +0100, Julien Grall wrote: >> Adding Andre, > > Thanks, I meant to and forgot... > >> On 09/17/2013 02:37 AM, Ian Campbell wrote: >>> Hi, >> >> Hi, >> >>> The following reworks early bring up on ARM to use a separate set of >>> boot pagetables. This simplifies things by avoiding the need to bring up >>> all CPUs in lock step, which in turn allows us to do secondary CPU >>> bringup in C code. >> >> Great ! I will give a try on different boards and see what happens. > > Thanks. > >>> Unfortunately the main bulk of this change is a single large patch which >>> is hard to decompose any further since it is basically pulling on the >>> thread and then knitting a new jumper from it. >> >> I think you can split the patch in: >> - Add the new platform callback >> - Fast model SMP code >> - ... >> >> We will have dead code for "few" commit in Xen, but it will be easier to >> read the patch series :). > > yes, that''s a good idea. The main patch will still be massive though. > >>> With these changes Xen now absolutely requires that the bootloader calls >>> the hypervisor in HYP mode, the previous workarounds have been removed. >>> For use on models a bootwrapper is now required. See >>> git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 >>> git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 >>> >>> I have implemented support for CPU bringup on the fastmodel vexpress >>> platforms (v7and v8) here, I suppose it should work OK on a real >>> vexpress too but I''ve not tried it. >> >> Unfortunately on the versatile express there is 2 different ways to >> bring up CPUs. >> We can stick to this CPU bring up, as long as we ask the user to modify >> the board configuration. > > Is it possible to determine programaticaly which method to use?It seems no, I will take a closer look.> In any case this series isn''t changing anything in this regard, so we > must already be asking users to modify the boards configuration.-- Julien Grall
Julien Grall
2013-Sep-18 13:57 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
On 09/17/2013 02:40 AM, Ian Campbell wrote:> 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);The device should contains a node with compatible "arm,vexpress-sysreg". Can you use this node instead of hardcoding value?> + 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 > +-- Julien Grall
Ian Campbell
2013-Sep-18 15:12 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
On Wed, 2013-09-18 at 14:57 +0100, Julien Grall wrote:> > +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); > > The device should contains a node with compatible "arm,vexpress-sysreg". > Can you use this node instead of hardcoding value?It doesn''t seem to be in the dts''s which are designed for use with the fast-models (git://linux-arm.org/arm-dts.git). In any case this code is already conditional on running on a vexpress platform. Making the vexpress support more complete/dynamic is a nice to have but not really a blocker IMHO. Ian.
Julien Grall
2013-Sep-18 15:44 UTC
Re: [PATCH RFC 1/7] xen: arm: Load xen under 4GB on 32-bit
On 09/17/2013 02:40 AM, Ian Campbell wrote:> We need to be able to use a 1:1 mapping during bring up. > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Julien Grall <julien.grall@linaro.org>> --- > xen/arch/arm/setup.c | 8 ++++++++ > 1 file changed, 8 insertions(+) > > diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > index 4b31623..d0220d9 100644 > --- a/xen/arch/arm/setup.c > +++ b/xen/arch/arm/setup.c > @@ -258,6 +258,14 @@ static paddr_t __init get_xen_paddr(void) > if ( !e ) > continue; > > +#ifdef CONFIG_ARM_32 > + /* Xen must be under 4GB */ > + if ( e > 0x100000000ULL ) > + e = 0x100000000ULL; > + if ( e < bank->start ) > + continue; > +#endif > + > s = e - min_size; > > if ( s > paddr ) >-- Julien Grall
Julien Grall
2013-Sep-18 15:50 UTC
Re: [PATCH RFC 6/7] xen: arm: configure TCR_EL2 for 40 bit physical address space
On 09/17/2013 02:40 AM, Ian Campbell wrote:> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Julien Grall <julien.grall@linaro.org>> --- > xen/arch/arm/arm64/head.S | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S > index 6406562..59cbcd8 100644 > --- a/xen/arch/arm/arm64/head.S > +++ b/xen/arch/arm/arm64/head.S > @@ -200,12 +200,12 @@ skip_bss: > msr mair_el2, x0 > > /* Set up the HTCR: > - * PASize -- 4G > + * PASize -- 40 bits / 1TB > * Top byte is used > * PT walks use Outer-Shareable accesses, > * PT walks are write-back, write-allocate in both cache levels, > * Full 64-bit address space goes through this table. */ > - ldr x0, =0x80802500 > + ldr x0, =0x80822500 > msr tcr_el2, x0 > > /* Set up the SCTLR_EL2: >-- Julien Grall
Julien Grall
2013-Sep-18 17:06 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
On 09/17/2013 02:40 AM, Ian Campbell wrote:> 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 @@[..]> + > +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 */Can you use #(~MPIDR_HWID_MASK) instead of #(0xff << 24)? I think, it''s the same in arm64/head.S. -- Julien Grall
Julien Grall
2013-Sep-18 17:11 UTC
Re: [PATCH RFC 4/7] xen: arm: add two new device tree helpers
On 09/17/2013 02:40 AM, Ian Campbell wrote:> - dt_property_read_u64 > - dt_find_node_by_type > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > --- > xen/common/device_tree.c | 29 +++++++++++++++++++++++++++++ > xen/include/xen/device_tree.h | 16 ++++++++++++++++ > 2 files changed, 45 insertions(+) > > diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c > index 3a3c99c..74a82bc 100644 > --- a/xen/common/device_tree.c > +++ b/xen/common/device_tree.c > @@ -589,6 +589,21 @@ bool_t dt_property_read_u32(const struct dt_device_node *np, > return 1; > } > > +bool_t dt_property_read_u64(const struct dt_device_node *np, > + const char *name, u64 *out_value) > +{ > + u32 len; > + const __be32 *val; > + > + val = dt_get_property(np, name, &len); > + if ( !val || len < sizeof(*out_value) ) > + return 0; > + > + *out_value = dt_read_number(val, 2); > + > + return 1; > +} > + > bool_t dt_device_is_compatible(const struct dt_device_node *device, > const char *compat) > { > @@ -637,6 +652,20 @@ struct dt_device_node *dt_find_node_by_name(struct dt_device_node *from, > return np; > } > > +struct dt_device_node *dt_find_node_by_type(struct dt_device_node *from, > + const char *type) > +{ > + struct dt_device_node *np; > + struct dt_device_node *dt; > + > + dt = from ? from->allnext : dt_host; > + for_each_device_node(dt, np)Minor mistake, for_each_device_node was renamed to dt_for_each_device_node in the current xen tree.> + if ( np->type && (dt_node_cmp(np->type, type) == 0) ) > + break; > + > + return np; > +} > + > struct dt_device_node *dt_find_node_by_path(const char *path) > { > struct dt_device_node *np; > diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h > index 402cef2..3aa8452 100644 > --- a/xen/include/xen/device_tree.h > +++ b/xen/include/xen/device_tree.h > @@ -315,6 +315,16 @@ const void *dt_get_property(const struct dt_device_node *np, > */ > bool_t dt_property_read_u32(const struct dt_device_node *np, > const char *name, u32 *out_value); > +/** > + * dt_property_read_u64 - Helper to read a u64 property. > + * @np: node to get the value > + * @name: name of the property > + * @out_value: pointer to return value > + * > + * Return true if get the desired value. > + */ > +bool_t dt_property_read_u64(const struct dt_device_node *np, > + const char *name, u64 *out_value); > > /** > * Checks if the given "compat" string matches one of the strings in > @@ -347,6 +357,12 @@ struct dt_device_node *dt_find_node_by_name(struct dt_device_node *node, > const char *name); > > /** > + * dt_find_node_by_name - Find a node by its "name" property > + */ > +struct dt_device_node *dt_find_node_by_type(struct dt_device_node *from, > + const char *type); > + > +/** > * df_find_node_by_alias - Find a node matching an alias > * @alias: The alias to match > * >-- Julien Grall
Ian Campbell
2013-Sep-18 17:14 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
On Wed, 2013-09-18 at 18:06 +0100, Julien Grall wrote:> On 09/17/2013 02:40 AM, Ian Campbell wrote: > > > 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 @@ > > [..] > > > + > > +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 */ > > Can you use #(~MPIDR_HWID_MASK) instead of #(0xff << 24)? > I think, it''s the same in arm64/head.S.Yes, I''ve got that change locally already.
Ian Campbell
2013-Sep-18 17:14 UTC
Re: [PATCH RFC 4/7] xen: arm: add two new device tree helpers
On Wed, 2013-09-18 at 18:11 +0100, Julien Grall wrote:> On 09/17/2013 02:40 AM, Ian Campbell wrote: > > - dt_property_read_u64 > > - dt_find_node_by_type > > > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > > --- > > xen/common/device_tree.c | 29 +++++++++++++++++++++++++++++ > > xen/include/xen/device_tree.h | 16 ++++++++++++++++ > > 2 files changed, 45 insertions(+) > > > > diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c > > index 3a3c99c..74a82bc 100644 > > --- a/xen/common/device_tree.c > > +++ b/xen/common/device_tree.c > > @@ -589,6 +589,21 @@ bool_t dt_property_read_u32(const struct dt_device_node *np, > > return 1; > > } > > > > +bool_t dt_property_read_u64(const struct dt_device_node *np, > > + const char *name, u64 *out_value) > > +{ > > + u32 len; > > + const __be32 *val; > > + > > + val = dt_get_property(np, name, &len); > > + if ( !val || len < sizeof(*out_value) ) > > + return 0; > > + > > + *out_value = dt_read_number(val, 2); > > + > > + return 1; > > +} > > + > > bool_t dt_device_is_compatible(const struct dt_device_node *device, > > const char *compat) > > { > > @@ -637,6 +652,20 @@ struct dt_device_node *dt_find_node_by_name(struct dt_device_node *from, > > return np; > > } > > > > +struct dt_device_node *dt_find_node_by_type(struct dt_device_node *from, > > + const char *type) > > +{ > > + struct dt_device_node *np; > > + struct dt_device_node *dt; > > + > > + dt = from ? from->allnext : dt_host; > > + for_each_device_node(dt, np) > > Minor mistake, for_each_device_node was renamed to > dt_for_each_device_node in the current xen tree.Ack, I caught this while rebasing too, thanks though.
On 09/17/2013 02:37 AM, Ian Campbell wrote:> Hi, > > The following reworks early bring up on ARM to use a separate set of > boot pagetables. This simplifies things by avoiding the need to bring up > all CPUs in lock step, which in turn allows us to do secondary CPU > bringup in C code. > > Unfortunately the main bulk of this change is a single large patch which > is hard to decompose any further since it is basically pulling on the > thread and then knitting a new jumper from it. > > With these changes Xen now absolutely requires that the bootloader calls > the hypervisor in HYP mode, the previous workarounds have been removed. > For use on models a bootwrapper is now required. See > git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 > git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 > > I have implemented support for CPU bringup on the fastmodel vexpress > platforms (v7and v8) here, I suppose it should work OK on a real > vexpress too but I''ve not tried it.I have just tried the patch series on the versatile express and it doesn''t work. I''m using the u-boot from Andre and all the cpus already boot in hyp mode (checked without this patch series). Xen log here: http://pastebin.com/eJ21dqRm Andre, do you know if we need a specific kick cpus for the versatile express and your hyp mode patch series? -- Julien Grall
On Wed, 2013-09-18 at 18:33 +0100, Julien Grall wrote:> On 09/17/2013 02:37 AM, Ian Campbell wrote: > > Hi, > > > > The following reworks early bring up on ARM to use a separate set of > > boot pagetables. This simplifies things by avoiding the need to bring up > > all CPUs in lock step, which in turn allows us to do secondary CPU > > bringup in C code. > > > > Unfortunately the main bulk of this change is a single large patch which > > is hard to decompose any further since it is basically pulling on the > > thread and then knitting a new jumper from it. > > > > With these changes Xen now absolutely requires that the bootloader calls > > the hypervisor in HYP mode, the previous workarounds have been removed. > > For use on models a bootwrapper is now required. See > > git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 > > git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 > > > > I have implemented support for CPU bringup on the fastmodel vexpress > > platforms (v7and v8) here, I suppose it should work OK on a real > > vexpress too but I''ve not tried it. > > I have just tried the patch series on the versatile express and it > doesn''t work. I''m using the u-boot from Andre and all the cpus already > boot in hyp mode (checked without this patch series).:-( The code should essentially the same as the old kick cpus, but reimplemented in C. The only difference I can spot is that the C version is kicking a single CPU at a time while the ASM version is kicking everyone at once. Does using send_SGI_allbutself instead work as a hack? Perhaps our idea of the CPUID is wrong or something? Your patches to fixup the logical CPU id stuff might help? Ian.
On Wed, 2013-09-18 at 20:22 +0100, Ian Campbell wrote:> On Wed, 2013-09-18 at 18:33 +0100, Julien Grall wrote: > > On 09/17/2013 02:37 AM, Ian Campbell wrote: > > > Hi, > > > > > > The following reworks early bring up on ARM to use a separate set of > > > boot pagetables. This simplifies things by avoiding the need to bring up > > > all CPUs in lock step, which in turn allows us to do secondary CPU > > > bringup in C code. > > > > > > Unfortunately the main bulk of this change is a single large patch which > > > is hard to decompose any further since it is basically pulling on the > > > thread and then knitting a new jumper from it. > > > > > > With these changes Xen now absolutely requires that the bootloader calls > > > the hypervisor in HYP mode, the previous workarounds have been removed. > > > For use on models a bootwrapper is now required. See > > > git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 > > > git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 > > > > > > I have implemented support for CPU bringup on the fastmodel vexpress > > > platforms (v7and v8) here, I suppose it should work OK on a real > > > vexpress too but I''ve not tried it. > > > > I have just tried the patch series on the versatile express and it > > doesn''t work. I''m using the u-boot from Andre and all the cpus already > > boot in hyp mode (checked without this patch series). > > :-( > > The code should essentially the same as the old kick cpus, but > reimplemented in C. The only difference I can spot is that the C version > is kicking a single CPU at a time while the ASM version is kicking > everyone at once. Does using send_SGI_allbutself instead work as a hack? > > Perhaps our idea of the CPUID is wrong or something? Your patches to > fixup the logical CPU id stuff might help?You don''t happen to still have your vexpress in A7 mode do you? Ian.
On 09/18/2013 08:24 PM, Ian Campbell wrote:> On Wed, 2013-09-18 at 20:22 +0100, Ian Campbell wrote: >> On Wed, 2013-09-18 at 18:33 +0100, Julien Grall wrote: >>> On 09/17/2013 02:37 AM, Ian Campbell wrote: >>>> Hi, >>>> >>>> The following reworks early bring up on ARM to use a separate set of >>>> boot pagetables. This simplifies things by avoiding the need to bring up >>>> all CPUs in lock step, which in turn allows us to do secondary CPU >>>> bringup in C code. >>>> >>>> Unfortunately the main bulk of this change is a single large patch which >>>> is hard to decompose any further since it is basically pulling on the >>>> thread and then knitting a new jumper from it. >>>> >>>> With these changes Xen now absolutely requires that the bootloader calls >>>> the hypervisor in HYP mode, the previous workarounds have been removed. >>>> For use on models a bootwrapper is now required. See >>>> git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 >>>> git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 >>>> >>>> I have implemented support for CPU bringup on the fastmodel vexpress >>>> platforms (v7and v8) here, I suppose it should work OK on a real >>>> vexpress too but I''ve not tried it. >>> >>> I have just tried the patch series on the versatile express and it >>> doesn''t work. I''m using the u-boot from Andre and all the cpus already >>> boot in hyp mode (checked without this patch series). >> >> :-( >> >> The code should essentially the same as the old kick cpus, but >> reimplemented in C. The only difference I can spot is that the C version >> is kicking a single CPU at a time while the ASM version is kicking >> everyone at once. Does using send_SGI_allbutself instead work as a hack? >> >> Perhaps our idea of the CPUID is wrong or something? Your patches to >> fixup the logical CPU id stuff might help?I have found the issue, in send_SGI_mask we remove the offline CPUs with the following line: mask &= cpumask_bits(&cpu_online_map); As the secondary cpu (assuming we have a board with only 2 cores) is not yet online, we can''t send SGI with our code. I''m very surprised that the code works on the fast models. To solve the issue, I think we need to create another helper which will send an SGI wihout removing offline CPUs.> You don''t happen to still have your vexpress in A7 mode do you?I''m using the versatile express with only A15 processors enabled. -- Julien Grall
On Wed, 2013-09-18 at 21:00 +0100, Julien Grall wrote:> On 09/18/2013 08:24 PM, Ian Campbell wrote: > > On Wed, 2013-09-18 at 20:22 +0100, Ian Campbell wrote: > >> On Wed, 2013-09-18 at 18:33 +0100, Julien Grall wrote: > >>> On 09/17/2013 02:37 AM, Ian Campbell wrote: > >>>> Hi, > >>>> > >>>> The following reworks early bring up on ARM to use a separate set of > >>>> boot pagetables. This simplifies things by avoiding the need to bring up > >>>> all CPUs in lock step, which in turn allows us to do secondary CPU > >>>> bringup in C code. > >>>> > >>>> Unfortunately the main bulk of this change is a single large patch which > >>>> is hard to decompose any further since it is basically pulling on the > >>>> thread and then knitting a new jumper from it. > >>>> > >>>> With these changes Xen now absolutely requires that the bootloader calls > >>>> the hypervisor in HYP mode, the previous workarounds have been removed. > >>>> For use on models a bootwrapper is now required. See > >>>> git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 > >>>> git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 > >>>> > >>>> I have implemented support for CPU bringup on the fastmodel vexpress > >>>> platforms (v7and v8) here, I suppose it should work OK on a real > >>>> vexpress too but I''ve not tried it. > >>> > >>> I have just tried the patch series on the versatile express and it > >>> doesn''t work. I''m using the u-boot from Andre and all the cpus already > >>> boot in hyp mode (checked without this patch series). > >> > >> :-( > >> > >> The code should essentially the same as the old kick cpus, but > >> reimplemented in C. The only difference I can spot is that the C version > >> is kicking a single CPU at a time while the ASM version is kicking > >> everyone at once. Does using send_SGI_allbutself instead work as a hack? > >> > >> Perhaps our idea of the CPUID is wrong or something? Your patches to > >> fixup the logical CPU id stuff might help? > > I have found the issue, in send_SGI_mask we remove the offline CPUs with > the following line: > mask &= cpumask_bits(&cpu_online_map); > > As the secondary cpu (assuming we have a board with only 2 cores) is not > yet online, we can''t send SGI with our code. > I''m very surprised that the code works on the fast models.So am I, now. OK. So online mask == 0x1 and we are trying to wake mask 0x2, so the actual target list we end up using is 0... The gic manual says "When TargetListFilter is 0b00, if the CPUTargetList field is 0x00 the Distributor does not forward the interrupt to any CPU interface." (footnote to table 4-21), so it shouldn''t be waking anything... It may be a model bug> To solve the issue, I think we need to create another helper which will > send an SGI wihout removing offline CPUs.Looking briefly at the callchains leading to send_SGI_mask I don''t see any which deliberately pass an offline CPU (which would be pretty non-sensical apart from this one case). So we could perhaps just remove this check and make it the caller''s problem. Or maybe the right check is for cpu_possible mask or something similar instead of online? Ian.
On 09/18/2013 09:22 PM, Ian Campbell wrote:> On Wed, 2013-09-18 at 21:00 +0100, Julien Grall wrote: >> On 09/18/2013 08:24 PM, Ian Campbell wrote: >>> On Wed, 2013-09-18 at 20:22 +0100, Ian Campbell wrote: >>>> On Wed, 2013-09-18 at 18:33 +0100, Julien Grall wrote: >>>>> On 09/17/2013 02:37 AM, Ian Campbell wrote: >>>>>> Hi, >>>>>> >>>>>> The following reworks early bring up on ARM to use a separate set of >>>>>> boot pagetables. This simplifies things by avoiding the need to bring up >>>>>> all CPUs in lock step, which in turn allows us to do secondary CPU >>>>>> bringup in C code. >>>>>> >>>>>> Unfortunately the main bulk of this change is a single large patch which >>>>>> is hard to decompose any further since it is basically pulling on the >>>>>> thread and then knitting a new jumper from it. >>>>>> >>>>>> With these changes Xen now absolutely requires that the bootloader calls >>>>>> the hypervisor in HYP mode, the previous workarounds have been removed. >>>>>> For use on models a bootwrapper is now required. See >>>>>> git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 >>>>>> git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 >>>>>> >>>>>> I have implemented support for CPU bringup on the fastmodel vexpress >>>>>> platforms (v7and v8) here, I suppose it should work OK on a real >>>>>> vexpress too but I''ve not tried it. >>>>> >>>>> I have just tried the patch series on the versatile express and it >>>>> doesn''t work. I''m using the u-boot from Andre and all the cpus already >>>>> boot in hyp mode (checked without this patch series). >>>> >>>> :-( >>>> >>>> The code should essentially the same as the old kick cpus, but >>>> reimplemented in C. The only difference I can spot is that the C version >>>> is kicking a single CPU at a time while the ASM version is kicking >>>> everyone at once. Does using send_SGI_allbutself instead work as a hack? >>>> >>>> Perhaps our idea of the CPUID is wrong or something? Your patches to >>>> fixup the logical CPU id stuff might help? >> >> I have found the issue, in send_SGI_mask we remove the offline CPUs with >> the following line: >> mask &= cpumask_bits(&cpu_online_map); >> >> As the secondary cpu (assuming we have a board with only 2 cores) is not >> yet online, we can''t send SGI with our code. >> I''m very surprised that the code works on the fast models. > > So am I, now. > > OK. So online mask == 0x1 and we are trying to wake mask 0x2, so the > actual target list we end up using is 0... > > The gic manual says "When TargetListFilter is 0b00, if the CPUTargetList > field is 0x00 the Distributor does not forward the interrupt to any CPU > interface." (footnote to table 4-21), so it shouldn''t be waking > anything... It may be a model bug > >> To solve the issue, I think we need to create another helper which will >> send an SGI wihout removing offline CPUs. > > Looking briefly at the callchains leading to send_SGI_mask I don''t see > any which deliberately pass an offline CPU (which would be pretty > non-sensical apart from this one case). So we could perhaps just remove > this check and make it the caller''s problem. > Or maybe the right check is for cpu_possible mask or something similar > instead of online?You are right, cpu_possible mask is better. I can modify this patch http://patches.linaro.org/20437/ to add the check in gic_cpu_mask. -- Julien Grall
On Wed, 2013-09-18 at 22:14 +0100, Julien Grall wrote:> On 09/18/2013 09:22 PM, Ian Campbell wrote: > > On Wed, 2013-09-18 at 21:00 +0100, Julien Grall wrote: > >> On 09/18/2013 08:24 PM, Ian Campbell wrote: > >>> On Wed, 2013-09-18 at 20:22 +0100, Ian Campbell wrote: > >>>> On Wed, 2013-09-18 at 18:33 +0100, Julien Grall wrote: > >>>>> On 09/17/2013 02:37 AM, Ian Campbell wrote: > >>>>>> Hi, > >>>>>> > >>>>>> The following reworks early bring up on ARM to use a separate set of > >>>>>> boot pagetables. This simplifies things by avoiding the need to bring up > >>>>>> all CPUs in lock step, which in turn allows us to do secondary CPU > >>>>>> bringup in C code. > >>>>>> > >>>>>> Unfortunately the main bulk of this change is a single large patch which > >>>>>> is hard to decompose any further since it is basically pulling on the > >>>>>> thread and then knitting a new jumper from it. > >>>>>> > >>>>>> With these changes Xen now absolutely requires that the bootloader calls > >>>>>> the hypervisor in HYP mode, the previous workarounds have been removed. > >>>>>> For use on models a bootwrapper is now required. See > >>>>>> git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 > >>>>>> git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 > >>>>>> > >>>>>> I have implemented support for CPU bringup on the fastmodel vexpress > >>>>>> platforms (v7and v8) here, I suppose it should work OK on a real > >>>>>> vexpress too but I''ve not tried it. > >>>>> > >>>>> I have just tried the patch series on the versatile express and it > >>>>> doesn''t work. I''m using the u-boot from Andre and all the cpus already > >>>>> boot in hyp mode (checked without this patch series). > >>>> > >>>> :-( > >>>> > >>>> The code should essentially the same as the old kick cpus, but > >>>> reimplemented in C. The only difference I can spot is that the C version > >>>> is kicking a single CPU at a time while the ASM version is kicking > >>>> everyone at once. Does using send_SGI_allbutself instead work as a hack? > >>>> > >>>> Perhaps our idea of the CPUID is wrong or something? Your patches to > >>>> fixup the logical CPU id stuff might help? > >> > >> I have found the issue, in send_SGI_mask we remove the offline CPUs with > >> the following line: > >> mask &= cpumask_bits(&cpu_online_map); > >> > >> As the secondary cpu (assuming we have a board with only 2 cores) is not > >> yet online, we can''t send SGI with our code. > >> I''m very surprised that the code works on the fast models. > > > > So am I, now. > > > > OK. So online mask == 0x1 and we are trying to wake mask 0x2, so the > > actual target list we end up using is 0... > > > > The gic manual says "When TargetListFilter is 0b00, if the CPUTargetList > > field is 0x00 the Distributor does not forward the interrupt to any CPU > > interface." (footnote to table 4-21), so it shouldn''t be waking > > anything... It may be a model bug > > > >> To solve the issue, I think we need to create another helper which will > >> send an SGI wihout removing offline CPUs. > > > > Looking briefly at the callchains leading to send_SGI_mask I don''t see > > any which deliberately pass an offline CPU (which would be pretty > > non-sensical apart from this one case). So we could perhaps just remove > > this check and make it the caller''s problem. > > Or maybe the right check is for cpu_possible mask or something similar > > instead of online? > > You are right, cpu_possible mask is better. > I can modify this patch http://patches.linaro.org/20437/ to add the > check in gic_cpu_mask.Sounds reasonable.> >
Tim Deegan
2013-Sep-19 09:21 UTC
Re: [PATCH RFC 1/7] xen: arm: Load xen under 4GB on 32-bit
At 02:40 +0100 on 17 Sep (1379385644), Ian Campbell wrote:> We need to be able to use a 1:1 mapping during bring up. > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Tim Deegan <tim@xen.org>
At 02:40 +0100 on 17 Sep (1379385645), Ian Campbell wrote:> Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > --- > xen/arch/arm/setup.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > index d0220d9..e58dbc6 100644 > --- a/xen/arch/arm/setup.c > +++ b/xen/arch/arm/setup.c > @@ -83,8 +83,8 @@ static void __init processor_id(void) > printk("Huh, cpu architecture %x, expected 0xf (defined by cpuid)\n", > c->midr.architecture); > > - printk("Processor: \"%s\", variant: 0x%x, part 0x%03x, rev 0x%x\n", > - implementer, c->midr.variant, c->midr.part_number, c->midr.revision); > + printk("Processor: %08"PRIx32": \"%s\", variant: 0x%x, part 0x%03x, rev 0x%x\n", > + c->midr.bits, implementer, c->midr.variant, c->midr.part_number, c->midr.revision); >Introducing a long line here in the arguments. With that fixed, Acked-by: Tim Deegan <tim@xen.org> Tim
Tim Deegan
2013-Sep-19 09:27 UTC
Re: [PATCH RFC 3/7] xen: arm: make sure we stay within the memory bank during mm setup
At 13:19 +0100 on 17 Sep (1379423991), Julien Grall wrote:> On 09/17/2013 02:40 AM, Ian Campbell wrote: > >Otherwise if there is a module in another bank we can run off the end. > > > >Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > >--- > > xen/arch/arm/setup.c | 7 ++++++- > > 1 file changed, 6 insertions(+), 1 deletion(-) > > > >diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c > >index e58dbc6..94b1362 100644 > >--- a/xen/arch/arm/setup.c > >+++ b/xen/arch/arm/setup.c > >@@ -223,8 +223,10 @@ static paddr_t __init next_module(paddr_t s, paddr_t > >*n) > > continue; > > if ( mod_s > lowest ) > > continue; > >+ if ( mod_s > *n ) > > > I needed to look at the call-site to know the meaning of "n". > Can you add a comment above the function to specify that n contains the > end of the bank/RAM?+1. Also to say that the end-of-module we return is clipped if it overruns. Maybe ''n'' could be renamed ''end'' too? Tim.
Tim Deegan
2013-Sep-19 11:36 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
Hi, This looks pretty good - thanks for cleaning it all up! I''ve reviewed the asm bits below; I''ll look at the C code separately, just to break things up. At 02:40 +0100 on 17 Sep (1379385648), Ian Campbell wrote:> --- 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_cpus/!!/!/ throughout, right? In fact, why not call it is_secondary_cpu for ease of thinking? :)> +common_start: > + mov r7, #0 /* r13 := CPU ID */s/r13/r7/ in comment.> + mrc CP32(r1, MPIDR) > + tst r1, #(1<<31) /* Multiprocessor extension supported? */#MPIDR_SMP? likewise #MPIDR_SMP and #(~MPIDR_HW_MASK) below. OTOH it might be better idea to leave this almost-code-motion alone and then, once the dust settles, sweep through head.S replacing magic constants with their named equivalents.> + beq 1f > + tst r1, #(1<<30) /* Uniprocessor system? */ > + bne 1f > + bic r7, r1, #(0xff << 24) /* Mask out flags to get CPU ID */ > +1:[...]> /* console fixmap */ > #if defined(EARLY_PRINTK) > + /* Non-boot CPUs don''t need to rebuild the fixmap */ > + teq r12, #0 > + bne 1f > +While we''re shuffling things around, I think this console fixmap fettling should be moved to the end of the PT build process for consisitency. I think it belongs with the fixmap building that happens after paging is enabled Also s/rebuild/build/ in the comment?> + /* 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) */s/xen_/boot_/ in comments. There''s some more of that later on, too.> + 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 */ > 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 > + * 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) */ > + > + 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 */Isn''t this the same as the entry you already had in r2:r3 (assuming we''re loaded at a 2MB-aligned address)? You can just store it again in the other slot.> - 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. > + */Block comments elsewhere in this file don''t have the extra ''/*'' and ''*/'' lines. I guess it''s Xen style to add them, but please either both or neither. :)> + > +1: /* boot pagetable setup complete */This label belongs above the ''Defer fixmap'' comment, or else it needs a name.> -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 */ > + 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 */So, I think this is where the code to populate FIXMAP_CONSOLE ought to end up.> /* 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 syDo we need any TLB flushes here, since we''re modifying the live pagetables? I don''t recall whether the ARM MMU is guaranteed not to cache/prefetch negative results (like the x86 one is).> - PRINT("- Ready -\r\n") > +1: PRINT("- Ready -\r\n")Again, I''d prefer the label to go above (logically connected to the end of the block being skipped) to avoid the risk of someone adding new code just before ''- Ready -'' and having it be accidentally skipped.> /* 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. > + */Another mixed-style block comment. [...]> +ENTRY(relocate_xen) > + push {r4,r5,r6,r7,r8,r9,r10,r11} > + > + ldr r4, [sp, #8*4] /* Get 4th argument from stack */Long line -- that comment can be reeled in a bit.> + > + /* 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, #16Misalignment ^^^> + 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 */Can you be consistent about ''dsb sy'' vs ''dsb''? There were no ''dsb sy''s in the file to start with, so I''d be inclined to stick to plain ''dsb'' throughout (and maybe follow up adding ''sy'' throughout if you like).> + 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 */Weird alignment of comments here. I know it seems like bikeshedding, but I really do find that keeping asm code tidy makes it easier to understand. :)> + 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[...]> --- a/xen/arch/arm/arm32/mode_switch.S > +++ /dev/nullYay!> 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.SA lot of the things I commented on in the 32-bit version apply here too; I won''t repeat them here. [...]> - /* 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 */No it''s not. :) I guess it''s already like that, but this seems like it deserves a better comment. [...]> @@ -130,30 +165,18 @@ boot_cpu: > bl putn > PRINT(" -\r\n") > > - /* Are we in EL3 */ > - mrs x0, CurrentELThe PRINT() above clobbers x0, so we need to either keep that re-read of CurrentEL, or stash the value somewhere else while we print it. [...]> +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 */Wait, what? Don''t you want to reuse the 2MB map of PA(start) that you already have in x2? And x1 here is constant 0x8, not the address of anything.> + > + 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 */[...]> - /* 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 */Missing * ^^^ [...]> --- a/xen/arch/arm/arm64/mode_switch.S > +++ /dev/nullAlso yay! Tim
Tim Deegan
2013-Sep-19 13:36 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
At 02:40 +0100 on 17 Sep (1379385648), Ian Campbell wrote:> + /* 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);Does this need a cache flush? I.e., could a later eviction of these zeros race with a secondary CPU building its boot pagetables?> + /* 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);Do secondary CPUs need to switch twice? As long as they''re coming up one at a time we could set init_ttbr to each CPU''s allocated pagetables in __cpu_up(). Or can we not guarantee to bring them up one at a time? In which case, are their boot_pgtable manipulations safe against each other?> -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();You can also drop the declaration of ready_cpus above and the code to increment it in head.S (x2).> +#ifdef CONFIG_ARM_32 > +int platform_cpu_init(int cpu); > +int platform_cpu_up(int cpu);arch_cpu_{init,up} are marked __init, but platform_cpu_{init,up} are not. Is that deliberate? Cheers, Tim.
Tim Deegan
2013-Sep-19 13:42 UTC
Re: [PATCH RFC 6/7] xen: arm: configure TCR_EL2 for 40 bit physical address space
At 02:40 +0100 on 17 Sep (1379385649), Ian Campbell wrote:> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Tim Deegan <tim@xen.org>
Tim Deegan
2013-Sep-19 13:47 UTC
Re: [PATCH RFC 7/7] xen: arm: split cpu0''s domheap mapping PTs out from xen_second
At 02:40 +0100 on 17 Sep (1379385650), Ian Campbell wrote:> Now that bringup has been rewritten we don''t need these 4 contiguous pages for > the 1:1 map. So split them out and only allocate them for 32 bit > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Tim Deegan <tim@xen.org>
On 09/18/2013 10:28 PM, Ian Campbell wrote:> On Wed, 2013-09-18 at 22:14 +0100, Julien Grall wrote: >> On 09/18/2013 09:22 PM, Ian Campbell wrote: >>> On Wed, 2013-09-18 at 21:00 +0100, Julien Grall wrote: >>>> On 09/18/2013 08:24 PM, Ian Campbell wrote: >>>>> On Wed, 2013-09-18 at 20:22 +0100, Ian Campbell wrote: >>>>>> On Wed, 2013-09-18 at 18:33 +0100, Julien Grall wrote: >>>>>>> On 09/17/2013 02:37 AM, Ian Campbell wrote: >>>>>>>> Hi, >>>>>>>> >>>>>>>> The following reworks early bring up on ARM to use a separate set of >>>>>>>> boot pagetables. This simplifies things by avoiding the need to bring up >>>>>>>> all CPUs in lock step, which in turn allows us to do secondary CPU >>>>>>>> bringup in C code. >>>>>>>> >>>>>>>> Unfortunately the main bulk of this change is a single large patch which >>>>>>>> is hard to decompose any further since it is basically pulling on the >>>>>>>> thread and then knitting a new jumper from it. >>>>>>>> >>>>>>>> With these changes Xen now absolutely requires that the bootloader calls >>>>>>>> the hypervisor in HYP mode, the previous workarounds have been removed. >>>>>>>> For use on models a bootwrapper is now required. See >>>>>>>> git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 >>>>>>>> git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 >>>>>>>> >>>>>>>> I have implemented support for CPU bringup on the fastmodel vexpress >>>>>>>> platforms (v7and v8) here, I suppose it should work OK on a real >>>>>>>> vexpress too but I''ve not tried it. >>>>>>> >>>>>>> I have just tried the patch series on the versatile express and it >>>>>>> doesn''t work. I''m using the u-boot from Andre and all the cpus already >>>>>>> boot in hyp mode (checked without this patch series). >>>>>> >>>>>> :-( >>>>>> >>>>>> The code should essentially the same as the old kick cpus, but >>>>>> reimplemented in C. The only difference I can spot is that the C version >>>>>> is kicking a single CPU at a time while the ASM version is kicking >>>>>> everyone at once. Does using send_SGI_allbutself instead work as a hack? >>>>>> >>>>>> Perhaps our idea of the CPUID is wrong or something? Your patches to >>>>>> fixup the logical CPU id stuff might help? >>>> >>>> I have found the issue, in send_SGI_mask we remove the offline CPUs with >>>> the following line: >>>> mask &= cpumask_bits(&cpu_online_map); >>>> >>>> As the secondary cpu (assuming we have a board with only 2 cores) is not >>>> yet online, we can''t send SGI with our code. >>>> I''m very surprised that the code works on the fast models. >>> >>> So am I, now. >>> >>> OK. So online mask == 0x1 and we are trying to wake mask 0x2, so the >>> actual target list we end up using is 0... >>> >>> The gic manual says "When TargetListFilter is 0b00, if the CPUTargetList >>> field is 0x00 the Distributor does not forward the interrupt to any CPU >>> interface." (footnote to table 4-21), so it shouldn''t be waking >>> anything... It may be a model bug >>> >>>> To solve the issue, I think we need to create another helper which will >>>> send an SGI wihout removing offline CPUs. >>> >>> Looking briefly at the callchains leading to send_SGI_mask I don''t see >>> any which deliberately pass an offline CPU (which would be pretty >>> non-sensical apart from this one case). So we could perhaps just remove >>> this check and make it the caller''s problem. >>> Or maybe the right check is for cpu_possible mask or something similar >>> instead of online? >> >> You are right, cpu_possible mask is better. >> I can modify this patch http://patches.linaro.org/20437/ to add the >> check in gic_cpu_mask. > > Sounds reasonable.Hmm ... in fact this solution is not enough :/. With my patch series "handle non-contiguous CPU ID" (mainly the patch #3 http://patches.linaro.org/20437/), the gic cpu ID of the target cpu is not yet initialize. Linux solves this issue by setting each gic cpu mask (our gic_cpu_id) to 0xff and refine each time a new cpu boot. If we choose this solution that would mean that all secondaries cpus will boot at the same time. As I understand with your new boot code (patch #5), we are only able to handle one cpu simultaneously. Perhaps, we need to reintroduce an holding pen which contains the MPIDR. -- Julien Grall
On Thu, 2013-09-19 at 15:49 +0100, Julien Grall wrote:> On 09/18/2013 10:28 PM, Ian Campbell wrote: > > On Wed, 2013-09-18 at 22:14 +0100, Julien Grall wrote: > >> On 09/18/2013 09:22 PM, Ian Campbell wrote: > >>> On Wed, 2013-09-18 at 21:00 +0100, Julien Grall wrote: > >>>> On 09/18/2013 08:24 PM, Ian Campbell wrote: > >>>>> On Wed, 2013-09-18 at 20:22 +0100, Ian Campbell wrote: > >>>>>> On Wed, 2013-09-18 at 18:33 +0100, Julien Grall wrote: > >>>>>>> On 09/17/2013 02:37 AM, Ian Campbell wrote: > >>>>>>>> Hi, > >>>>>>>> > >>>>>>>> The following reworks early bring up on ARM to use a separate set of > >>>>>>>> boot pagetables. This simplifies things by avoiding the need to bring up > >>>>>>>> all CPUs in lock step, which in turn allows us to do secondary CPU > >>>>>>>> bringup in C code. > >>>>>>>> > >>>>>>>> Unfortunately the main bulk of this change is a single large patch which > >>>>>>>> is hard to decompose any further since it is basically pulling on the > >>>>>>>> thread and then knitting a new jumper from it. > >>>>>>>> > >>>>>>>> With these changes Xen now absolutely requires that the bootloader calls > >>>>>>>> the hypervisor in HYP mode, the previous workarounds have been removed. > >>>>>>>> For use on models a bootwrapper is now required. See > >>>>>>>> git://xenbits.xen.org/people/ianc/boot-wrapper.git xen-arm32 > >>>>>>>> git://xenbits.xen.org/people/ianc/boot-wrapper-aarch64.git xen-arm64 > >>>>>>>> > >>>>>>>> I have implemented support for CPU bringup on the fastmodel vexpress > >>>>>>>> platforms (v7and v8) here, I suppose it should work OK on a real > >>>>>>>> vexpress too but I''ve not tried it. > >>>>>>> > >>>>>>> I have just tried the patch series on the versatile express and it > >>>>>>> doesn''t work. I''m using the u-boot from Andre and all the cpus already > >>>>>>> boot in hyp mode (checked without this patch series). > >>>>>> > >>>>>> :-( > >>>>>> > >>>>>> The code should essentially the same as the old kick cpus, but > >>>>>> reimplemented in C. The only difference I can spot is that the C version > >>>>>> is kicking a single CPU at a time while the ASM version is kicking > >>>>>> everyone at once. Does using send_SGI_allbutself instead work as a hack? > >>>>>> > >>>>>> Perhaps our idea of the CPUID is wrong or something? Your patches to > >>>>>> fixup the logical CPU id stuff might help? > >>>> > >>>> I have found the issue, in send_SGI_mask we remove the offline CPUs with > >>>> the following line: > >>>> mask &= cpumask_bits(&cpu_online_map); > >>>> > >>>> As the secondary cpu (assuming we have a board with only 2 cores) is not > >>>> yet online, we can''t send SGI with our code. > >>>> I''m very surprised that the code works on the fast models. > >>> > >>> So am I, now. > >>> > >>> OK. So online mask == 0x1 and we are trying to wake mask 0x2, so the > >>> actual target list we end up using is 0... > >>> > >>> The gic manual says "When TargetListFilter is 0b00, if the CPUTargetList > >>> field is 0x00 the Distributor does not forward the interrupt to any CPU > >>> interface." (footnote to table 4-21), so it shouldn''t be waking > >>> anything... It may be a model bug > >>> > >>>> To solve the issue, I think we need to create another helper which will > >>>> send an SGI wihout removing offline CPUs. > >>> > >>> Looking briefly at the callchains leading to send_SGI_mask I don''t see > >>> any which deliberately pass an offline CPU (which would be pretty > >>> non-sensical apart from this one case). So we could perhaps just remove > >>> this check and make it the caller''s problem. > >>> Or maybe the right check is for cpu_possible mask or something similar > >>> instead of online? > >> > >> You are right, cpu_possible mask is better. > >> I can modify this patch http://patches.linaro.org/20437/ to add the > >> check in gic_cpu_mask. > > > > Sounds reasonable. > > Hmm ... in fact this solution is not enough :/. > With my patch series "handle non-contiguous CPU ID" (mainly the patch #3 > http://patches.linaro.org/20437/), the gic cpu ID of the target cpu is > not yet initialize. > > Linux solves this issue by setting each gic cpu mask (our gic_cpu_id) to > 0xff and refine each time a new cpu boot. If we choose this solution > that would mean that all secondaries cpus will boot at the same time. > As I understand with your new boot code (patch #5), we are only able to > handle one cpu simultaneously. > > Perhaps, we need to reintroduce an holding pen which contains the MPIDR.Yeah, I was hoping to avoid that but it looks like the only sensible way forward. A least we can still do the kick late and directly onto the relocated xen, so it''s not too bad. Ian.
Ian Campbell
2013-Sep-20 17:09 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
On Thu, 2013-09-19 at 12:36 +0100, Tim Deegan wrote:> > > - PRINT("- Ready -\r\n") > > +1: PRINT("- Ready -\r\n") > > Again, I''d prefer the label to go above (logically connected to the end > of the block being skipped) to avoid the risk of someone adding new code > just before ''- Ready -'' and having it be accidentally skipped.I''ve been half thinking about defining some macros: #define BOOT_CPU_START(name) cbnz x22, boot_cpu_#name_skip #define BOOT_CPU_END(name) boot_cpu_#name_skip: So we would end up with: BOOT_CPU_START(build_fixmap) /* All the stuff to build the fixmap */ BOOT_CPU_END(build_fixmap) I''m in two minds about whether this is an improvement though. Ian.
Ian Campbell
2013-Sep-20 17:16 UTC
Re: [PATCH RFC 5/7] xen: arm: rewrite start of day page table and cpu bring up
On Thu, 2013-09-19 at 12:36 +0100, Tim Deegan wrote:> > > + 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 > > Do we need any TLB flushes here, since we''re modifying the live > pagetables? I don''t recall whether the ARM MMU is guaranteed not to > cache/prefetch negative results (like the x86 one is).My recollection is that it doesn''t. Ian.