The following implements hypervisor support for booting an arm64 Linux kernel as a dom0 onto of a 64-bit hypervisor. This works with both 32- and 64-bit root filesystems (as you''d expect). I''ll post the kernel side too but note that it is very much WIP, I''m just throwing this out there prior to going AFK for 3 weeks next week. I haven''t yet tried a guest (even 32-bit) on top of this kernel, I know for a fact that the kernel side of this work isn''t up to it (mainly because no sync bitops -> no event channels). For the same reason 64-bit 64-bit guests don''t work yet. The series is built on top of "arm: host SMP support" from last week.
On Tue, 2013-03-12 at 14:53 +0000, Ian Campbell wrote:> > I haven''t yet tried a guest (even 32-bit) on top of this kernel, I > know for a fact that the kernel side of this work isn''t up to it > (mainly because no sync bitops -> no event channels).So here is that skanky patch. It is based on: commit d3fbfe7fbaa68ee918fd62c385b40d233d5c631d Author: Will Deacon <will.deacon@arm.com> Date: Mon Jan 28 12:06:58 2013 +0000 amba-clcd: separate ioremap framebuffer from DMA implementation As well I hinted above evtchn stuff isn''t expected to work due to lack of asm optimised bitops on ARM causing a fallback to a spinlock based thing which is no use for talking to the h/v. I''ve also hacked around the arch/arm arch/arm64 in the worst possible ways (where multiple worst options exist I have endeavoured to use both possible techniques ;-)). We need to decide how to deal with this -- drivers/xen/arm or virt/xen/arm seem like contenders. Tricks based on -I../../../ etc have been used elsewhere in the kernel but aren''t popular. It should be pretty obvious this is just a dump, only reason I''m sending it out is for reference since I''m going AFK for 3 weeks soon, perhaps someone else will do the kernel side while I''m away, if not I''ll pick it up when I get back. diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index ef14873..f1f3706 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1860,8 +1860,9 @@ config XEN_DOM0 config XEN bool "Xen guest support on ARM (EXPERIMENTAL)" - depends on EXPERIMENTAL && ARM && OF + depends on EXPERIMENTAL && ARM && AEABI && OF depends on CPU_V7 && !CPU_V6 + depends on !GENERIC_ATOMIC64 help Say Y if you want to run Linux in a Virtual Machine on Xen on ARM. diff --git a/arch/arm/include/asm/xen/events.h b/arch/arm/include/asm/xen/events.h index e86a1b3..8b1f37b 100644 --- a/arch/arm/include/asm/xen/events.h +++ b/arch/arm/include/asm/xen/events.h @@ -16,6 +16,8 @@ static inline int xen_irqs_disabled(struct pt_regs *regs) return raw_irqs_disabled_flags(regs->ARM_cpsr); } -#define xchg_xen_ulong(ptr, val) atomic64_xchg((atomic64_t *)(ptr), (val)) +#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((ptr), \ + atomic64_t, \ + counter), (val)) #endif /* _ASM_ARM_XEN_EVENTS_H */ diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h index 30cdacb..0ef7370 100644 --- a/arch/arm/include/asm/xen/page.h +++ b/arch/arm/include/asm/xen/page.h @@ -1,7 +1,7 @@ #ifndef _ASM_ARM_XEN_PAGE_H #define _ASM_ARM_XEN_PAGE_H -#include <asm/mach/map.h> +//#include <asm/mach/map.h> #include <asm/page.h> #include <asm/pgtable.h> @@ -88,6 +88,10 @@ static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn) return __set_phys_to_machine(pfn, mfn); } +#ifdef CONFIG_ARM64 +#define xen_remap(cookie, size) __ioremap((cookie), (size), __pgprot(PROT_NORMAL_HACK)) +#else #define xen_remap(cookie, size) __arm_ioremap((cookie), (size), MT_MEMORY); +#endif #endif /* _ASM_ARM_XEN_PAGE_H */ diff --git a/arch/arm/xen/hypercall.S b/arch/arm/xen/hypercall.S index 71f7239..cadf0c0 100644 --- a/arch/arm/xen/hypercall.S +++ b/arch/arm/xen/hypercall.S @@ -31,34 +31,52 @@ */ /* - * The Xen hypercall calling convention is very similar to the ARM - * procedure calling convention: the first paramter is passed in r0, the - * second in r1, the third in r2 and the fourth in r3. Considering that + * The Xen hypercall calling convention is very similar to the ARM EABI + * procedure calling convention: the first paramter is passed in x0/r0, the + * second in x1/r1, the third in x2/r2 and the fourth in x3/r3. Considering that * Xen hypercalls have 5 arguments at most, the fifth paramter is passed - * in r4, differently from the procedure calling convention of using the + * in x4/r4, differently from the procedure calling convention of using the * stack for that case. * - * The hypercall number is passed in r12. + * The hypercall number is passed in r12 (arm) or x16 (arm64). In both cases the + * relevant ARM procedure calling convention specifies this is an + * inter-procedure-call scratch register (e.g. for use in linker + * stubs). This use does not conflict with use during a hypercall. * - * The return value is in r0. + * The return value is in r0/x0. * * The hvc ISS is required to be 0xEA1, that is the Xen specific ARM * hypercall tag. + * + * Parameter structs passed to hypercalls are laid out according to + the ARM EABI standard. */ #include <linux/linkage.h> #include <asm/assembler.h> -#include <asm/opcodes-virt.h> #include <xen/interface/xen.h> - #define XEN_IMM 0xEA1 +#ifdef CONFIG_ARM + +#include <asm/opcodes-virt.h> + +#define HYPERCALL_REG r12 +#define RET mov pc,lr + +#else + +#define HYPERCALL_REG x16 +#define __HVC(x) hvc x +#define RET ret +#endif + #define HYPERCALL_SIMPLE(hypercall) \ ENTRY(HYPERVISOR_##hypercall) \ - mov r12, #__HYPERVISOR_##hypercall; \ + mov HYPERCALL_REG, #__HYPERVISOR_##hypercall; \ __HVC(XEN_IMM); \ - mov pc, lr; \ + RET; \ ENDPROC(HYPERVISOR_##hypercall) #define HYPERCALL0 HYPERCALL_SIMPLE @@ -67,6 +85,7 @@ ENDPROC(HYPERVISOR_##hypercall) #define HYPERCALL3 HYPERCALL_SIMPLE #define HYPERCALL4 HYPERCALL_SIMPLE +#ifdef CONFIG_ARM #define HYPERCALL5(hypercall) \ ENTRY(HYPERVISOR_##hypercall) \ stmdb sp!, {r4} \ @@ -74,9 +93,12 @@ ENTRY(HYPERVISOR_##hypercall) \ mov r12, #__HYPERVISOR_##hypercall; \ __HVC(XEN_IMM); \ ldm sp!, {r4} \ - mov pc, lr \ + RET \ ENDPROC(HYPERVISOR_##hypercall) - +#else + /*XXX*/ +#endif + .text HYPERCALL2(xen_version); @@ -88,6 +110,7 @@ HYPERCALL2(hvm_op); HYPERCALL2(memory_op); HYPERCALL2(physdev_op); +#ifdef CONFIG_ARM ENTRY(privcmd_call) stmdb sp!, {r4} mov r12, r0 @@ -100,3 +123,17 @@ ENTRY(privcmd_call) ldm sp!, {r4} mov pc, lr ENDPROC(privcmd_call); +#else +ENTRY(privcmd_call) + push x4, xzr + mov x12, x0 + mov x0, x1 + mov x1, x2 + mov x2, x3 + ldr x3, [sp, #8] + ldr x4, [sp, #4] + __HVC(XEN_IMM) + pop x5, xzr + ret +ENDPROC(privcmd_call); +#endif diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index f683721..d7d7b02 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -189,6 +189,25 @@ config HW_PERF_EVENTS source "mm/Kconfig" +config XEN_DOM0 + def_bool y + depends on XEN + +config XEN + bool "Xen guest support on ARM64 (EXPERIMENTAL)" + depends on EXPERIMENTAL && ARM64 && OF + #depends on CPU_V7 && !CPU_V6 + help + Say Y if you want to run Linux in a Virtual Machine on Xen on ARM. + + + This option is EXPERIMENTAL because the hypervisor + interfaces which it uses are not yet considered stable + therefore backwards and forwards compatibility is not yet + guaranteed. + + If unsure, say N. + endmenu menu "Boot options" diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index c95c5cb..8084cb3 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -37,6 +37,7 @@ TEXT_OFFSET := 0x00080000 export TEXT_OFFSET GZFLAGS core-y += arch/arm64/kernel/ arch/arm64/mm/ +core-$(CONFIG_XEN) += arch/arm/xen/ libs-y := arch/arm64/lib/ $(libs-y) libs-y += $(LIBGCC) diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index c343448..eb31952 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile @@ -1,4 +1,5 @@ dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb +dtb-y += foundation-v8.dtb targets += dtbs targets += $(dtb-y) diff --git a/arch/arm64/boot/dts/foundation-v8.dts b/arch/arm64/boot/dts/foundation-v8.dts new file mode 100644 index 0000000..33dc3ff --- /dev/null +++ b/arch/arm64/boot/dts/foundation-v8.dts @@ -0,0 +1,207 @@ +/* + * ARM Ltd. + * + * RTSM Foundation v8 platform (model) + * + * A very stripped down Versatile Express inspired platform + * + */ + +/dts-v1/; + +/ { + #address-cells = <2>; + #size-cells = <1>; + model = "V2P-AARCH64"; + compatible = "arm,vexpress,v2p-aarch64", "arm,vexpress"; + interrupt-parent = <&gic>; + + chosen { + bootargs = "dom0_mem=128M dom0_max_vcpus=1 console=com1,vga"; + xen,dom0-bootargs = "earlyprintk=xenboot console=ttyAMA1 root=/dev/mmcblk0 debug rw init=/root/init.sh"; + }; + + aliases { + serial0 = &v2m_serial0; + serial1 = &v2m_serial1; + serial2 = &v2m_serial2; + serial3 = &v2m_serial3; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,armv8"; + reg = <0>; + enable-method = "spin-table"; + cpu-release-addr = <0x0 0x8000fff8>; + }; +// cpu@1 { +// device_type = "cpu"; +// compatible = "arm,armv8"; +// reg = <1>; +// enable-method = "spin-table"; +// cpu-release-addr = <0x0 0x8000fff8>; +// }; +// cpu@2 { +// device_type = "cpu"; +// compatible = "arm,armv8"; +// reg = <2>; +// enable-method = "spin-table"; +// cpu-release-addr = <0x0 0x8000fff8>; +// }; +// cpu@3 { +// device_type = "cpu"; +// compatible = "arm,armv8"; +// reg = <3>; +// enable-method = "spin-table"; +// cpu-release-addr = <0x0 0x8000fff8>; +// }; + }; + + memory@80000000 { + device_type = "memory"; + reg = < 0x00000000 0x80000000 0x80000000 >; +// 0x00000008 0x80000000 0x80000000 >; + }; + hypervisor { + compatible = "xen,xen-4.2", "xen,xen"; + /* this field is going to be adjusted by the hypervisor */ + reg = <0 0xb0000000 0x20000>; + /* this field is going to be adjusted by the hypervisor */ + interrupts = <1 15 0xf08>; + }; + + + gic: interrupt-controller@2c001000 { + compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; + #interrupt-cells = <3>; + #address-cells = <0>; + interrupt-controller; + reg = <0 0x2c001000 0x1000>, + <0 0x2c002000 0x1000>, + <0 0x2c004000 0x2000>, + <0 0x2c006000 0x2000>; + }; + + pmu { + compatible = "arm,armv8-pmuv3"; + interrupts = <0 60 4 0 61 4 0 62 4 0 63 4>; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 14 0xff01>; + clock-frequency = <100000000>; + }; + + motherboard { + compatible = "simple-bus"; + arm,v2m-memory-map = "rs1"; + #address-cells = <2>; /* SMB chipselect number and offset */ + #size-cells = <1>; + #interrupt-cells = <1>; + + interrupt-map-mask = <0 0 63>; + interrupt-map = <0 0 0 &gic 0 0 4>, + <0 0 1 &gic 0 1 4>, + <0 0 2 &gic 0 2 4>, + <0 0 3 &gic 0 3 4>, + <0 0 4 &gic 0 4 4>, + <0 0 5 &gic 0 5 4>, + <0 0 6 &gic 0 6 4>, + <0 0 7 &gic 0 7 4>, + <0 0 8 &gic 0 8 4>, + <0 0 9 &gic 0 9 4>, + <0 0 10 &gic 0 10 4>, + <0 0 11 &gic 0 11 4>, + <0 0 12 &gic 0 12 4>, + <0 0 13 &gic 0 13 4>, + <0 0 14 &gic 0 14 4>, + <0 0 15 &gic 0 15 4>, + <0 0 16 &gic 0 16 4>, + <0 0 17 &gic 0 17 4>, + <0 0 18 &gic 0 18 4>, + <0 0 19 &gic 0 19 4>, + <0 0 20 &gic 0 20 4>, + <0 0 21 &gic 0 21 4>, + <0 0 22 &gic 0 22 4>, + <0 0 23 &gic 0 23 4>, + <0 0 24 &gic 0 24 4>, + <0 0 25 &gic 0 25 4>, + <0 0 26 &gic 0 26 4>, + <0 0 27 &gic 0 27 4>, + <0 0 28 &gic 0 28 4>, + <0 0 29 &gic 0 29 4>, + <0 0 30 &gic 0 30 4>, + <0 0 31 &gic 0 31 4>, + <0 0 32 &gic 0 32 4>, + <0 0 33 &gic 0 33 4>, + <0 0 34 &gic 0 34 4>, + <0 0 35 &gic 0 35 4>, + <0 0 36 &gic 0 36 4>, + <0 0 37 &gic 0 37 4>, + <0 0 38 &gic 0 38 4>, + <0 0 39 &gic 0 39 4>, + <0 0 40 &gic 0 40 4>, + <0 0 41 &gic 0 41 4>, + <0 0 42 &gic 0 42 4>; + + ranges = <2 0 0x0 0x18000000 0x04000000>, + <3 0 0x0 0x1c000000 0x04000000>; + + ethernet@2,02000000 { + compatible = "smsc,lan91c111"; + reg = <2 0x02000000 0x10000>; + interrupts = <15>; + }; + + iofpga@3,00000000 { + compatible = "arm,amba-bus", "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 3 0 0x200000>; + + sysreg@010000 { + compatible = "arm,vexpress-sysreg"; + reg = <0x010000 0x1000>; + }; + + v2m_serial0: uart@090000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x090000 0x1000>; + interrupts = <5>; + }; + + v2m_serial1: uart@0a0000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0a0000 0x1000>; + interrupts = <6>; + }; + + v2m_serial2: uart@0b0000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0b0000 0x1000>; + interrupts = <7>; + }; + + v2m_serial3: uart@0c0000 { + compatible = "arm,pl011", "arm,primecell"; + reg = <0x0c0000 0x1000>; + interrupts = <8>; + }; + + virtio_block@0130000 { + compatible = "virtio,mmio"; + reg = <0x130000 0x1000>; + interrupts = <42>; + }; + }; + }; + + /* chosen */ +}; + diff --git a/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts b/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts index 89c3065..d583ff8 100644 --- a/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts +++ b/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts @@ -21,7 +21,20 @@ #address-cells = <2>; #size-cells = <2>; - chosen { }; + chosen { + bootargs = "dom0_mem=128M dom0_max_vcpus=1 console=com1,vga"; + xen,dom0-bootargs = "earlyprintk=xenboot console=ttyAMA1 root=/dev/mmcblk0 debug rw init=/root/init.sh"; +// bootargs = "console=ttyAMA0 earlyprintk=pl011,0x1c090000 root=/dev/mmcblk0 debug rw init=/root/init.sh"; + /*xen,dom0-bootargs = "earlyprintk=xenboot console=hvc0 root=/dev/mmcblk0 debug rw init=/root/init.sh";*/ + }; + hypervisor { + compatible = "xen,xen-4.2", "xen,xen"; + /* this field is going to be adjusted by the hypervisor */ + reg = <0 0xb0000000 0 0x20000>; + /* this field is going to be adjusted by the hypervisor */ + interrupts = <1 15 0xf08>; + }; + aliases { serial0 = &v2m_serial0; @@ -41,33 +54,11 @@ enable-method = "spin-table"; cpu-release-addr = <0x0 0x8000fff8>; }; - cpu@1 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <1>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; - }; - cpu@2 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <2>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; - }; - cpu@3 { - device_type = "cpu"; - compatible = "arm,armv8"; - reg = <3>; - enable-method = "spin-table"; - cpu-release-addr = <0x0 0x8000fff8>; - }; }; memory@80000000 { device_type = "memory"; - reg = <0x00000000 0x80000000 0 0x80000000>, - <0x00000008 0x80000000 0 0x80000000>; + reg = <0x00000000 0x80000000 0 0x80000000>; }; gic: interrupt-controller@2c001000 { @@ -76,7 +67,9 @@ #address-cells = <0>; interrupt-controller; reg = <0 0x2c001000 0 0x1000>, - <0 0x2c002000 0 0x100>; + <0 0x2c002000 0 0x100>, + <0 0x2c004000 0 0x2000>, + <0 0x2c006000 0 0x2000>; }; timer { diff --git a/arch/arm64/include/asm/hypervisor.h b/arch/arm64/include/asm/hypervisor.h new file mode 100644 index 0000000..b90d9e5 --- /dev/null +++ b/arch/arm64/include/asm/hypervisor.h @@ -0,0 +1,6 @@ +#ifndef _ASM_ARM_HYPERVISOR_H +#define _ASM_ARM_HYPERVISOR_H + +#include <asm/xen/hypervisor.h> + +#endif diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h index 57f12c9..fc95a8e 100644 --- a/arch/arm64/include/asm/io.h +++ b/arch/arm64/include/asm/io.h @@ -224,6 +224,7 @@ extern void __iounmap(volatile void __iomem *addr); #define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_DIRTY) #define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRE)) #define PROT_NORMAL_NC (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL_NC)) +#define PROT_NORMAL_HACK (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL)) #define ioremap(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) #define ioremap_nocache(addr, size) __ioremap((addr), (size), __pgprot(PROT_DEVICE_nGnRE)) diff --git a/arch/arm64/include/asm/sync_bitops.h b/arch/arm64/include/asm/sync_bitops.h new file mode 100644 index 0000000..fa323e6 --- /dev/null +++ b/arch/arm64/include/asm/sync_bitops.h @@ -0,0 +1,26 @@ +#ifndef __ASM_SYNC_BITOPS_H__ +#define __ASM_SYNC_BITOPS_H__ + +#include <asm/bitops.h> +#include <asm/cmpxchg.h> + +/* sync_bitops functions are equivalent to the SMP implementation of the + * original functions, independently from CONFIG_SMP being defined. + * + * We need them because _set_bit etc are not SMP safe if !CONFIG_SMP. But + * under Xen you might be communicating with a completely external entity + * who might be on another CPU (e.g. two uniprocessor guests communicating + * via event channels and grant tables). So we need a variant of the bit + * ops which are SMP safe even on a UP kernel. + */ + +#define sync_set_bit(nr, p) _set_bit(nr, p) +#define sync_clear_bit(nr, p) _clear_bit(nr, p) +#define sync_change_bit(nr, p) _change_bit(nr, p) +#define sync_test_and_set_bit(nr, p) _test_and_set_bit(nr, p) +#define sync_test_and_clear_bit(nr, p) _test_and_clear_bit(nr, p) +#define sync_test_and_change_bit(nr, p) _test_and_change_bit(nr, p) +#define sync_test_bit(nr, addr) test_bit(nr, addr) +#define sync_cmpxchg cmpxchg + +#endif diff --git a/arch/arm64/include/asm/xen/events.h b/arch/arm64/include/asm/xen/events.h new file mode 100644 index 0000000..4b4834f --- /dev/null +++ b/arch/arm64/include/asm/xen/events.h @@ -0,0 +1,22 @@ +#ifndef _ASM_ARM_XEN_EVENTS_H +#define _ASM_ARM_XEN_EVENTS_H + +#include <asm/ptrace.h> + +enum ipi_vector { + XEN_PLACEHOLDER_VECTOR, + + /* Xen IPIs go here */ + XEN_NR_IPIS, +}; + +static inline int xen_irqs_disabled(struct pt_regs *regs) +{ + return raw_irqs_disabled_flags(regs->pstate); +} + +#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((ptr), \ + atomic64_t, \ + counter), (val)) + +#endif /* _ASM_ARM_XEN_EVENTS_H */ diff --git a/arch/arm64/include/asm/xen/hypercall.h b/arch/arm64/include/asm/xen/hypercall.h new file mode 120000 index 0000000..3c2e6ce --- /dev/null +++ b/arch/arm64/include/asm/xen/hypercall.h @@ -0,0 +1 @@ +../../../../arm/include/asm/xen/hypercall.h \ No newline at end of file diff --git a/arch/arm64/include/asm/xen/hypervisor.h b/arch/arm64/include/asm/xen/hypervisor.h new file mode 120000 index 0000000..e7c8923 --- /dev/null +++ b/arch/arm64/include/asm/xen/hypervisor.h @@ -0,0 +1 @@ +../../../../arm/include/asm/xen/hypervisor.h \ No newline at end of file diff --git a/arch/arm64/include/asm/xen/interface.h b/arch/arm64/include/asm/xen/interface.h new file mode 120000 index 0000000..3d12f53 --- /dev/null +++ b/arch/arm64/include/asm/xen/interface.h @@ -0,0 +1 @@ +../../../../arm/include/asm/xen/interface.h \ No newline at end of file diff --git a/arch/arm64/include/asm/xen/page.h b/arch/arm64/include/asm/xen/page.h new file mode 120000 index 0000000..671b1d3 --- /dev/null +++ b/arch/arm64/include/asm/xen/page.h @@ -0,0 +1 @@ +../../../../arm/include/asm/xen/page.h \ No newline at end of file diff --git a/arch/arm64/xen b/arch/arm64/xen new file mode 120000 index 0000000..2a99060 --- /dev/null +++ b/arch/arm64/xen @@ -0,0 +1 @@ +../arm/xen \ No newline at end of file diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c index 8286f90..2846439 100644 --- a/drivers/mfd/vexpress-sysreg.c +++ b/drivers/mfd/vexpress-sysreg.c @@ -260,10 +260,11 @@ static int vexpress_sysreg_config_func_exec(void *func, int offset, /* Early execution, no timer available, have to spin */ u32 cfgstat; - do { - cpu_relax(); - cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT); - } while (!cfgstat); + cpu_relax(); +// do { +// cpu_relax(); +// cfgstat = readl(vexpress_sysreg_base + SYS_CFGSTAT); +// } while (!cfgstat); if (!write && (cfgstat & SYS_CFGSTAT_COMPLETE)) *data = readl(vexpress_sysreg_base + SYS_CFGDATA); diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 651b576..36f0c91 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -355,20 +355,20 @@ static void init_evtchn_cpu_bindings(void) static inline void clear_evtchn(int port) { - struct shared_info *s = HYPERVISOR_shared_info; - sync_clear_bit(port, BM(&s->evtchn_pending[0])); + //struct shared_info *s = HYPERVISOR_shared_info; + //sync_clear_bit(port, &s->evtchn_pending[0]); } static inline void set_evtchn(int port) { - struct shared_info *s = HYPERVISOR_shared_info; - sync_set_bit(port, BM(&s->evtchn_pending[0])); + //struct shared_info *s = HYPERVISOR_shared_info; + //sync_set_bit(port, &s->evtchn_pending[0]); } static inline int test_evtchn(int port) { - struct shared_info *s = HYPERVISOR_shared_info; - return sync_test_bit(port, BM(&s->evtchn_pending[0])); + //struct shared_info *s = HYPERVISOR_shared_info; + return 0; //sync_test_bit(port, &s->evtchn_pending[0]); } @@ -391,8 +391,8 @@ EXPORT_SYMBOL_GPL(notify_remote_via_irq); static void mask_evtchn(int port) { - struct shared_info *s = HYPERVISOR_shared_info; - sync_set_bit(port, BM(&s->evtchn_mask[0])); + //struct shared_info *s = HYPERVISOR_shared_info; + //sync_set_bit(port, &s->evtchn_mask[0]); } static void unmask_evtchn(int port) @@ -418,6 +418,7 @@ static void unmask_evtchn(int port) struct evtchn_unmask unmask = { .port = port }; (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask); } else { +#if 0 struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); sync_clear_bit(port, BM(&s->evtchn_mask[0])); @@ -431,6 +432,7 @@ static void unmask_evtchn(int port) !sync_test_and_set_bit(port / BITS_PER_EVTCHN_WORD, BM(&vcpu_info->evtchn_pending_sel))) vcpu_info->evtchn_upcall_pending = 1; +#endif } put_cpu(); @@ -1523,16 +1525,16 @@ static int set_affinity_irq(struct irq_data *data, const struct cpumask *dest, int resend_irq_on_evtchn(unsigned int irq) { - int masked, evtchn = evtchn_from_irq(irq); - struct shared_info *s = HYPERVISOR_shared_info; +// int masked, evtchn = evtchn_from_irq(irq); +// struct shared_info *s = HYPERVISOR_shared_info; - if (!VALID_EVTCHN(evtchn)) - return 1; +// if (!VALID_EVTCHN(evtchn)) +// return 1; - masked = sync_test_and_set_bit(evtchn, BM(s->evtchn_mask)); - sync_set_bit(evtchn, BM(s->evtchn_pending)); - if (!masked) - unmask_evtchn(evtchn); +// masked = sync_test_and_set_bit(evtchn, s->evtchn_mask); +// sync_set_bit(evtchn, s->evtchn_pending); +// if (!masked) +// unmask_evtchn(evtchn); return 1; } @@ -1576,12 +1578,12 @@ static int retrigger_dynirq(struct irq_data *data) int ret = 0; if (VALID_EVTCHN(evtchn)) { - int masked; +// int masked; - masked = sync_test_and_set_bit(evtchn, BM(sh->evtchn_mask)); - sync_set_bit(evtchn, BM(sh->evtchn_pending)); - if (!masked) - unmask_evtchn(evtchn); +// masked = sync_test_and_set_bit(evtchn, sh->evtchn_mask); +// sync_set_bit(evtchn, sh->evtchn_pending); +// if (!masked) +// unmask_evtchn(evtchn); ret = 1; } diff --git a/include/xen/interface/io/protocols.h b/include/xen/interface/io/protocols.h index 0eafaf2..056744b 100644 --- a/include/xen/interface/io/protocols.h +++ b/include/xen/interface/io/protocols.h @@ -15,7 +15,7 @@ # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_IA64 #elif defined(__powerpc64__) # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_POWERPC64 -#elif defined(__arm__) +#elif defined(__arm__) || defined(__aarch64__) # define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_ARM #else # error arch fixup needed here diff --git a/kernel/printk.c b/kernel/printk.c index 587404d..f4ad381 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -1542,7 +1542,6 @@ asmlinkage int vprintk_emit(int facility, int level, * prefix which might be passed-in as a parameter. */ text_len = vscnprintf(text, sizeof(textbuf), fmt, args); - xen_raw_console_write(text); /* mark and strip a trailing newline */ if (text_len && text[text_len-1] == ''\n'') {
Ian Campbell
2013-Mar-12 15:48 UTC
[PATCH 01/14] xen: arm: define 64-bit guest hypercall calling convention.
From: Ian Campbell <ian.campbell@citrix.com> As well as using x<N> rather than r<N> registers for passing arguments/results as mandate the use of x16 as the hypercall number. Add some pedantry about struct alignment layout referencing the ARM Procedure Calling Standard to avoid confusion with the previous "OABI" convention. While at it also mandate that hypercall argument structs are always little endian. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/include/public/arch-arm.h | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h index 3333399..e44e90f 100644 --- a/xen/include/public/arch-arm.h +++ b/xen/include/public/arch-arm.h @@ -33,20 +33,31 @@ * A hypercall is issued using the ARM HVC instruction. * * A hypercall can take up to 5 arguments. These are passed in - * registers, the first argument in r0, the second argument in r1, the - * third in r2, the forth in r3 and the fifth in r4. + * registers, the first argument in x0/r0 (for arm64/arm32 guests + * respectively irrespective of whether the underlying hypervisor is + * 32- or 64-bit), the second argument in x1/r1, the third in x2/r2, + * the forth in x3/r3 and the fifth in x4/r4. * - * The hypercall number is passed in r12. + * The hypercall number is passed in r12 (arm) or x16 (arm64). In both + * cases the relevant ARM procedure calling convention specifies this + * is an inter-procedure-call scratch register (e.g. for use in linker + * stubs). This use does not conflict with use during a hypercall. * * The HVC ISS must contain a Xen specific TAG: XEN_HYPERCALL_TAG. * - * The return value is in r0. + * The return value is in x0/r0. * - * The hypercall will clobber r12 and the argument registers used by - * that hypercall (except r0 which is the return value) i.e. a 2 - * argument hypercall will clobber r1 and a 4 argument hypercall will - * clobber r1, r2 and r3. + * The hypercall will clobber x16/r12 and the argument registers used + * by that hypercall (except r0 which is the return value) i.e. in + * addition to x16/r12 a 2 argument hypercall will clobber x1/r1 and a + * 4 argument hypercall will clobber x1/r1, x2/r2 and x3/r3. * + * Parameter structs passed to hypercalls are laid out according to + * the Procedure Call Standard for the ARM Architecture (AAPCS, AKA + * EABI) and Procedure Call Standard for the ARM 64-bit Architecture + * (AAPCS64). Where there is a conflict the 64-bit standard should be + * used regardless of guest type. Structures which are passed as + * hypercall arguments are always little endian. */ #define XEN_HYPERCALL_TAG 0XEA1 -- 1.7.10.4
From: Ian Campbell <ian.campbell@citrix.com> Correct definition of UREGS_kernel_sizeof and use it. Correct adjustment of stack on entry and exit. Add 64-bit versions of the build time checks for stack pointer alignment correctness when pushing the stack frames. Lastly, correct the padding in the stack frames to properly align the inner and outer frames and also avoid an unnecessary 64bit padding field. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/arm64/asm-offsets.c | 2 +- xen/arch/arm/arm64/entry.S | 9 +++++---- xen/arch/arm/domain.c | 2 ++ xen/arch/arm/traps.c | 7 +++++++ xen/include/asm-arm/arm64/processor.h | 7 +++---- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/xen/arch/arm/arm64/asm-offsets.c b/xen/arch/arm/arm64/asm-offsets.c index 7949e3e..7544082 100644 --- a/xen/arch/arm/arm64/asm-offsets.c +++ b/xen/arch/arm/arm64/asm-offsets.c @@ -39,7 +39,7 @@ void __dummy__(void) OFFSET(UREGS_SP_el1, struct cpu_user_regs, sp_el1); OFFSET(UREGS_ELR_el1, struct cpu_user_regs, elr_el1); - OFFSET(UREGS_kernel_sizeof, struct cpu_user_regs, cpsr); + OFFSET(UREGS_kernel_sizeof, struct cpu_user_regs, spsr_el1); DEFINE(UREGS_user_sizeof, sizeof(struct cpu_user_regs)); BLANK(); diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S index 9d38088..a5fd608 100644 --- a/xen/arch/arm/arm64/entry.S +++ b/xen/arch/arm/arm64/entry.S @@ -34,7 +34,7 @@ lr .req x30 // link register mrs x22, SP_el0 str x22, [x21] - add x21, sp, #UREGS_ELR_el1 + add x21, sp, #UREGS_SP_el1 mrs x22, SP_el1 mrs x23, ELR_el1 stp x22, x23, [x21] @@ -59,7 +59,7 @@ lr .req x30 // link register * Save state on entry to hypervisor */ .macro entry, hyp, compat - sub sp, sp, #(UREGS_SPSR_el1 - UREGS_SP) + sub sp, sp, #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ push x28, x29 push x26, x27 push x24, x25 @@ -78,7 +78,7 @@ lr .req x30 // link register .if \hyp == 1 /* Hypervisor mode */ - add x21, sp, #(UREGS_X0 - UREGS_SP) + add x21, sp, #UREGS_kernel_sizeof .else /* Guest mode */ @@ -213,7 +213,8 @@ ENTRY(return_to_hypervisor) pop x26, x27 pop x28, x29 - ldr lr, [sp], #(UREGS_SPSR_el1 - UREGS_SP) + ldr lr, [sp], #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ + eret /* diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index f369871..08bb132 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -419,6 +419,8 @@ int vcpu_initialise(struct vcpu *v) { int rc = 0; + BUILD_BUG_ON( sizeof(struct cpu_info) > STACK_SIZE ); + v->arch.stack = alloc_xenheap_pages(STACK_ORDER, MEMF_node(vcpu_to_node(v))); if ( v->arch.stack == NULL ) return -ENOMEM; diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index a98a45e..6b19bc5 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -43,9 +43,16 @@ * entry.S) and struct cpu_info (which lives at the bottom of a Xen * stack) must be doubleword-aligned in size. */ static inline void check_stack_alignment_constraints(void) { +#ifdef CONFIG_ARM_64 + BUILD_BUG_ON((sizeof (struct cpu_user_regs)) & 0xf); + BUILD_BUG_ON((offsetof(struct cpu_user_regs, spsr_el1)) & 0xf); + BUILD_BUG_ON((offsetof(struct cpu_user_regs, lr)) & 0xf); + BUILD_BUG_ON((sizeof (struct cpu_info)) & 0xf); +#else BUILD_BUG_ON((sizeof (struct cpu_user_regs)) & 0x7); BUILD_BUG_ON((offsetof(struct cpu_user_regs, sp_usr)) & 0x7); BUILD_BUG_ON((sizeof (struct cpu_info)) & 0x7); +#endif } static int debug_stack_lines = 20; diff --git a/xen/include/asm-arm/arm64/processor.h b/xen/include/asm-arm/arm64/processor.h index b4602fa..bf436c8 100644 --- a/xen/include/asm-arm/arm64/processor.h +++ b/xen/include/asm-arm/arm64/processor.h @@ -51,6 +51,7 @@ struct cpu_user_regs __DECL_REG(x27, r11_fiq); __DECL_REG(x28, r12_fiq); __DECL_REG(/* x29 */ fp, /* r13_fiq */ sp_fiq); + __DECL_REG(/* x30 */ lr, /* r14_fiq */ lr_fiq); register_t sp; /* Valid for hypervisor frames */ @@ -59,7 +60,7 @@ struct cpu_user_regs __DECL_REG(pc, pc32); /* ELR_EL2 */ uint32_t cpsr; /* SPSR_EL2 */ - uint64_t pad0; + uint32_t pad0; /* Align end of kernel frame. */ /* Outer guest frame only from here on... */ @@ -68,7 +69,7 @@ struct cpu_user_regs uint32_t spsr_svc; /* AArch32 */ }; - uint32_t pad1; /* Align */ + uint32_t pad1; /* Doubleword-align the user half of the frame */ /* AArch32 guests only */ uint32_t spsr_fiq, spsr_irq, spsr_und, spsr_abt; @@ -76,8 +77,6 @@ struct cpu_user_regs /* AArch64 guests only */ uint64_t sp_el0; uint64_t sp_el1, elr_el1; - - uint64_t pad2; /* Doubleword-align the user half of the frame */ }; #undef __DECL_REG -- 1.7.10.4
Ian Campbell
2013-Mar-12 15:48 UTC
[PATCH 03/14] xen: arm: rename 32-bit specific zImage field offset constants
From: Ian Campbell <ian.campbell@citrix.com> This will help avoid confusion when 64-bit Image support is added. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/kernel.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c index 8f4a60d..e7f34a4 100644 --- a/xen/arch/arm/kernel.c +++ b/xen/arch/arm/kernel.c @@ -19,12 +19,12 @@ #define KERNEL_FLASH_ADDRESS 0x00000000UL #define KERNEL_FLASH_SIZE 0x00800000UL -#define ZIMAGE_MAGIC_OFFSET 0x24 -#define ZIMAGE_START_OFFSET 0x28 -#define ZIMAGE_END_OFFSET 0x2c -#define ZIMAGE_HEADER_LEN 0x30 +#define ZIMAGE32_MAGIC_OFFSET 0x24 +#define ZIMAGE32_START_OFFSET 0x28 +#define ZIMAGE32_END_OFFSET 0x2c +#define ZIMAGE32_HEADER_LEN 0x30 -#define ZIMAGE_MAGIC 0x016f2818 +#define ZIMAGE32_MAGIC 0x016f2818 struct minimal_dtb_header { uint32_t magic; @@ -99,26 +99,26 @@ static void kernel_zimage_load(struct kernel_info *info) } } -/** - * Check the image is a zImage and return the load address and length +/* + * Check if the image is a 32-bit zImage and setup kernel_info */ -static int kernel_try_zimage_prepare(struct kernel_info *info, +static int kernel_try_zimage32_prepare(struct kernel_info *info, paddr_t addr, paddr_t size) { - uint32_t zimage[ZIMAGE_HEADER_LEN/4]; + uint32_t zimage[ZIMAGE32_HEADER_LEN/4]; uint32_t start, end; struct minimal_dtb_header dtb_hdr; - if ( size < ZIMAGE_HEADER_LEN ) + if ( size < ZIMAGE32_HEADER_LEN ) return -EINVAL; copy_from_paddr(zimage, addr, sizeof(zimage), DEV_SHARED); - if (zimage[ZIMAGE_MAGIC_OFFSET/4] != ZIMAGE_MAGIC) + if (zimage[ZIMAGE32_MAGIC_OFFSET/4] != ZIMAGE32_MAGIC) return -EINVAL; - start = zimage[ZIMAGE_START_OFFSET/4]; - end = zimage[ZIMAGE_END_OFFSET/4]; + start = zimage[ZIMAGE32_START_OFFSET/4]; + end = zimage[ZIMAGE32_END_OFFSET/4]; if ( (end - start) > size ) return -EINVAL; @@ -224,7 +224,7 @@ int kernel_prepare(struct kernel_info *info) info->load_attr = BUFFERABLE; } - rc = kernel_try_zimage_prepare(info, start, size); + rc = kernel_try_zimage32_prepare(info, start, size); if (rc < 0) rc = kernel_try_elf_prepare(info, start, size); -- 1.7.10.4
Ian Campbell
2013-Mar-12 15:48 UTC
[PATCH 04/14] xen: arm: support for loading 64-bit zImage dom0
From: Ian Campbell <ian.campbell@citrix.com> This is defined in linux/Documentation/arm64/booting.txt. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/kernel.c | 80 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 5 deletions(-) diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c index e7f34a4..59844b0 100644 --- a/xen/arch/arm/kernel.c +++ b/xen/arch/arm/kernel.c @@ -26,6 +26,8 @@ #define ZIMAGE32_MAGIC 0x016f2818 +#define ZIMAGE64_MAGIC 0x14000008 + struct minimal_dtb_header { uint32_t magic; uint32_t total_size; @@ -99,6 +101,57 @@ static void kernel_zimage_load(struct kernel_info *info) } } +#ifdef CONFIG_ARM_64 +/* + * Check if the image is a 64-bit zImage and setup kernel_info + */ +static int kernel_try_zimage64_prepare(struct kernel_info *info, + paddr_t addr, paddr_t size) +{ + /* linux/Documentation/arm64/booting.txt */ + struct { + uint32_t magic; + uint32_t res0; + uint64_t text_offset; /* Image load offset */ + uint64_t res1; + uint64_t res2; + } zimage; + uint64_t start, end; + + if ( size < sizeof(zimage) ) + return -EINVAL; + + copy_from_paddr(&zimage, addr, sizeof(zimage), DEV_SHARED); + + if (zimage.magic != ZIMAGE64_MAGIC) + return -EINVAL; + + /* Currently there is no length in the header, so just use the size */ + start = 0; + end = size; + + /* + * Given the above this check is a bit pointless, but leave it + * here in case someone adds a length field in the future. + */ + if ( (end - start) > size ) + return -EINVAL; + + info->zimage.kernel_addr = addr; + + info->zimage.load_addr = info->mem.bank[0].start + + zimage.text_offset; + info->zimage.len = end - start; + + info->entry = info->zimage.load_addr; + info->load = kernel_zimage_load; + + info->type = DOMAIN_PV64; + + return 0; +} +#endif + /* * Check if the image is a 32-bit zImage and setup kernel_info */ @@ -153,6 +206,10 @@ static int kernel_try_zimage32_prepare(struct kernel_info *info, info->entry = info->zimage.load_addr; info->load = kernel_zimage_load; +#ifdef CONFIG_ARM_64 + info->type = DOMAIN_PV32; +#endif + return 0; } @@ -187,6 +244,19 @@ static int kernel_try_elf_prepare(struct kernel_info *info, if ( (rc = elf_xen_parse(&info->elf.elf, &info->elf.parms)) != 0 ) goto err; +#ifdef CONFIG_ARM_64 + if ( elf_32bit(&info->elf.elf) ) + info->type = DOMAIN_PV32; + else if ( elf_64bit(&info->elf.elf) ) + info->type = DOMAIN_PV64; + else + { + printk("Unknown ELF class\n"); + rc = -EINVAL; + goto err; + } +#endif + /* * TODO: can the ELF header be used to find the physical address * to load the image to? Instead of assuming virt == phys. @@ -224,13 +294,13 @@ int kernel_prepare(struct kernel_info *info) info->load_attr = BUFFERABLE; } - rc = kernel_try_zimage32_prepare(info, start, size); - if (rc < 0) - rc = kernel_try_elf_prepare(info, start, size); - #ifdef CONFIG_ARM_64 - info->type = DOMAIN_PV32; /* No 64-bit guest support yet */ + rc = kernel_try_zimage64_prepare(info, start, size); + if (rc < 0) #endif + rc = kernel_try_zimage32_prepare(info, start, size); + if (rc < 0) + rc = kernel_try_elf_prepare(info, start, size); return rc; } -- 1.7.10.4
Ian Campbell
2013-Mar-12 15:48 UTC
[PATCH 05/14] xen: arm: support building a 64-bit dom0 domain
From: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/domain_build.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index f161845..b1402d5 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -334,9 +334,8 @@ int construct_dom0(struct domain *d) memset(regs, 0, sizeof(*regs)); - regs->pc = (uint32_t)kinfo.entry; + regs->pc = (register_t)kinfo.entry; - regs->cpsr = PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_SVC; #ifdef CONFIG_ARM_64 d->arch.type = kinfo.type; @@ -344,6 +343,11 @@ int construct_dom0(struct domain *d) if ( is_pv32_domain(d) ) { + regs->cpsr = PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_SVC; + + /* Pretend to be a Cortex A15 */ + d->arch.vpidr = 0x410fc0f0; + /* FROM LINUX head.S * * Kernel startup entry point. @@ -361,6 +365,8 @@ int construct_dom0(struct domain *d) #ifdef CONFIG_ARM_64 else { + regs->cpsr = PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_EL1h; + /* From linux/Documentation/arm64/booting.txt */ regs->x0 = kinfo.dtb_paddr; regs->x1 = 0; /* Reserved for future use */ -- 1.7.10.4
Ian Campbell
2013-Mar-12 15:48 UTC
[PATCH 06/14] xen: arm: precalculate VTTBR_EL2 for a domain when setting up its p2m
From: Ian Campbell <ian.campbell@citrix.com> Mostly just to help with upcoming vcpu_show_registers changes. Signed-off-by: Ian Campbell <ijc@hellion.org.uk> --- xen/arch/arm/p2m.c | 16 +++++++++------- xen/include/asm-arm/domain.h | 3 +++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c index 1e8c8b4..175216c 100644 --- a/xen/arch/arm/p2m.c +++ b/xen/arch/arm/p2m.c @@ -23,13 +23,10 @@ void dump_p2m_lookup(struct domain *d, paddr_t addr) void p2m_load_VTTBR(struct domain *d) { - struct p2m_domain *p2m = &d->arch.p2m; - paddr_t maddr = page_to_maddr(p2m->first_level); - uint64_t vttbr = maddr; - - vttbr |= ((uint64_t)p2m->vmid&0xff)<<48; - - WRITE_SYSREG64(vttbr, VTTBR_EL2); + if ( is_idle_domain(d) ) + return; + BUG_ON(!d->arch.vttbr); + WRITE_SYSREG64(d->arch.vttbr, VTTBR_EL2); isb(); /* Ensure update is visible */ } @@ -300,6 +297,9 @@ int p2m_alloc_table(struct domain *d) p2m->first_level = page; + d->arch.vttbr = page_to_maddr(p2m->first_level) + | ((uint64_t)p2m->vmid&0xff)<<48; + spin_unlock(&p2m->lock); return 0; @@ -331,6 +331,8 @@ int p2m_init(struct domain *d) /* Zero is reserved */ p2m->vmid = d->domain_id + 1; + d->arch.vttbr = 0; + p2m->first_level = NULL; return 0; diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h index bf9caff..3da9163 100644 --- a/xen/include/asm-arm/domain.h +++ b/xen/include/asm-arm/domain.h @@ -53,7 +53,10 @@ struct arch_domain enum domain_type type; #endif + /* Virtual MMU */ struct p2m_domain p2m; + uint64_t vttbr; + struct hvm_domain hvm_domain; xen_pfn_t *grant_table_gpfn; -- 1.7.10.4
Ian Campbell
2013-Mar-12 15:48 UTC
[PATCH 07/14] xen: arm: improve register dump output for 64-bit guest (and more generally too)
From: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/traps.c | 171 +++++++++++++++++++++++++++--------------- xen/include/asm-arm/cpregs.h | 1 + 2 files changed, 113 insertions(+), 59 deletions(-) diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index 6b19bc5..2f4e157 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -238,7 +238,7 @@ void panic_PAR(uint64_t par) msg = decode_fsc( (par&PAR_FSC_MASK) >> PAR_FSC_SHIFT, &level); - printk("PAR: %010"PRIx64": %s stage %d%s%s\n", + printk("PAR: %016"PRIx64": %s stage %d%s%s\n", par, msg, stage, second_in_first ? " during second stage lookup" : "", @@ -248,33 +248,60 @@ void panic_PAR(uint64_t par) } struct reg_ctxt { - uint32_t sctlr, tcr; - uint64_t ttbr0, ttbr1; + /* Guest-side state */ + uint32_t sctlr_el1, tcr_el1; + uint64_t ttbr0_el1, ttbr1_el1; #ifdef CONFIG_ARM_32 + uint32_t dfsr, ifsr; uint32_t dfar, ifar; #else + uint32_t esr_el1; uint64_t far; + uint32_t ifsr32_el2; #endif + + /* Hypervisor-side state */ + uint64_t vttbr_el2; }; +static const char *mode_string(uint32_t cpsr) +{ + uint32_t mode; + static const char *mode_strings[] = { + [PSR_MODE_USR] = "32-bit Guest USR", + [PSR_MODE_FIQ] = "32-bit Guest FIQ", + [PSR_MODE_IRQ] = "32-bit Guest IRQ", + [PSR_MODE_SVC] = "32-bit Guest SVC", + [PSR_MODE_MON] = "32-bit Monitor", + [PSR_MODE_ABT] = "32-bit Guest ABT", + [PSR_MODE_HYP] = "Hypervisor", + [PSR_MODE_UND] = "32-bit Guest UND", + [PSR_MODE_SYS] = "32-bit Guest SYS", +#ifdef CONFIG_ARM_64 + [PSR_MODE_EL3h] = "64-bit EL3h (Monitor, handler)", + [PSR_MODE_EL3t] = "64-bit EL3t (Monitor, thread)", + [PSR_MODE_EL2h] = "64-bit EL2h (Hypervisor, handler)", + [PSR_MODE_EL2t] = "64-bit EL2t (Hypervisor, thread)", + [PSR_MODE_EL1h] = "64-bit EL1h (Guest Kernel, handler)", + [PSR_MODE_EL1t] = "64-bit EL1t (Guest Kernel, thread)", + [PSR_MODE_EL0t] = "64-bit EL0t (Guest User)", +#endif + }; + mode = cpsr & PSR_MODE_MASK; + + if ( mode > ARRAY_SIZE(mode_strings) ) + return "Unknown"; + return mode_strings[mode] ? : "Unknown"; +} + static void show_registers_32(struct cpu_user_regs *regs, struct reg_ctxt *ctxt, int guest_mode, const struct vcpu *v) { - static const char *mode_strings[] = { - [PSR_MODE_USR] = "USR", - [PSR_MODE_FIQ] = "FIQ", - [PSR_MODE_IRQ] = "IRQ", - [PSR_MODE_SVC] = "SVC", - [PSR_MODE_MON] = "MON", - [PSR_MODE_ABT] = "ABT", - [PSR_MODE_HYP] = "HYP", - [PSR_MODE_UND] = "UND", - [PSR_MODE_SYS] = "SYS" - }; #ifdef CONFIG_ARM_64 + BUG_ON( ! (regs->cpsr & PSR_MODE_BIT) ); printk("PC: %08"PRIx32"\n", regs->pc32); #else printk("PC: %08"PRIx32, regs->pc); @@ -282,9 +309,8 @@ static void show_registers_32(struct cpu_user_regs *regs, print_symbol(" %s", regs->pc); printk("\n"); #endif - printk("CPSR: %08"PRIx32" MODE:%s%s\n", regs->cpsr, - guest_mode ? "32-bit Guest " : "Hypervisor", - guest_mode ? mode_strings[regs->cpsr & PSR_MODE_MASK] : ""); + printk("CPSR: %08"PRIx32" MODE:%s\n", regs->cpsr, + mode_string(regs->cpsr)); printk(" R0: %08"PRIx32" R1: %08"PRIx32" R2: %08"PRIx32" R3: %08"PRIx32"\n", regs->r0, regs->r1, regs->r2, regs->r3); printk(" R4: %08"PRIx32" R5: %08"PRIx32" R6: %08"PRIx32" R7: %08"PRIx32"\n", @@ -325,15 +351,19 @@ static void show_registers_32(struct cpu_user_regs *regs, if ( guest_mode ) { - printk("TTBR0 %010"PRIx64" TTBR1 %010"PRIx64" TCR %08"PRIx32"\n", - ctxt->ttbr0, ctxt->ttbr1, ctxt->tcr); - printk("SCTLR %08"PRIx32"\n", ctxt->sctlr); - printk("IFAR %08"PRIx32" DFAR %08"PRIx32"\n", + printk(" SCTLR: %08"PRIx32"\n", ctxt->sctlr_el1); + printk(" TCR: %08"PRIx32"\n", ctxt->tcr_el1); + printk(" TTBR0: %016"PRIx64"\n", ctxt->ttbr0_el1); + printk(" TTBR1: %016"PRIx64"\n", ctxt->ttbr1_el1); + printk(" IFAR: %08"PRIx32", IFSR: %08"PRIx32"\n" + " DFAR: %08"PRIx32", DFSR: %08"PRIx32"\n", #ifdef CONFIG_ARM_64 (uint32_t)(ctxt->far >> 32), - (uint32_t)(ctxt->far & 0xffffffff) + ctxt->ifsr32_el2, + (uint32_t)(ctxt->far & 0xffffffff), + ctxt->esr_el1 #else - ctxt->ifar, ctxt->dfar + ctxt->ifar, ctxt->ifsr, ctxt->dfar, ctxt->dfsr #endif ); printk("\n"); @@ -346,13 +376,25 @@ static void show_registers_64(struct cpu_user_regs *regs, int guest_mode, const struct vcpu *v) { + + BUG_ON( (regs->cpsr & PSR_MODE_BIT) ); + printk("PC: %016"PRIx64, regs->pc); if ( !guest_mode ) print_symbol(" %s", regs->pc); printk("\n"); - printk("SP: %08"PRIx64"\n", regs->sp); + printk("LR: %016"PRIx64"\n", regs->lr); + if ( guest_mode ) + { + printk("SP_EL0: %016"PRIx64"\n", regs->sp_el0); + printk("SP_EL1: %016"PRIx64"\n", regs->sp_el1); + } + else + { + printk("SP: %016"PRIx64"\n", regs->sp); + } printk("CPSR: %08"PRIx32" MODE:%s\n", regs->cpsr, - guest_mode ? "64-bit Guest" : "Hypervisor"); + mode_string(regs->cpsr)); printk(" X0: %016"PRIx64" X1: %016"PRIx64" X2: %016"PRIx64"\n", regs->x0, regs->x1, regs->x2); printk(" X3: %016"PRIx64" X4: %016"PRIx64" X5: %016"PRIx64"\n", @@ -371,17 +413,20 @@ static void show_registers_64(struct cpu_user_regs *regs, regs->x21, regs->x22, regs->x23); printk(" X24: %016"PRIx64" X25: %016"PRIx64" X26: %016"PRIx64"\n", regs->x24, regs->x25, regs->x26); - printk(" X27: %016"PRIx64" X28: %016"PRIx64" X29: %016"PRIx64"\n", - regs->x27, regs->x28, regs->lr); + printk(" X27: %016"PRIx64" X28: %016"PRIx64" FP: %016"PRIx64"\n", + regs->x27, regs->x28, regs->fp); printk("\n"); if ( guest_mode ) { - printk("SCTLR_EL1: %08"PRIx32"\n", ctxt->sctlr); - printk(" TCR_EL1: %08"PRIx32"\n", ctxt->tcr); - printk("TTBR0_EL1: %010"PRIx64"\n", ctxt->ttbr0); - printk("TTBR1_EL1: %010"PRIx64"\n", ctxt->ttbr1); - printk(" FAR_EL1: %010"PRIx64"\n", ctxt->far); + printk(" ELR_EL1: %016"PRIx64"\n", regs->elr_el1); + printk(" ESR_EL1: %08"PRIx32"\n", ctxt->esr_el1); + printk(" FAR_EL1: %016"PRIx64"\n", ctxt->far); + printk("\n"); + printk(" SCTLR_EL1: %08"PRIx32"\n", ctxt->sctlr_el1); + printk(" TCR_EL1: %08"PRIx32"\n", ctxt->tcr_el1); + printk(" TTBR0_EL1: %016"PRIx64"\n", ctxt->ttbr0_el1); + printk(" TTBR1_EL1: %016"PRIx64"\n", ctxt->ttbr1_el1); printk("\n"); } } @@ -413,60 +458,68 @@ static void _show_registers(struct cpu_user_regs *regs, show_registers_32(regs, ctxt, guest_mode, v); #endif } - -#ifdef CONFIG_ARM_32 - printk("HTTBR %"PRIx64"\n", READ_CP64(HTTBR)); - printk("HDFAR %"PRIx32"\n", READ_CP32(HDFAR)); - printk("HIFAR %"PRIx32"\n", READ_CP32(HIFAR)); - printk("HPFAR %"PRIx32"\n", READ_CP32(HPFAR)); - printk("HCR %08"PRIx32"\n", READ_CP32(HCR)); - printk("HSR %"PRIx32"\n", READ_CP32(HSR)); - printk("VTTBR %010"PRIx64"\n", READ_CP64(VTTBR)); + printk(" VTCR_EL2: %08"PRIx32"\n", READ_SYSREG32(VTCR_EL2)); + printk(" VTTBR_EL2: %016"PRIx64"\n", ctxt->vttbr_el2); printk("\n"); - printk("DFSR %"PRIx32" DFAR %"PRIx32"\n", READ_CP32(DFSR), READ_CP32(DFAR)); - printk("IFSR %"PRIx32" IFAR %"PRIx32"\n", READ_CP32(IFSR), READ_CP32(IFAR)); + printk(" SCTLR_EL2: %08"PRIx32"\n", READ_SYSREG32(SCTLR_EL2)); + printk(" HCR_EL2: %016"PRIregister"\n", READ_SYSREG(HCR_EL2)); + printk(" TTBR0_EL2: %016"PRIx64"\n", READ_SYSREG64(TTBR0_EL2)); printk("\n"); + printk(" ESR_EL2: %08"PRIx32"\n", READ_SYSREG32(ESR_EL2)); + printk(" HPFAR_EL2: %016"PRIregister"\n", READ_SYSREG(HPFAR_EL2)); + +#ifdef CONFIG_ARM_32 + printk(" HDFAR: %08"PRIx32"\n", READ_CP32(HDFAR)); + printk(" HIFAR: %08"PRIx32"\n", READ_CP32(HIFAR)); #else - printk("TTBR0_EL2: %"PRIx64"\n", READ_SYSREG64(TTBR0_EL2)); - printk(" FAR_EL2: %"PRIx64"\n", READ_SYSREG64(FAR_EL2)); - printk("HPFAR_EL2: %"PRIx64"\n", READ_SYSREG64(HPFAR_EL2)); - printk(" HCR_EL2: %"PRIx64"\n", READ_SYSREG64(HCR_EL2)); - printk(" ESR_EL2: %"PRIx64"\n", READ_SYSREG64(ESR_EL2)); - printk("VTTBR_EL2: %"PRIx64"\n", READ_SYSREG64(VTTBR_EL2)); - printk("\n"); + printk(" FAR_EL2: %016"PRIx64"\n", READ_SYSREG64(FAR_EL2)); #endif + printk("\n"); } void show_registers(struct cpu_user_regs *regs) { struct reg_ctxt ctxt; - ctxt.sctlr = READ_SYSREG(SCTLR_EL1); - ctxt.tcr = READ_SYSREG(TCR_EL1); - ctxt.ttbr0 = READ_SYSREG64(TTBR0_EL1); - ctxt.ttbr1 = READ_SYSREG64(TTBR1_EL1); + ctxt.sctlr_el1 = READ_SYSREG(SCTLR_EL1); + ctxt.tcr_el1 = READ_SYSREG(TCR_EL1); + ctxt.ttbr0_el1 = READ_SYSREG64(TTBR0_EL1); + ctxt.ttbr1_el1 = READ_SYSREG64(TTBR1_EL1); #ifdef CONFIG_ARM_32 ctxt.dfar = READ_CP32(DFAR); ctxt.ifar = READ_CP32(IFAR); + ctxt.dfsr = READ_CP32(DFSR); + ctxt.ifsr = READ_CP32(IFSR); #else ctxt.far = READ_SYSREG(FAR_EL1); + ctxt.esr_el1 = READ_SYSREG(ESR_EL1); + ctxt.ifsr32_el2 = READ_SYSREG(IFSR32_EL2); #endif + ctxt.vttbr_el2 = READ_SYSREG64(VTTBR_EL2); + _show_registers(regs, &ctxt, guest_mode(regs), current); } void vcpu_show_registers(const struct vcpu *v) { struct reg_ctxt ctxt; - ctxt.sctlr = v->arch.sctlr; - ctxt.tcr = v->arch.ttbcr; - ctxt.ttbr0 = v->arch.ttbr0; - ctxt.ttbr1 = v->arch.ttbr1; + ctxt.sctlr_el1 = v->arch.sctlr; + ctxt.tcr_el1 = v->arch.ttbcr; + ctxt.ttbr0_el1 = v->arch.ttbr0; + ctxt.ttbr1_el1 = v->arch.ttbr1; #ifdef CONFIG_ARM_32 ctxt.dfar = v->arch.dfar; ctxt.ifar = v->arch.ifar; + ctxt.dfsr = v->arch.dfsr; + ctxt.ifsr = v->arch.ifsr; #else ctxt.far = v->arch.far; + ctxt.esr_el1 = v->arch.esr; + ctxt.ifsr32_el2 = v->arch.ifsr; #endif + + ctxt.vttbr_el2 = v->domain->arch.vttbr; + _show_registers(&v->arch.cpu_info->guest_cpu_user_regs, &ctxt, 1, v); } @@ -834,7 +887,7 @@ void dump_guest_s1_walk(struct domain *d, vaddr_t addr) printk("dom%d VA 0x%08"PRIvaddr"\n", d->domain_id, addr); printk(" TTBCR: 0x%08"PRIx32"\n", ttbcr); - printk(" TTBR0: 0x%010"PRIx64" = 0x%"PRIpaddr"\n", + printk(" TTBR0: 0x%016"PRIx64" = 0x%"PRIpaddr"\n", ttbr0, p2m_lookup(d, ttbr0 & PAGE_MASK)); if ( ttbcr & TTBCR_EAE ) diff --git a/xen/include/asm-arm/cpregs.h b/xen/include/asm-arm/cpregs.h index f08d59a..71daafa 100644 --- a/xen/include/asm-arm/cpregs.h +++ b/xen/include/asm-arm/cpregs.h @@ -250,6 +250,7 @@ #define DACR32_EL2 DACR #define ESR_EL2 HSR #define HCR_EL2 HCR +#define HPFAR_EL2 HPFAR #define ID_AFR0_EL1 ID_AFR0 #define ID_DFR0_EL1 ID_DFR0 #define ID_ISAR0_EL1 ID_ISAR0 -- 1.7.10.4
Ian Campbell
2013-Mar-12 15:48 UTC
[PATCH 08/14] xen: arm: support dumping 64-bit guest stack
From: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/traps.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index 2f4e157..2671eba 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -523,9 +523,81 @@ void vcpu_show_registers(const struct vcpu *v) _show_registers(&v->arch.cpu_info->guest_cpu_user_regs, &ctxt, 1, v); } -static void show_guest_stack(struct cpu_user_regs *regs) +static void show_guest_stack(struct vcpu *v, struct cpu_user_regs *regs) { - printk("GUEST STACK GOES HERE\n"); + int i; + vaddr_t sp; + paddr_t stack_phys; + void *mapped; + unsigned long *stack, addr; + + switch ( regs->cpsr & PSR_MODE_MASK ) + { + case PSR_MODE_USR: + case PSR_MODE_SYS: +#ifdef CONFIG_ARM_64 + case PSR_MODE_EL0t: +#endif + printk("No stack trace for guest user-mode\n"); + return; + + case PSR_MODE_FIQ: + case PSR_MODE_IRQ: + case PSR_MODE_SVC: + case PSR_MODE_ABT: + case PSR_MODE_UND: + printk("No stack trace for 32-bit guest kernel-mode\n"); + return; + +#ifdef CONFIG_ARM_64 + case PSR_MODE_EL1t: + sp = regs->sp_el0; + break; + case PSR_MODE_EL1h: + sp = regs->sp_el1; + break; +#endif + + case PSR_MODE_HYP: + case PSR_MODE_MON: +#ifdef CONFIG_ARM_64 + case PSR_MODE_EL3h: + case PSR_MODE_EL3t: + case PSR_MODE_EL2h: + case PSR_MODE_EL2t: +#endif + default: + BUG(); + return; + } + + printk("Guest stack trace from sp=%"PRIvaddr":\n ", sp); + + if ( gvirt_to_maddr(sp, &stack_phys) ) + { + printk("Failed to convert stack to physical address\n"); + return; + } + + mapped = map_domain_page(stack_phys >> PAGE_SHIFT); + + stack = mapped + (sp & ~PAGE_MASK); + + for ( i = 0; i < (debug_stack_lines*stack_words_per_line); i++ ) + { + if ( (((long)stack - 1) ^ ((long)(stack + 1) - 1)) & PAGE_SIZE ) + break; + addr = *stack; + if ( (i != 0) && ((i % stack_words_per_line) == 0) ) + printk("\n "); + printk(" %p", _p(addr)); + stack++; + } + if ( i == 0 ) + printk("Stack empty."); + printk("\n"); + unmap_domain_page(mapped); + } #define STACK_BEFORE_EXCEPTION(regs) ((register_t*)(regs)->sp) @@ -589,7 +661,7 @@ void show_stack(struct cpu_user_regs *regs) int i; if ( guest_mode(regs) ) - return show_guest_stack(regs); + return show_guest_stack(current, regs); printk("Xen stack trace from sp=%p:\n ", stack); @@ -631,7 +703,7 @@ void vcpu_show_execution_state(struct vcpu *v) vcpu_show_registers(v); if ( !usr_mode(&v->arch.cpu_info->guest_cpu_user_regs) ) - show_guest_stack(&v->arch.cpu_info->guest_cpu_user_regs); + show_guest_stack(v, &v->arch.cpu_info->guest_cpu_user_regs); vcpu_unpause(v); } -- 1.7.10.4
Ian Campbell
2013-Mar-12 15:48 UTC
[PATCH 09/14] xen: arm: show less words in a line of a stack trace in 64-bit builds
From: Ian Campbell <ian.campbell@citrix.com> Words are twice as wide so this ensures that a line is still <80 characters. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/traps.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index 2671eba..f1dd557 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -55,10 +55,15 @@ static inline void check_stack_alignment_constraints(void) { #endif } +#ifdef CONFIG_ARM_32 static int debug_stack_lines = 20; -integer_param("debug_stack_lines", debug_stack_lines); - #define stack_words_per_line 8 +#else +static int debug_stack_lines = 40; +#define stack_words_per_line 4 +#endif + +integer_param("debug_stack_lines", debug_stack_lines); void __cpuinit init_traps(void) -- 1.7.10.4
Ian Campbell
2013-Mar-12 15:48 UTC
[PATCH 10/14] xen: arm: Set EL1 register width in HCR_EL2 during context switch.
From: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/domain.c | 7 +++++++ xen/include/asm-arm/processor.h | 3 +++ 2 files changed, 10 insertions(+) diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 08bb132..20bb6c7 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -203,6 +203,13 @@ static void ctxt_switch_to(struct vcpu *n) isb(); +#ifdef CONFIG_ARM_64 + if ( is_pv32_domain(n->domain) ) + hcr &= ~HCR_RW; + else + hcr |= HCR_RW; +#endif + WRITE_SYSREG(hcr, HCR_EL2); isb(); diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h index 1681ebf..32c441b 100644 --- a/xen/include/asm-arm/processor.h +++ b/xen/include/asm-arm/processor.h @@ -41,6 +41,9 @@ #define HSCTLR_BASE 0x30c51878 /* HCR Hyp Configuration Register */ +#ifdef CONFIG_ARM_64 +#define HCR_RW (1<<31) +#endif #define HCR_TGE (1<<27) #define HCR_TVM (1<<26) #define HCR_TTLB (1<<25) -- 1.7.10.4
Ian Campbell
2013-Mar-12 15:48 UTC
[PATCH 11/14] xen: arm: handle traps from 64-bit guests
From: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/arm64/entry.S | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S index a5fd608..7799751 100644 --- a/xen/arch/arm/arm64/entry.S +++ b/xen/arch/arm/arm64/entry.S @@ -142,11 +142,16 @@ hyp_irq: guest_sync: entry hyp=0, compat=0 - invalid BAD_SYNC /* No AArch64 guest support yet */ + msr daifclr, #2 + mov x0, sp + bl do_trap_hypervisor + b return_to_guest guest_irq: entry hyp=0, compat=0 - invalid BAD_IRQ /* No AArch64 guest support yet */ + mov x0, sp + bl do_trap_irq + b return_to_guest guest_fiq_invalid: entry hyp=0, compat=0 -- 1.7.10.4
Ian Campbell
2013-Mar-12 15:48 UTC
[PATCH 12/14] xen: arm: handle hypercalls from 64-bit guests
From: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/traps.c | 67 ++++++++++++++++++++++++++++----------- xen/include/asm-arm/processor.h | 7 ++-- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index f1dd557..190d1e8 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -726,8 +726,8 @@ unsigned long do_arch_0(unsigned int cmd, unsigned long long value) return 0; } -typedef unsigned long (*arm_hypercall_fn_t)( - unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); +typedef register_t (*arm_hypercall_fn_t)( + register_t, register_t, register_t, register_t, register_t); typedef struct { arm_hypercall_fn_t fn; @@ -783,30 +783,49 @@ static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code) } } -static void do_trap_hypercall(struct cpu_user_regs *regs, unsigned long iss) +#ifdef CONFIG_ARM_64 +#define HYPERCALL_RESULT_REG(r) (r)->x0 +#define HYPERCALL_ARG1(r) (r)->x0 +#define HYPERCALL_ARG2(r) (r)->x1 +#define HYPERCALL_ARG3(r) (r)->x2 +#define HYPERCALL_ARG4(r) (r)->x3 +#define HYPERCALL_ARG5(r) (r)->x4 +#define HYPERCALL_ARGS(r) (r)->x0, (r)->x1, (r)->x2, (r)->x3, (r)->x4 +#else +#define HYPERCALL_RESULT_REG(r) (r)->r0 +#define HYPERCALL_ARG1(r) (r)->r0 +#define HYPERCALL_ARG2(r) (r)->r1 +#define HYPERCALL_ARG3(r) (r)->r2 +#define HYPERCALL_ARG4(r) (r)->r3 +#define HYPERCALL_ARG5(r) (r)->r4 +#define HYPERCALL_ARGS(r) (r)->r0, (r)->r1, (r)->r2, (r)->r3, (r)->r4 +#endif + +static void do_trap_hypercall(struct cpu_user_regs *regs, register_t *nr, + unsigned long iss) { arm_hypercall_fn_t call = NULL; #ifndef NDEBUG - uint32_t orig_pc = regs->pc; + register_t orig_pc = regs->pc; #endif if ( iss != XEN_HYPERCALL_TAG ) domain_crash_synchronous(); - if ( regs->r12 >= ARRAY_SIZE(arm_hypercall_table) ) + if ( *nr >= ARRAY_SIZE(arm_hypercall_table) ) { - regs->r0 = -ENOSYS; + HYPERCALL_RESULT_REG(regs) = -ENOSYS; return; } - call = arm_hypercall_table[regs->r12].fn; + call = arm_hypercall_table[*nr].fn; if ( call == NULL ) { - regs->r0 = -ENOSYS; + HYPERCALL_RESULT_REG(regs) = -ENOSYS; return; } - regs->r0 = call(regs->r0, regs->r1, regs->r2, regs->r3, regs->r4); + HYPERCALL_RESULT_REG(regs) = call(HYPERCALL_ARGS(regs)); #ifndef NDEBUG /* @@ -815,16 +834,16 @@ static void do_trap_hypercall(struct cpu_user_regs *regs, unsigned long iss) */ if ( orig_pc == regs->pc ) { - switch ( arm_hypercall_table[regs->r12].nr_args ) { - case 5: regs->r4 = 0xDEADBEEF; - case 4: regs->r3 = 0xDEADBEEF; - case 3: regs->r2 = 0xDEADBEEF; - case 2: regs->r1 = 0xDEADBEEF; - case 1: /* Don''t clobber r0 -- it''s the return value */ + switch ( arm_hypercall_table[*nr].nr_args ) { + case 5: HYPERCALL_ARG5(regs) = 0xDEADBEEF; + case 4: HYPERCALL_ARG4(regs) = 0xDEADBEEF; + case 3: HYPERCALL_ARG3(regs) = 0xDEADBEEF; + case 2: HYPERCALL_ARG2(regs) = 0xDEADBEEF; + case 1: /* Don''t clobber x0/r0 -- it''s the return value */ break; default: BUG(); } - regs->r12 = 0xDEADBEEF; + *nr = 0xDEADBEEF; } #endif } @@ -1079,11 +1098,23 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs) goto bad_trap; do_cp15_64(regs, hsr); break; - case HSR_EC_HVC: + case HSR_EC_HVC32: +#ifndef NDEBUG + if ( (hsr.iss & 0xff00) == 0xff00 ) + return do_debug_trap(regs, hsr.iss & 0x00ff); +#endif + do_trap_hypercall(regs, (register_t *)®s->r12, hsr.iss); + break; + +#ifdef CONFIG_ARM_64 + case HSR_EC_HVC64: +#ifndef NDEBUG if ( (hsr.iss & 0xff00) == 0xff00 ) return do_debug_trap(regs, hsr.iss & 0x00ff); - do_trap_hypercall(regs, hsr.iss); +#endif + do_trap_hypercall(regs, ®s->x16, hsr.iss); break; +#endif case HSR_EC_DATA_ABORT_GUEST: do_trap_data_abort_guest(regs, hsr.dabt); break; diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h index 32c441b..17f5465 100644 --- a/xen/include/asm-arm/processor.h +++ b/xen/include/asm-arm/processor.h @@ -86,8 +86,11 @@ #define HSR_EC_JAZELLE 0x09 #define HSR_EC_BXJ 0x0a #define HSR_EC_CP14_64 0x0c -#define HSR_EC_SVC 0x11 -#define HSR_EC_HVC 0x12 +#define HSR_EC_SVC32 0x11 +#define HSR_EC_HVC32 0x12 +#ifdef CONFIG_ARM_64 +#define HSR_EC_HVC64 0x16 +#endif #define HSR_EC_INSTR_ABORT_GUEST 0x20 #define HSR_EC_INSTR_ABORT_HYP 0x21 #define HSR_EC_DATA_ABORT_GUEST 0x24 -- 1.7.10.4
Ian Campbell
2013-Mar-12 15:48 UTC
[PATCH 13/14] xen: arm: handle 64-bit system register access traps.
From: Ian Campbell <ian.campbell@citrix.com> Wire up the vtimer handling to it. Use a simplified version of the 32-bit cp-register macros to have convenient decoding of HSR register values. (simplified because we don''t need them for passing to the assembler on 64-bit) Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/arch/arm/traps.c | 39 +++++++++++++ xen/arch/arm/vtimer.c | 119 ++++++++++++++++++++++++++------------- xen/include/asm-arm/processor.h | 32 +++++++++++ xen/include/asm-arm/sysregs.h | 56 ++++++++++++++++++ 4 files changed, 208 insertions(+), 38 deletions(-) create mode 100644 xen/include/asm-arm/sysregs.h diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index 190d1e8..67d9072 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -973,6 +973,39 @@ static void do_cp15_64(struct cpu_user_regs *regs, } +#ifdef CONFIG_ARM_64 +static void do_sysreg(struct cpu_user_regs *regs, + union hsr hsr) +{ + struct hsr_sysreg sysreg = hsr.sysreg; + + switch ( hsr.bits & HSR_SYSREG_REGS_MASK ) + { + case CNTP_CTL_EL0: + case CNTP_TVAL_EL0: + if ( !vtimer_emulate(regs, hsr) ) + { + dprintk(XENLOG_ERR, + "failed emulation of 64-bit vtimer sysreg access\n"); + domain_crash_synchronous(); + } + break; + default: + printk("%s %d, %d, c%d, c%d, %d %s x%d @ 0x%"PRIregister"\n", + sysreg.read ? "mrs" : "msr", + sysreg.op0, sysreg.op1, + sysreg.crn, sysreg.crm, + sysreg.op2, + sysreg.read ? "=>" : "<=", + sysreg.reg, regs->pc); + panic("unhandled 64-bit sysreg access %#x\n", + hsr.bits & HSR_SYSREG_REGS_MASK); + } + + regs->pc += 4; +} +#endif + void dump_guest_s1_walk(struct domain *d, vaddr_t addr) { uint32_t ttbcr = READ_SYSREG32(TCR_EL1); @@ -1114,7 +1147,13 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs) #endif do_trap_hypercall(regs, ®s->x16, hsr.iss); break; + case HSR_EC_SYSREG: + if ( is_pv32_domain(current->domain) ) + goto bad_trap; + do_sysreg(regs, hsr); + break; #endif + case HSR_EC_DATA_ABORT_GUEST: do_trap_data_abort_guest(regs, hsr.dabt); break; diff --git a/xen/arch/arm/vtimer.c b/xen/arch/arm/vtimer.c index a68f662..f9fc045 100644 --- a/xen/arch/arm/vtimer.c +++ b/xen/arch/arm/vtimer.c @@ -102,51 +102,62 @@ int virt_timer_restore(struct vcpu *v) return 0; } -static int vtimer_emulate_32(struct cpu_user_regs *regs, union hsr hsr) +static void vtimer_cntp_ctl(struct cpu_user_regs *regs, uint32_t *r, int read) { struct vcpu *v = current; - struct hsr_cp32 cp32 = hsr.cp32; - uint32_t *r = (uint32_t *)select_user_reg(regs, cp32.reg); - s_time_t now; - - switch ( hsr.bits & HSR_CP32_REGS_MASK ) + if ( read ) { - case HSR_CPREG32(CNTP_CTL): - if ( cp32.read ) + *r = v->arch.phys_timer.ctl; + } + else + { + v->arch.phys_timer.ctl = *r; + + if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE ) { - *r = v->arch.phys_timer.ctl; + set_timer(&v->arch.phys_timer.timer, + v->arch.phys_timer.cval + v->arch.phys_timer.offset); } else + stop_timer(&v->arch.phys_timer.timer); + } +} + +static void vtimer_cntp_tval(struct cpu_user_regs *regs, uint32_t *r, int read) +{ + struct vcpu *v = current; + s_time_t now; + + now = NOW() - v->arch.phys_timer.offset; + + if ( read ) + { + *r = (uint32_t)(ns_to_ticks(v->arch.phys_timer.cval - now) & 0xffffffffull); + } + else + { + v->arch.phys_timer.cval = now + ticks_to_ns(*r); + if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE ) { - v->arch.phys_timer.ctl = *r; - - if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE ) - { - set_timer(&v->arch.phys_timer.timer, - v->arch.phys_timer.cval + v->arch.phys_timer.offset); - } - else - stop_timer(&v->arch.phys_timer.timer); + set_timer(&v->arch.phys_timer.timer, + v->arch.phys_timer.cval + v->arch.phys_timer.offset); } + } +} +static int vtimer_emulate_cp32(struct cpu_user_regs *regs, union hsr hsr) +{ + struct hsr_cp32 cp32 = hsr.cp32; + uint32_t *r = (uint32_t *)select_user_reg(regs, cp32.reg); + + switch ( hsr.bits & HSR_CP32_REGS_MASK ) + { + case HSR_CPREG32(CNTP_CTL): + vtimer_cntp_ctl(regs, r, cp32.read); return 1; case HSR_CPREG32(CNTP_TVAL): - now = NOW() - v->arch.phys_timer.offset; - if ( cp32.read ) - { - *r = (uint32_t)(ns_to_ticks(v->arch.phys_timer.cval - now) & 0xffffffffull); - } - else - { - v->arch.phys_timer.cval = now + ticks_to_ns(*r); - if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE ) - { - set_timer(&v->arch.phys_timer.timer, - v->arch.phys_timer.cval + v->arch.phys_timer.offset); - } - } - + vtimer_cntp_tval(regs, r, cp32.read); return 1; default: @@ -154,7 +165,7 @@ static int vtimer_emulate_32(struct cpu_user_regs *regs, union hsr hsr) } } -static int vtimer_emulate_64(struct cpu_user_regs *regs, union hsr hsr) +static int vtimer_emulate_cp64(struct cpu_user_regs *regs, union hsr hsr) { struct vcpu *v = current; struct hsr_cp64 cp64 = hsr.cp64; @@ -185,16 +196,48 @@ static int vtimer_emulate_64(struct cpu_user_regs *regs, union hsr hsr) } } +#ifdef CONFIG_ARM_64 +static int vtimer_emulate_sysreg(struct cpu_user_regs *regs, union hsr hsr) +{ + struct hsr_sysreg sysreg = hsr.sysreg; + register_t *x = select_user_reg(regs, sysreg.reg); + uint32_t r = (uint32_t)*x; + + switch ( hsr.bits & HSR_SYSREG_REGS_MASK ) + { + case CNTP_CTL_EL0: + vtimer_cntp_ctl(regs, &r, sysreg.read); + *x = r; + return 1; + case CNTP_TVAL_EL0: + vtimer_cntp_tval(regs, &r, sysreg.read); + *x = r; + return 1; + default: + return 0; + } + +} +#endif + int vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr) { - if ( !is_pv32_domain(current->domain) ) - return -EINVAL; switch (hsr.ec) { case HSR_EC_CP15_32: - return vtimer_emulate_32(regs, hsr); + if ( !is_pv32_domain(current->domain) ) + return 0; + return vtimer_emulate_cp32(regs, hsr); case HSR_EC_CP15_64: - return vtimer_emulate_64(regs, hsr); + if ( !is_pv32_domain(current->domain) ) + return 0; + return vtimer_emulate_cp64(regs, hsr); +#ifdef CONFIG_ARM_64 + case HSR_EC_SYSREG: + if ( is_pv32_domain(current->domain) ) + return 0; + return vtimer_emulate_sysreg(regs, hsr); +#endif default: return 0; } diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h index 17f5465..d75530d 100644 --- a/xen/include/asm-arm/processor.h +++ b/xen/include/asm-arm/processor.h @@ -2,6 +2,7 @@ #define __ASM_ARM_PROCESSOR_H #include <asm/cpregs.h> +#include <asm/sysregs.h> /* MIDR Main ID Register */ #define MIDR_MASK 0xff0ffff0 @@ -90,6 +91,7 @@ #define HSR_EC_HVC32 0x12 #ifdef CONFIG_ARM_64 #define HSR_EC_HVC64 0x16 +#define HSR_EC_SYSREG 0x18 #endif #define HSR_EC_INSTR_ABORT_GUEST 0x20 #define HSR_EC_INSTR_ABORT_HYP 0x21 @@ -249,6 +251,21 @@ union hsr { unsigned long ec:6; /* Exception Class */ } cp64; /* HSR_EC_CP15_64, HSR_EC_CP14_64 */ +#ifdef CONFIG_ARM_64 + struct hsr_sysreg { + unsigned long read:1; /* Direction */ + unsigned long crm:4; /* CRm */ + unsigned long reg:5; /* Rt */ + unsigned long crn:4; /* CRn */ + unsigned long op1:3; /* Op1 */ + unsigned long op2:3; /* Op2 */ + unsigned long op0:2; /* Op0 */ + unsigned long res0:3; + unsigned long len:1; /* Instruction length */ + unsigned long ec:6; + } sysreg; /* HSR_EC_SYSREG */ +#endif + struct hsr_dabt { unsigned long dfsc:6; /* Data Fault Status Code */ unsigned long write:1; /* Write / not Read */ @@ -291,6 +308,21 @@ union hsr { #define HSR_CP64_CRM_SHIFT (1) #define HSR_CP64_REGS_MASK (HSR_CP64_OP1_MASK|HSR_CP64_CRM_MASK) +/* HSR.EC == HSR_SYSREG */ +#define HSR_SYSREG_OP0_MASK (0x00300000) +#define HSR_SYSREG_OP0_SHIFT (20) +#define HSR_SYSREG_OP1_MASK (0x0001c000) +#define HSR_SYSREG_OP1_SHIFT (14) +#define HSR_SYSREG_CRN_MASK (0x00003800) +#define HSR_SYSREG_CRN_SHIFT (10) +#define HSR_SYSREG_CRM_MASK (0x0000001e) +#define HSR_SYSREG_CRM_SHIFT (1) +#define HSR_SYSREG_OP2_MASK (0x000e0000) +#define HSR_SYSREG_OP2_SHIFT (17) +#define HSR_SYSREG_REGS_MASK (HSR_SYSREG_OP0_MASK|HSR_SYSREG_OP1_MASK|\ + HSR_SYSREG_CRN_MASK|HSR_SYSREG_CRM_MASK|\ + HSR_SYSREG_OP2_MASK) + /* Physical Address Register */ #define PAR_F (1<<0) diff --git a/xen/include/asm-arm/sysregs.h b/xen/include/asm-arm/sysregs.h new file mode 100644 index 0000000..9c64777 --- /dev/null +++ b/xen/include/asm-arm/sysregs.h @@ -0,0 +1,56 @@ +#ifndef __ASM_ARM_SYSREGS_H +#define __ASM_ARM_SYSREGS_H + +#ifdef CONFIG_ARM_64 + +#include <xen/stringify.h> + +/* AArch 64 System Register Encodings */ +#define __HSR_SYSREG_c0 0 +#define __HSR_SYSREG_c1 1 +#define __HSR_SYSREG_c2 2 +#define __HSR_SYSREG_c3 3 +#define __HSR_SYSREG_c4 4 +#define __HSR_SYSREG_c5 5 +#define __HSR_SYSREG_c6 6 +#define __HSR_SYSREG_c7 7 +#define __HSR_SYSREG_c8 8 +#define __HSR_SYSREG_c9 9 +#define __HSR_SYSREG_c10 10 +#define __HSR_SYSREG_c11 11 +#define __HSR_SYSREG_c12 12 +#define __HSR_SYSREG_c13 13 +#define __HSR_SYSREG_c14 14 +#define __HSR_SYSREG_c15 15 + +#define __HSR_SYSREG_0 0 +#define __HSR_SYSREG_1 1 +#define __HSR_SYSREG_2 2 +#define __HSR_SYSREG_3 3 +#define __HSR_SYSREG_4 4 +#define __HSR_SYSREG_5 5 +#define __HSR_SYSREG_6 6 +#define __HSR_SYSREG_7 7 + +/* These are used to decode traps with HSR.EC==HSR_EC_SYSREG */ +#define HSR_SYSREG(op0,op1,crn,crm,op2) \ + ((__HSR_SYSREG_##op0) << HSR_SYSREG_OP0_SHIFT) | \ + ((__HSR_SYSREG_##op1) << HSR_SYSREG_OP1_SHIFT) | \ + ((__HSR_SYSREG_##crn) << HSR_SYSREG_CRN_SHIFT) | \ + ((__HSR_SYSREG_##crm) << HSR_SYSREG_CRM_SHIFT) | \ + ((__HSR_SYSREG_##op2) << HSR_SYSREG_OP2_SHIFT) + +#define CNTP_CTL_EL0 HSR_SYSREG(3,3,c14,c2,1) +#define CNTP_TVAL_EL0 HSR_SYSREG(3,3,c14,c2,0) +#endif + +#endif + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ -- 1.7.10.4
From: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- xen/include/asm-arm/processor.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h index d75530d..53ffce2 100644 --- a/xen/include/asm-arm/processor.h +++ b/xen/include/asm-arm/processor.h @@ -244,11 +244,11 @@ union hsr { unsigned long reg1:5; /* Rt1 */ unsigned long reg2:5; /* Rt2 */ unsigned long sbzp2:1; - unsigned long op1:4; /* Op1 */ - unsigned long cc:4; /* Condition Code */ + unsigned long op1:4; /* Op1 */ + unsigned long cc:4; /* Condition Code */ unsigned long ccvalid:1;/* CC Valid */ - unsigned long len:1; /* Instruction length */ - unsigned long ec:6; /* Exception Class */ + unsigned long len:1; /* Instruction length */ + unsigned long ec:6; /* Exception Class */ } cp64; /* HSR_EC_CP15_64, HSR_EC_CP14_64 */ #ifdef CONFIG_ARM_64 -- 1.7.10.4
Stefano Stabellini
2013-Apr-08 11:17 UTC
Re: [PATCH 01/14] xen: arm: define 64-bit guest hypercall calling convention.
On Tue, 12 Mar 2013, Ian Campbell wrote:> From: Ian Campbell <ian.campbell@citrix.com> > > As well as using x<N> rather than r<N> registers for passing arguments/results > as mandate the use of x16 as the hypercall number. > > Add some pedantry about struct alignment layout referencing the ARM Procedure > Calling Standard to avoid confusion with the previous "OABI" convention. While > at it also mandate that hypercall argument structs are always little endian. > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>> xen/include/public/arch-arm.h | 27 +++++++++++++++++++-------- > 1 file changed, 19 insertions(+), 8 deletions(-) > > diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h > index 3333399..e44e90f 100644 > --- a/xen/include/public/arch-arm.h > +++ b/xen/include/public/arch-arm.h > @@ -33,20 +33,31 @@ > * A hypercall is issued using the ARM HVC instruction. > * > * A hypercall can take up to 5 arguments. These are passed in > - * registers, the first argument in r0, the second argument in r1, the > - * third in r2, the forth in r3 and the fifth in r4. > + * registers, the first argument in x0/r0 (for arm64/arm32 guests > + * respectively irrespective of whether the underlying hypervisor is > + * 32- or 64-bit), the second argument in x1/r1, the third in x2/r2, > + * the forth in x3/r3 and the fifth in x4/r4. > * > - * The hypercall number is passed in r12. > + * The hypercall number is passed in r12 (arm) or x16 (arm64). In both > + * cases the relevant ARM procedure calling convention specifies this > + * is an inter-procedure-call scratch register (e.g. for use in linker > + * stubs). This use does not conflict with use during a hypercall. > * > * The HVC ISS must contain a Xen specific TAG: XEN_HYPERCALL_TAG. > * > - * The return value is in r0. > + * The return value is in x0/r0. > * > - * The hypercall will clobber r12 and the argument registers used by > - * that hypercall (except r0 which is the return value) i.e. a 2 > - * argument hypercall will clobber r1 and a 4 argument hypercall will > - * clobber r1, r2 and r3. > + * The hypercall will clobber x16/r12 and the argument registers used > + * by that hypercall (except r0 which is the return value) i.e. in > + * addition to x16/r12 a 2 argument hypercall will clobber x1/r1 and a > + * 4 argument hypercall will clobber x1/r1, x2/r2 and x3/r3. > * > + * Parameter structs passed to hypercalls are laid out according to > + * the Procedure Call Standard for the ARM Architecture (AAPCS, AKA > + * EABI) and Procedure Call Standard for the ARM 64-bit Architecture > + * (AAPCS64). Where there is a conflict the 64-bit standard should be > + * used regardless of guest type. Structures which are passed as > + * hypercall arguments are always little endian. > */ > > #define XEN_HYPERCALL_TAG 0XEA1 > -- > 1.7.10.4 >
Stefano Stabellini
2013-Apr-08 11:24 UTC
Re: [PATCH 04/14] xen: arm: support for loading 64-bit zImage dom0
On Tue, 12 Mar 2013, Ian Campbell wrote:> From: Ian Campbell <ian.campbell@citrix.com> > > This is defined in linux/Documentation/arm64/booting.txt. > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > --- > xen/arch/arm/kernel.c | 80 +++++++++++++++++++++++++++++++++++++++++++++---- > 1 file changed, 75 insertions(+), 5 deletions(-) > > diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c > index e7f34a4..59844b0 100644 > --- a/xen/arch/arm/kernel.c > +++ b/xen/arch/arm/kernel.c > @@ -26,6 +26,8 @@ > > #define ZIMAGE32_MAGIC 0x016f2818 > > +#define ZIMAGE64_MAGIC 0x14000008 > + > struct minimal_dtb_header { > uint32_t magic; > uint32_t total_size; > @@ -99,6 +101,57 @@ static void kernel_zimage_load(struct kernel_info *info) > } > } > > +#ifdef CONFIG_ARM_64 > +/* > + * Check if the image is a 64-bit zImage and setup kernel_info > + */ > +static int kernel_try_zimage64_prepare(struct kernel_info *info, > + paddr_t addr, paddr_t size) > +{ > + /* linux/Documentation/arm64/booting.txt */ > + struct { > + uint32_t magic; > + uint32_t res0; > + uint64_t text_offset; /* Image load offset */ > + uint64_t res1; > + uint64_t res2; > + } zimage; > + uint64_t start, end; > + > + if ( size < sizeof(zimage) ) > + return -EINVAL; > + > + copy_from_paddr(&zimage, addr, sizeof(zimage), DEV_SHARED); > + > + if (zimage.magic != ZIMAGE64_MAGIC) > + return -EINVAL; > + > + /* Currently there is no length in the header, so just use the size */ > + start = 0; > + end = size; > + > + /* > + * Given the above this check is a bit pointless, but leave it > + * here in case someone adds a length field in the future. > + */ > + if ( (end - start) > size ) > + return -EINVAL; > + > + info->zimage.kernel_addr = addr; > + > + info->zimage.load_addr = info->mem.bank[0].start > + + zimage.text_offset; > + info->zimage.len = end - start; > + > + info->entry = info->zimage.load_addr; > + info->load = kernel_zimage_load; > + > + info->type = DOMAIN_PV64; > + > + return 0; > +} > +#endifthis function doesn''t seem very different from kernel_try_elf_prepare: do we really need two of them?
Stefano Stabellini
2013-Apr-08 11:25 UTC
Re: [PATCH 05/14] xen: arm: support building a 64-bit dom0 domain
On Tue, 12 Mar 2013, Ian Campbell wrote:> From: Ian Campbell <ian.campbell@citrix.com> > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>> xen/arch/arm/domain_build.c | 10 ++++++++-- > 1 file changed, 8 insertions(+), 2 deletions(-) > > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c > index f161845..b1402d5 100644 > --- a/xen/arch/arm/domain_build.c > +++ b/xen/arch/arm/domain_build.c > @@ -334,9 +334,8 @@ int construct_dom0(struct domain *d) > > memset(regs, 0, sizeof(*regs)); > > - regs->pc = (uint32_t)kinfo.entry; > + regs->pc = (register_t)kinfo.entry; > > - regs->cpsr = PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_SVC; > > #ifdef CONFIG_ARM_64 > d->arch.type = kinfo.type; > @@ -344,6 +343,11 @@ int construct_dom0(struct domain *d) > > if ( is_pv32_domain(d) ) > { > + regs->cpsr = PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_SVC; > + > + /* Pretend to be a Cortex A15 */ > + d->arch.vpidr = 0x410fc0f0; > + > /* FROM LINUX head.S > * > * Kernel startup entry point. > @@ -361,6 +365,8 @@ int construct_dom0(struct domain *d) > #ifdef CONFIG_ARM_64 > else > { > + regs->cpsr = PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_EL1h; > + > /* From linux/Documentation/arm64/booting.txt */ > regs->x0 = kinfo.dtb_paddr; > regs->x1 = 0; /* Reserved for future use */ > -- > 1.7.10.4 >
Stefano Stabellini
2013-Apr-08 11:27 UTC
Re: [PATCH 06/14] xen: arm: precalculate VTTBR_EL2 for a domain when setting up its p2m
On Tue, 12 Mar 2013, Ian Campbell wrote:> From: Ian Campbell <ian.campbell@citrix.com> > > Mostly just to help with upcoming vcpu_show_registers changes. > > Signed-off-by: Ian Campbell <ijc@hellion.org.uk>Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>> xen/arch/arm/p2m.c | 16 +++++++++------- > xen/include/asm-arm/domain.h | 3 +++ > 2 files changed, 12 insertions(+), 7 deletions(-) > > diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c > index 1e8c8b4..175216c 100644 > --- a/xen/arch/arm/p2m.c > +++ b/xen/arch/arm/p2m.c > @@ -23,13 +23,10 @@ void dump_p2m_lookup(struct domain *d, paddr_t addr) > > void p2m_load_VTTBR(struct domain *d) > { > - struct p2m_domain *p2m = &d->arch.p2m; > - paddr_t maddr = page_to_maddr(p2m->first_level); > - uint64_t vttbr = maddr; > - > - vttbr |= ((uint64_t)p2m->vmid&0xff)<<48; > - > - WRITE_SYSREG64(vttbr, VTTBR_EL2); > + if ( is_idle_domain(d) ) > + return; > + BUG_ON(!d->arch.vttbr); > + WRITE_SYSREG64(d->arch.vttbr, VTTBR_EL2); > isb(); /* Ensure update is visible */ > } > > @@ -300,6 +297,9 @@ int p2m_alloc_table(struct domain *d) > > p2m->first_level = page; > > + d->arch.vttbr = page_to_maddr(p2m->first_level) > + | ((uint64_t)p2m->vmid&0xff)<<48; > + > spin_unlock(&p2m->lock); > > return 0; > @@ -331,6 +331,8 @@ int p2m_init(struct domain *d) > /* Zero is reserved */ > p2m->vmid = d->domain_id + 1; > > + d->arch.vttbr = 0; > + > p2m->first_level = NULL; > > return 0; > diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h > index bf9caff..3da9163 100644 > --- a/xen/include/asm-arm/domain.h > +++ b/xen/include/asm-arm/domain.h > @@ -53,7 +53,10 @@ struct arch_domain > enum domain_type type; > #endif > > + /* Virtual MMU */ > struct p2m_domain p2m; > + uint64_t vttbr; > + > struct hvm_domain hvm_domain; > xen_pfn_t *grant_table_gpfn; > > -- > 1.7.10.4 >
Stefano Stabellini
2013-Apr-08 11:43 UTC
Re: [PATCH 12/14] xen: arm: handle hypercalls from 64-bit guests
On Tue, 12 Mar 2013, Ian Campbell wrote:> From: Ian Campbell <ian.campbell@citrix.com> > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>> xen/arch/arm/traps.c | 67 ++++++++++++++++++++++++++++----------- > xen/include/asm-arm/processor.h | 7 ++-- > 2 files changed, 54 insertions(+), 20 deletions(-) > > diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c > index f1dd557..190d1e8 100644 > --- a/xen/arch/arm/traps.c > +++ b/xen/arch/arm/traps.c > @@ -726,8 +726,8 @@ unsigned long do_arch_0(unsigned int cmd, unsigned long long value) > return 0; > } > > -typedef unsigned long (*arm_hypercall_fn_t)( > - unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); > +typedef register_t (*arm_hypercall_fn_t)( > + register_t, register_t, register_t, register_t, register_t); > > typedef struct { > arm_hypercall_fn_t fn; > @@ -783,30 +783,49 @@ static void do_debug_trap(struct cpu_user_regs *regs, unsigned int code) > } > } > > -static void do_trap_hypercall(struct cpu_user_regs *regs, unsigned long iss) > +#ifdef CONFIG_ARM_64 > +#define HYPERCALL_RESULT_REG(r) (r)->x0 > +#define HYPERCALL_ARG1(r) (r)->x0 > +#define HYPERCALL_ARG2(r) (r)->x1 > +#define HYPERCALL_ARG3(r) (r)->x2 > +#define HYPERCALL_ARG4(r) (r)->x3 > +#define HYPERCALL_ARG5(r) (r)->x4 > +#define HYPERCALL_ARGS(r) (r)->x0, (r)->x1, (r)->x2, (r)->x3, (r)->x4 > +#else > +#define HYPERCALL_RESULT_REG(r) (r)->r0 > +#define HYPERCALL_ARG1(r) (r)->r0 > +#define HYPERCALL_ARG2(r) (r)->r1 > +#define HYPERCALL_ARG3(r) (r)->r2 > +#define HYPERCALL_ARG4(r) (r)->r3 > +#define HYPERCALL_ARG5(r) (r)->r4 > +#define HYPERCALL_ARGS(r) (r)->r0, (r)->r1, (r)->r2, (r)->r3, (r)->r4 > +#endif > + > +static void do_trap_hypercall(struct cpu_user_regs *regs, register_t *nr, > + unsigned long iss) > { > arm_hypercall_fn_t call = NULL; > #ifndef NDEBUG > - uint32_t orig_pc = regs->pc; > + register_t orig_pc = regs->pc; > #endif > > if ( iss != XEN_HYPERCALL_TAG ) > domain_crash_synchronous(); > > - if ( regs->r12 >= ARRAY_SIZE(arm_hypercall_table) ) > + if ( *nr >= ARRAY_SIZE(arm_hypercall_table) ) > { > - regs->r0 = -ENOSYS; > + HYPERCALL_RESULT_REG(regs) = -ENOSYS; > return; > } > > - call = arm_hypercall_table[regs->r12].fn; > + call = arm_hypercall_table[*nr].fn; > if ( call == NULL ) > { > - regs->r0 = -ENOSYS; > + HYPERCALL_RESULT_REG(regs) = -ENOSYS; > return; > } > > - regs->r0 = call(regs->r0, regs->r1, regs->r2, regs->r3, regs->r4); > + HYPERCALL_RESULT_REG(regs) = call(HYPERCALL_ARGS(regs)); > > #ifndef NDEBUG > /* > @@ -815,16 +834,16 @@ static void do_trap_hypercall(struct cpu_user_regs *regs, unsigned long iss) > */ > if ( orig_pc == regs->pc ) > { > - switch ( arm_hypercall_table[regs->r12].nr_args ) { > - case 5: regs->r4 = 0xDEADBEEF; > - case 4: regs->r3 = 0xDEADBEEF; > - case 3: regs->r2 = 0xDEADBEEF; > - case 2: regs->r1 = 0xDEADBEEF; > - case 1: /* Don''t clobber r0 -- it''s the return value */ > + switch ( arm_hypercall_table[*nr].nr_args ) { > + case 5: HYPERCALL_ARG5(regs) = 0xDEADBEEF; > + case 4: HYPERCALL_ARG4(regs) = 0xDEADBEEF; > + case 3: HYPERCALL_ARG3(regs) = 0xDEADBEEF; > + case 2: HYPERCALL_ARG2(regs) = 0xDEADBEEF; > + case 1: /* Don''t clobber x0/r0 -- it''s the return value */ > break; > default: BUG(); > } > - regs->r12 = 0xDEADBEEF; > + *nr = 0xDEADBEEF; > } > #endif > } > @@ -1079,11 +1098,23 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs) > goto bad_trap; > do_cp15_64(regs, hsr); > break; > - case HSR_EC_HVC: > + case HSR_EC_HVC32: > +#ifndef NDEBUG > + if ( (hsr.iss & 0xff00) == 0xff00 ) > + return do_debug_trap(regs, hsr.iss & 0x00ff); > +#endif > + do_trap_hypercall(regs, (register_t *)®s->r12, hsr.iss); > + break; > + > +#ifdef CONFIG_ARM_64 > + case HSR_EC_HVC64: > +#ifndef NDEBUG > if ( (hsr.iss & 0xff00) == 0xff00 ) > return do_debug_trap(regs, hsr.iss & 0x00ff); > - do_trap_hypercall(regs, hsr.iss); > +#endif > + do_trap_hypercall(regs, ®s->x16, hsr.iss); > break; > +#endif > case HSR_EC_DATA_ABORT_GUEST: > do_trap_data_abort_guest(regs, hsr.dabt); > break; > diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h > index 32c441b..17f5465 100644 > --- a/xen/include/asm-arm/processor.h > +++ b/xen/include/asm-arm/processor.h > @@ -86,8 +86,11 @@ > #define HSR_EC_JAZELLE 0x09 > #define HSR_EC_BXJ 0x0a > #define HSR_EC_CP14_64 0x0c > -#define HSR_EC_SVC 0x11 > -#define HSR_EC_HVC 0x12 > +#define HSR_EC_SVC32 0x11 > +#define HSR_EC_HVC32 0x12 > +#ifdef CONFIG_ARM_64 > +#define HSR_EC_HVC64 0x16 > +#endif > #define HSR_EC_INSTR_ABORT_GUEST 0x20 > #define HSR_EC_INSTR_ABORT_HYP 0x21 > #define HSR_EC_DATA_ABORT_GUEST 0x24 > -- > 1.7.10.4 >
On Tue, 12 Mar 2013, Ian Campbell wrote:> From: Ian Campbell <ian.campbell@citrix.com> > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>> xen/include/asm-arm/processor.h | 8 ++++---- > 1 file changed, 4 insertions(+), 4 deletions(-) > > diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h > index d75530d..53ffce2 100644 > --- a/xen/include/asm-arm/processor.h > +++ b/xen/include/asm-arm/processor.h > @@ -244,11 +244,11 @@ union hsr { > unsigned long reg1:5; /* Rt1 */ > unsigned long reg2:5; /* Rt2 */ > unsigned long sbzp2:1; > - unsigned long op1:4; /* Op1 */ > - unsigned long cc:4; /* Condition Code */ > + unsigned long op1:4; /* Op1 */ > + unsigned long cc:4; /* Condition Code */ > unsigned long ccvalid:1;/* CC Valid */ > - unsigned long len:1; /* Instruction length */ > - unsigned long ec:6; /* Exception Class */ > + unsigned long len:1; /* Instruction length */ > + unsigned long ec:6; /* Exception Class */ > } cp64; /* HSR_EC_CP15_64, HSR_EC_CP14_64 */ > > #ifdef CONFIG_ARM_64 > -- > 1.7.10.4 >
Stefano Stabellini
2013-Apr-08 13:11 UTC
Re: [PATCH 13/14] xen: arm: handle 64-bit system register access traps.
On Tue, 12 Mar 2013, Ian Campbell wrote:> From: Ian Campbell <ian.campbell@citrix.com> > > Wire up the vtimer handling to it. > > Use a simplified version of the 32-bit cp-register macros to have convenient > decoding of HSR register values. (simplified because we don''t need them for > passing to the assembler on 64-bit) > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> assuming that you didn''t make any mistakes in writing down thw new SYSREG #define> xen/arch/arm/traps.c | 39 +++++++++++++ > xen/arch/arm/vtimer.c | 119 ++++++++++++++++++++++++++------------- > xen/include/asm-arm/processor.h | 32 +++++++++++ > xen/include/asm-arm/sysregs.h | 56 ++++++++++++++++++ > 4 files changed, 208 insertions(+), 38 deletions(-) > create mode 100644 xen/include/asm-arm/sysregs.h > > diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c > index 190d1e8..67d9072 100644 > --- a/xen/arch/arm/traps.c > +++ b/xen/arch/arm/traps.c > @@ -973,6 +973,39 @@ static void do_cp15_64(struct cpu_user_regs *regs, > > } > > +#ifdef CONFIG_ARM_64 > +static void do_sysreg(struct cpu_user_regs *regs, > + union hsr hsr) > +{ > + struct hsr_sysreg sysreg = hsr.sysreg; > + > + switch ( hsr.bits & HSR_SYSREG_REGS_MASK ) > + { > + case CNTP_CTL_EL0: > + case CNTP_TVAL_EL0: > + if ( !vtimer_emulate(regs, hsr) ) > + { > + dprintk(XENLOG_ERR, > + "failed emulation of 64-bit vtimer sysreg access\n"); > + domain_crash_synchronous(); > + } > + break; > + default: > + printk("%s %d, %d, c%d, c%d, %d %s x%d @ 0x%"PRIregister"\n", > + sysreg.read ? "mrs" : "msr", > + sysreg.op0, sysreg.op1, > + sysreg.crn, sysreg.crm, > + sysreg.op2, > + sysreg.read ? "=>" : "<=", > + sysreg.reg, regs->pc); > + panic("unhandled 64-bit sysreg access %#x\n", > + hsr.bits & HSR_SYSREG_REGS_MASK); > + } > + > + regs->pc += 4; > +} > +#endif > + > void dump_guest_s1_walk(struct domain *d, vaddr_t addr) > { > uint32_t ttbcr = READ_SYSREG32(TCR_EL1); > @@ -1114,7 +1147,13 @@ asmlinkage void do_trap_hypervisor(struct cpu_user_regs *regs) > #endif > do_trap_hypercall(regs, ®s->x16, hsr.iss); > break; > + case HSR_EC_SYSREG: > + if ( is_pv32_domain(current->domain) ) > + goto bad_trap; > + do_sysreg(regs, hsr); > + break; > #endif > + > case HSR_EC_DATA_ABORT_GUEST: > do_trap_data_abort_guest(regs, hsr.dabt); > break; > diff --git a/xen/arch/arm/vtimer.c b/xen/arch/arm/vtimer.c > index a68f662..f9fc045 100644 > --- a/xen/arch/arm/vtimer.c > +++ b/xen/arch/arm/vtimer.c > @@ -102,51 +102,62 @@ int virt_timer_restore(struct vcpu *v) > return 0; > } > > -static int vtimer_emulate_32(struct cpu_user_regs *regs, union hsr hsr) > +static void vtimer_cntp_ctl(struct cpu_user_regs *regs, uint32_t *r, int read) > { > struct vcpu *v = current; > - struct hsr_cp32 cp32 = hsr.cp32; > - uint32_t *r = (uint32_t *)select_user_reg(regs, cp32.reg); > - s_time_t now; > - > - switch ( hsr.bits & HSR_CP32_REGS_MASK ) > + if ( read ) > { > - case HSR_CPREG32(CNTP_CTL): > - if ( cp32.read ) > + *r = v->arch.phys_timer.ctl; > + } > + else > + { > + v->arch.phys_timer.ctl = *r; > + > + if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE ) > { > - *r = v->arch.phys_timer.ctl; > + set_timer(&v->arch.phys_timer.timer, > + v->arch.phys_timer.cval + v->arch.phys_timer.offset); > } > else > + stop_timer(&v->arch.phys_timer.timer); > + } > +} > + > +static void vtimer_cntp_tval(struct cpu_user_regs *regs, uint32_t *r, int read) > +{ > + struct vcpu *v = current; > + s_time_t now; > + > + now = NOW() - v->arch.phys_timer.offset; > + > + if ( read ) > + { > + *r = (uint32_t)(ns_to_ticks(v->arch.phys_timer.cval - now) & 0xffffffffull); > + } > + else > + { > + v->arch.phys_timer.cval = now + ticks_to_ns(*r); > + if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE ) > { > - v->arch.phys_timer.ctl = *r; > - > - if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE ) > - { > - set_timer(&v->arch.phys_timer.timer, > - v->arch.phys_timer.cval + v->arch.phys_timer.offset); > - } > - else > - stop_timer(&v->arch.phys_timer.timer); > + set_timer(&v->arch.phys_timer.timer, > + v->arch.phys_timer.cval + v->arch.phys_timer.offset); > } > + } > +} > > +static int vtimer_emulate_cp32(struct cpu_user_regs *regs, union hsr hsr) > +{ > + struct hsr_cp32 cp32 = hsr.cp32; > + uint32_t *r = (uint32_t *)select_user_reg(regs, cp32.reg); > + > + switch ( hsr.bits & HSR_CP32_REGS_MASK ) > + { > + case HSR_CPREG32(CNTP_CTL): > + vtimer_cntp_ctl(regs, r, cp32.read); > return 1; > > case HSR_CPREG32(CNTP_TVAL): > - now = NOW() - v->arch.phys_timer.offset; > - if ( cp32.read ) > - { > - *r = (uint32_t)(ns_to_ticks(v->arch.phys_timer.cval - now) & 0xffffffffull); > - } > - else > - { > - v->arch.phys_timer.cval = now + ticks_to_ns(*r); > - if ( v->arch.phys_timer.ctl & CNTx_CTL_ENABLE ) > - { > - set_timer(&v->arch.phys_timer.timer, > - v->arch.phys_timer.cval + v->arch.phys_timer.offset); > - } > - } > - > + vtimer_cntp_tval(regs, r, cp32.read); > return 1; > > default: > @@ -154,7 +165,7 @@ static int vtimer_emulate_32(struct cpu_user_regs *regs, union hsr hsr) > } > } > > -static int vtimer_emulate_64(struct cpu_user_regs *regs, union hsr hsr) > +static int vtimer_emulate_cp64(struct cpu_user_regs *regs, union hsr hsr) > { > struct vcpu *v = current; > struct hsr_cp64 cp64 = hsr.cp64; > @@ -185,16 +196,48 @@ static int vtimer_emulate_64(struct cpu_user_regs *regs, union hsr hsr) > } > } > > +#ifdef CONFIG_ARM_64 > +static int vtimer_emulate_sysreg(struct cpu_user_regs *regs, union hsr hsr) > +{ > + struct hsr_sysreg sysreg = hsr.sysreg; > + register_t *x = select_user_reg(regs, sysreg.reg); > + uint32_t r = (uint32_t)*x; > + > + switch ( hsr.bits & HSR_SYSREG_REGS_MASK ) > + { > + case CNTP_CTL_EL0: > + vtimer_cntp_ctl(regs, &r, sysreg.read); > + *x = r; > + return 1; > + case CNTP_TVAL_EL0: > + vtimer_cntp_tval(regs, &r, sysreg.read); > + *x = r; > + return 1; > + default: > + return 0; > + } > + > +} > +#endif > + > int vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr) > { > - if ( !is_pv32_domain(current->domain) ) > - return -EINVAL; > > switch (hsr.ec) { > case HSR_EC_CP15_32: > - return vtimer_emulate_32(regs, hsr); > + if ( !is_pv32_domain(current->domain) ) > + return 0; > + return vtimer_emulate_cp32(regs, hsr); > case HSR_EC_CP15_64: > - return vtimer_emulate_64(regs, hsr); > + if ( !is_pv32_domain(current->domain) ) > + return 0; > + return vtimer_emulate_cp64(regs, hsr); > +#ifdef CONFIG_ARM_64 > + case HSR_EC_SYSREG: > + if ( is_pv32_domain(current->domain) ) > + return 0; > + return vtimer_emulate_sysreg(regs, hsr); > +#endif > default: > return 0; > } > diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h > index 17f5465..d75530d 100644 > --- a/xen/include/asm-arm/processor.h > +++ b/xen/include/asm-arm/processor.h > @@ -2,6 +2,7 @@ > #define __ASM_ARM_PROCESSOR_H > > #include <asm/cpregs.h> > +#include <asm/sysregs.h> > > /* MIDR Main ID Register */ > #define MIDR_MASK 0xff0ffff0 > @@ -90,6 +91,7 @@ > #define HSR_EC_HVC32 0x12 > #ifdef CONFIG_ARM_64 > #define HSR_EC_HVC64 0x16 > +#define HSR_EC_SYSREG 0x18 > #endif > #define HSR_EC_INSTR_ABORT_GUEST 0x20 > #define HSR_EC_INSTR_ABORT_HYP 0x21 > @@ -249,6 +251,21 @@ union hsr { > unsigned long ec:6; /* Exception Class */ > } cp64; /* HSR_EC_CP15_64, HSR_EC_CP14_64 */ > > +#ifdef CONFIG_ARM_64 > + struct hsr_sysreg { > + unsigned long read:1; /* Direction */ > + unsigned long crm:4; /* CRm */ > + unsigned long reg:5; /* Rt */ > + unsigned long crn:4; /* CRn */ > + unsigned long op1:3; /* Op1 */ > + unsigned long op2:3; /* Op2 */ > + unsigned long op0:2; /* Op0 */ > + unsigned long res0:3; > + unsigned long len:1; /* Instruction length */ > + unsigned long ec:6; > + } sysreg; /* HSR_EC_SYSREG */ > +#endif > + > struct hsr_dabt { > unsigned long dfsc:6; /* Data Fault Status Code */ > unsigned long write:1; /* Write / not Read */ > @@ -291,6 +308,21 @@ union hsr { > #define HSR_CP64_CRM_SHIFT (1) > #define HSR_CP64_REGS_MASK (HSR_CP64_OP1_MASK|HSR_CP64_CRM_MASK) > > +/* HSR.EC == HSR_SYSREG */ > +#define HSR_SYSREG_OP0_MASK (0x00300000) > +#define HSR_SYSREG_OP0_SHIFT (20) > +#define HSR_SYSREG_OP1_MASK (0x0001c000) > +#define HSR_SYSREG_OP1_SHIFT (14) > +#define HSR_SYSREG_CRN_MASK (0x00003800) > +#define HSR_SYSREG_CRN_SHIFT (10) > +#define HSR_SYSREG_CRM_MASK (0x0000001e) > +#define HSR_SYSREG_CRM_SHIFT (1) > +#define HSR_SYSREG_OP2_MASK (0x000e0000) > +#define HSR_SYSREG_OP2_SHIFT (17) > +#define HSR_SYSREG_REGS_MASK (HSR_SYSREG_OP0_MASK|HSR_SYSREG_OP1_MASK|\ > + HSR_SYSREG_CRN_MASK|HSR_SYSREG_CRM_MASK|\ > + HSR_SYSREG_OP2_MASK) > + > /* Physical Address Register */ > #define PAR_F (1<<0) > > diff --git a/xen/include/asm-arm/sysregs.h b/xen/include/asm-arm/sysregs.h > new file mode 100644 > index 0000000..9c64777 > --- /dev/null > +++ b/xen/include/asm-arm/sysregs.h > @@ -0,0 +1,56 @@ > +#ifndef __ASM_ARM_SYSREGS_H > +#define __ASM_ARM_SYSREGS_H > + > +#ifdef CONFIG_ARM_64 > + > +#include <xen/stringify.h> > + > +/* AArch 64 System Register Encodings */ > +#define __HSR_SYSREG_c0 0 > +#define __HSR_SYSREG_c1 1 > +#define __HSR_SYSREG_c2 2 > +#define __HSR_SYSREG_c3 3 > +#define __HSR_SYSREG_c4 4 > +#define __HSR_SYSREG_c5 5 > +#define __HSR_SYSREG_c6 6 > +#define __HSR_SYSREG_c7 7 > +#define __HSR_SYSREG_c8 8 > +#define __HSR_SYSREG_c9 9 > +#define __HSR_SYSREG_c10 10 > +#define __HSR_SYSREG_c11 11 > +#define __HSR_SYSREG_c12 12 > +#define __HSR_SYSREG_c13 13 > +#define __HSR_SYSREG_c14 14 > +#define __HSR_SYSREG_c15 15 > + > +#define __HSR_SYSREG_0 0 > +#define __HSR_SYSREG_1 1 > +#define __HSR_SYSREG_2 2 > +#define __HSR_SYSREG_3 3 > +#define __HSR_SYSREG_4 4 > +#define __HSR_SYSREG_5 5 > +#define __HSR_SYSREG_6 6 > +#define __HSR_SYSREG_7 7 > + > +/* These are used to decode traps with HSR.EC==HSR_EC_SYSREG */ > +#define HSR_SYSREG(op0,op1,crn,crm,op2) \ > + ((__HSR_SYSREG_##op0) << HSR_SYSREG_OP0_SHIFT) | \ > + ((__HSR_SYSREG_##op1) << HSR_SYSREG_OP1_SHIFT) | \ > + ((__HSR_SYSREG_##crn) << HSR_SYSREG_CRN_SHIFT) | \ > + ((__HSR_SYSREG_##crm) << HSR_SYSREG_CRM_SHIFT) | \ > + ((__HSR_SYSREG_##op2) << HSR_SYSREG_OP2_SHIFT) > + > +#define CNTP_CTL_EL0 HSR_SYSREG(3,3,c14,c2,1) > +#define CNTP_TVAL_EL0 HSR_SYSREG(3,3,c14,c2,0) > +#endif > + > +#endif > + > +/* > + * Local variables: > + * mode: C > + * c-set-style: "BSD" > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ > -- > 1.7.10.4 >
Stefano Stabellini
2013-Apr-08 13:31 UTC
Re: [PATCH 02/14] xen: arm: tweak arm64 stack frame layout
On Tue, 12 Mar 2013, Ian Campbell wrote:> From: Ian Campbell <ian.campbell@citrix.com> > > Correct definition of UREGS_kernel_sizeof and use it. > > Correct adjustment of stack on entry and exit. > > Add 64-bit versions of the build time checks for stack pointer alignment > correctness when pushing the stack frames. > > Lastly, correct the padding in the stack frames to properly align the inner and > outer frames and also avoid an unnecessary 64bit padding field. > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > --- > xen/arch/arm/arm64/asm-offsets.c | 2 +- > xen/arch/arm/arm64/entry.S | 9 +++++---- > xen/arch/arm/domain.c | 2 ++ > xen/arch/arm/traps.c | 7 +++++++ > xen/include/asm-arm/arm64/processor.h | 7 +++---- > 5 files changed, 18 insertions(+), 9 deletions(-) > > diff --git a/xen/arch/arm/arm64/asm-offsets.c b/xen/arch/arm/arm64/asm-offsets.c > index 7949e3e..7544082 100644 > --- a/xen/arch/arm/arm64/asm-offsets.c > +++ b/xen/arch/arm/arm64/asm-offsets.c > @@ -39,7 +39,7 @@ void __dummy__(void) > OFFSET(UREGS_SP_el1, struct cpu_user_regs, sp_el1); > OFFSET(UREGS_ELR_el1, struct cpu_user_regs, elr_el1); > > - OFFSET(UREGS_kernel_sizeof, struct cpu_user_regs, cpsr); > + OFFSET(UREGS_kernel_sizeof, struct cpu_user_regs, spsr_el1); > DEFINE(UREGS_user_sizeof, sizeof(struct cpu_user_regs)); > BLANK(); > > diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S > index 9d38088..a5fd608 100644 > --- a/xen/arch/arm/arm64/entry.S > +++ b/xen/arch/arm/arm64/entry.S > @@ -34,7 +34,7 @@ lr .req x30 // link register > mrs x22, SP_el0 > str x22, [x21] > > - add x21, sp, #UREGS_ELR_el1 > + add x21, sp, #UREGS_SP_el1 > mrs x22, SP_el1 > mrs x23, ELR_el1 > stp x22, x23, [x21]Honestly I think it would be much cleaner and easier to read if we saved sp_el1 and elr_el1 separately.> @@ -59,7 +59,7 @@ lr .req x30 // link register > * Save state on entry to hypervisor > */ > .macro entry, hyp, compat > - sub sp, sp, #(UREGS_SPSR_el1 - UREGS_SP) > + sub sp, sp, #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ > push x28, x29 > push x26, x27 > push x24, x25 > @@ -78,7 +78,7 @@ lr .req x30 // link register > > .if \hyp == 1 /* Hypervisor mode */ > > - add x21, sp, #(UREGS_X0 - UREGS_SP) > + add x21, sp, #UREGS_kernel_sizeof > > .else /* Guest mode */ > > @@ -213,7 +213,8 @@ ENTRY(return_to_hypervisor) > pop x26, x27 > pop x28, x29 > > - ldr lr, [sp], #(UREGS_SPSR_el1 - UREGS_SP) > + ldr lr, [sp], #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ > + > eret > > /* > diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c > index f369871..08bb132 100644 > --- a/xen/arch/arm/domain.c > +++ b/xen/arch/arm/domain.c > @@ -419,6 +419,8 @@ int vcpu_initialise(struct vcpu *v) > { > int rc = 0; > > + BUILD_BUG_ON( sizeof(struct cpu_info) > STACK_SIZE ); > + > v->arch.stack = alloc_xenheap_pages(STACK_ORDER, MEMF_node(vcpu_to_node(v))); > if ( v->arch.stack == NULL ) > return -ENOMEM; > diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c > index a98a45e..6b19bc5 100644 > --- a/xen/arch/arm/traps.c > +++ b/xen/arch/arm/traps.c > @@ -43,9 +43,16 @@ > * entry.S) and struct cpu_info (which lives at the bottom of a Xen > * stack) must be doubleword-aligned in size. */ > static inline void check_stack_alignment_constraints(void) { > +#ifdef CONFIG_ARM_64 > + BUILD_BUG_ON((sizeof (struct cpu_user_regs)) & 0xf); > + BUILD_BUG_ON((offsetof(struct cpu_user_regs, spsr_el1)) & 0xf); > + BUILD_BUG_ON((offsetof(struct cpu_user_regs, lr)) & 0xf); > + BUILD_BUG_ON((sizeof (struct cpu_info)) & 0xf);Why both spsr_el1 and lr? From the comment on top of check_stack_alignment_constraints I would think that only spsr_el1 is needed?> +#else > BUILD_BUG_ON((sizeof (struct cpu_user_regs)) & 0x7); > BUILD_BUG_ON((offsetof(struct cpu_user_regs, sp_usr)) & 0x7); > BUILD_BUG_ON((sizeof (struct cpu_info)) & 0x7); > +#endif > } > > static int debug_stack_lines = 20; > diff --git a/xen/include/asm-arm/arm64/processor.h b/xen/include/asm-arm/arm64/processor.h > index b4602fa..bf436c8 100644 > --- a/xen/include/asm-arm/arm64/processor.h > +++ b/xen/include/asm-arm/arm64/processor.h > @@ -51,6 +51,7 @@ struct cpu_user_regs > __DECL_REG(x27, r11_fiq); > __DECL_REG(x28, r12_fiq); > __DECL_REG(/* x29 */ fp, /* r13_fiq */ sp_fiq); > + > __DECL_REG(/* x30 */ lr, /* r14_fiq */ lr_fiq); > > register_t sp; /* Valid for hypervisor frames */ > @@ -59,7 +60,7 @@ struct cpu_user_regs > __DECL_REG(pc, pc32); /* ELR_EL2 */ > uint32_t cpsr; /* SPSR_EL2 */ > > - uint64_t pad0; > + uint32_t pad0; /* Align end of kernel frame. */That would be because cpsr is a uint32_t, right?> /* Outer guest frame only from here on... */ > > @@ -68,7 +69,7 @@ struct cpu_user_regs > uint32_t spsr_svc; /* AArch32 */ > }; > > - uint32_t pad1; /* Align */ > + uint32_t pad1; /* Doubleword-align the user half of the frame */This one is because of the preceding union of two uint32_t> /* AArch32 guests only */ > uint32_t spsr_fiq, spsr_irq, spsr_und, spsr_abt; > @@ -76,8 +77,6 @@ struct cpu_user_regs > /* AArch64 guests only */ > uint64_t sp_el0; > uint64_t sp_el1, elr_el1; > - > - uint64_t pad2; /* Doubleword-align the user half of the frame */ > };of course padding with uint64_t is useless on arm (32 and 64)
Stefano Stabellini
2013-Apr-08 13:45 UTC
Re: [PATCH 11/14] xen: arm: handle traps from 64-bit guests
On Tue, 12 Mar 2013, Ian Campbell wrote:> From: Ian Campbell <ian.campbell@citrix.com> > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>> xen/arch/arm/arm64/entry.S | 9 +++++++-- > 1 file changed, 7 insertions(+), 2 deletions(-) > > diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S > index a5fd608..7799751 100644 > --- a/xen/arch/arm/arm64/entry.S > +++ b/xen/arch/arm/arm64/entry.S > @@ -142,11 +142,16 @@ hyp_irq: > > guest_sync: > entry hyp=0, compat=0 > - invalid BAD_SYNC /* No AArch64 guest support yet */ > + msr daifclr, #2 > + mov x0, sp > + bl do_trap_hypervisor > + b return_to_guest > > guest_irq: > entry hyp=0, compat=0 > - invalid BAD_IRQ /* No AArch64 guest support yet */ > + mov x0, sp > + bl do_trap_irq > + b return_to_guest > > guest_fiq_invalid: > entry hyp=0, compat=0 > -- > 1.7.10.4 >
Stefano Stabellini
2013-Apr-08 13:46 UTC
Re: [PATCH 09/14] xen: arm: show less words in a line of a stack trace in 64-bit builds
On Tue, 12 Mar 2013, Ian Campbell wrote:> From: Ian Campbell <ian.campbell@citrix.com> > > Words are twice as wide so this ensures that a line is still <80 characters. > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>> xen/arch/arm/traps.c | 9 +++++++-- > 1 file changed, 7 insertions(+), 2 deletions(-) > > diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c > index 2671eba..f1dd557 100644 > --- a/xen/arch/arm/traps.c > +++ b/xen/arch/arm/traps.c > @@ -55,10 +55,15 @@ static inline void check_stack_alignment_constraints(void) { > #endif > } > > +#ifdef CONFIG_ARM_32 > static int debug_stack_lines = 20; > -integer_param("debug_stack_lines", debug_stack_lines); > - > #define stack_words_per_line 8 > +#else > +static int debug_stack_lines = 40; > +#define stack_words_per_line 4 > +#endif > + > +integer_param("debug_stack_lines", debug_stack_lines); > > > void __cpuinit init_traps(void) > -- > 1.7.10.4 >
Stefano Stabellini
2013-Apr-08 17:29 UTC
Re: [PATCH 08/14] xen: arm: support dumping 64-bit guest stack
On Tue, 12 Mar 2013, Ian Campbell wrote:> From: Ian Campbell <ian.campbell@citrix.com> > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com>it would be nice to support more guest modes but this is undoubtedly an improvement. Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>> xen/arch/arm/traps.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++--- > 1 file changed, 76 insertions(+), 4 deletions(-) > > diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c > index 2f4e157..2671eba 100644 > --- a/xen/arch/arm/traps.c > +++ b/xen/arch/arm/traps.c > @@ -523,9 +523,81 @@ void vcpu_show_registers(const struct vcpu *v) > _show_registers(&v->arch.cpu_info->guest_cpu_user_regs, &ctxt, 1, v); > } > > -static void show_guest_stack(struct cpu_user_regs *regs) > +static void show_guest_stack(struct vcpu *v, struct cpu_user_regs *regs) > { > - printk("GUEST STACK GOES HERE\n"); > + int i; > + vaddr_t sp; > + paddr_t stack_phys; > + void *mapped; > + unsigned long *stack, addr; > + > + switch ( regs->cpsr & PSR_MODE_MASK ) > + { > + case PSR_MODE_USR: > + case PSR_MODE_SYS: > +#ifdef CONFIG_ARM_64 > + case PSR_MODE_EL0t: > +#endif > + printk("No stack trace for guest user-mode\n"); > + return; > + > + case PSR_MODE_FIQ: > + case PSR_MODE_IRQ: > + case PSR_MODE_SVC: > + case PSR_MODE_ABT: > + case PSR_MODE_UND: > + printk("No stack trace for 32-bit guest kernel-mode\n"); > + return; > + > +#ifdef CONFIG_ARM_64 > + case PSR_MODE_EL1t: > + sp = regs->sp_el0; > + break; > + case PSR_MODE_EL1h: > + sp = regs->sp_el1; > + break; > +#endif > + > + case PSR_MODE_HYP: > + case PSR_MODE_MON: > +#ifdef CONFIG_ARM_64 > + case PSR_MODE_EL3h: > + case PSR_MODE_EL3t: > + case PSR_MODE_EL2h: > + case PSR_MODE_EL2t: > +#endif > + default: > + BUG(); > + return; > + } > + > + printk("Guest stack trace from sp=%"PRIvaddr":\n ", sp); > + > + if ( gvirt_to_maddr(sp, &stack_phys) ) > + { > + printk("Failed to convert stack to physical address\n"); > + return; > + } > + > + mapped = map_domain_page(stack_phys >> PAGE_SHIFT); > + > + stack = mapped + (sp & ~PAGE_MASK); > + > + for ( i = 0; i < (debug_stack_lines*stack_words_per_line); i++ ) > + { > + if ( (((long)stack - 1) ^ ((long)(stack + 1) - 1)) & PAGE_SIZE ) > + break; > + addr = *stack; > + if ( (i != 0) && ((i % stack_words_per_line) == 0) ) > + printk("\n "); > + printk(" %p", _p(addr)); > + stack++; > + } > + if ( i == 0 ) > + printk("Stack empty."); > + printk("\n"); > + unmap_domain_page(mapped); > + > } > > #define STACK_BEFORE_EXCEPTION(regs) ((register_t*)(regs)->sp) > @@ -589,7 +661,7 @@ void show_stack(struct cpu_user_regs *regs) > int i; > > if ( guest_mode(regs) ) > - return show_guest_stack(regs); > + return show_guest_stack(current, regs); > > printk("Xen stack trace from sp=%p:\n ", stack); > > @@ -631,7 +703,7 @@ void vcpu_show_execution_state(struct vcpu *v) > > vcpu_show_registers(v); > if ( !usr_mode(&v->arch.cpu_info->guest_cpu_user_regs) ) > - show_guest_stack(&v->arch.cpu_info->guest_cpu_user_regs); > + show_guest_stack(v, &v->arch.cpu_info->guest_cpu_user_regs); > > vcpu_unpause(v); > } > -- > 1.7.10.4 >
Ian Campbell
2013-Apr-10 11:52 UTC
Re: [PATCH 04/14] xen: arm: support for loading 64-bit zImage dom0
On Mon, 2013-04-08 at 12:24 +0100, Stefano Stabellini wrote:> On Tue, 12 Mar 2013, Ian Campbell wrote: > > +static int kernel_try_zimage64_prepare(struct kernel_info *info, > > + paddr_t addr, paddr_t size) > > +{> this function doesn''t seem very different from kernel_try_elf_prepare: > do we really need two of them?The 32- and 64-bit zImage formats are completely different, different header fields/offsets different magic numbers etc. I thnk two functions is the way to go.
Ian Campbell
2013-Apr-10 11:52 UTC
Re: [PATCH 13/14] xen: arm: handle 64-bit system register access traps.
On Mon, 2013-04-08 at 14:11 +0100, Stefano Stabellini wrote:> On Tue, 12 Mar 2013, Ian Campbell wrote: > > From: Ian Campbell <ian.campbell@citrix.com> > > > > Wire up the vtimer handling to it. > > > > Use a simplified version of the 32-bit cp-register macros to have convenient > > decoding of HSR register values. (simplified because we don''t need them for > > passing to the assembler on 64-bit) > > > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > > > Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> > > assuming that you didn''t make any mistakes in writing down thw new > SYSREG #defineYeah, lets assume that ;-)
Ian Campbell
2013-Apr-10 11:57 UTC
Re: [PATCH 02/14] xen: arm: tweak arm64 stack frame layout
On Mon, 2013-04-08 at 14:31 +0100, Stefano Stabellini wrote:> On Tue, 12 Mar 2013, Ian Campbell wrote: > > From: Ian Campbell <ian.campbell@citrix.com> > > > > Correct definition of UREGS_kernel_sizeof and use it. > > > > Correct adjustment of stack on entry and exit. > > > > Add 64-bit versions of the build time checks for stack pointer alignment > > correctness when pushing the stack frames. > > > > Lastly, correct the padding in the stack frames to properly align the inner and > > outer frames and also avoid an unnecessary 64bit padding field. > > > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > > --- > > xen/arch/arm/arm64/asm-offsets.c | 2 +- > > xen/arch/arm/arm64/entry.S | 9 +++++---- > > xen/arch/arm/domain.c | 2 ++ > > xen/arch/arm/traps.c | 7 +++++++ > > xen/include/asm-arm/arm64/processor.h | 7 +++---- > > 5 files changed, 18 insertions(+), 9 deletions(-) > > > > diff --git a/xen/arch/arm/arm64/asm-offsets.c b/xen/arch/arm/arm64/asm-offsets.c > > index 7949e3e..7544082 100644 > > --- a/xen/arch/arm/arm64/asm-offsets.c > > +++ b/xen/arch/arm/arm64/asm-offsets.c > > @@ -39,7 +39,7 @@ void __dummy__(void) > > OFFSET(UREGS_SP_el1, struct cpu_user_regs, sp_el1); > > OFFSET(UREGS_ELR_el1, struct cpu_user_regs, elr_el1); > > > > - OFFSET(UREGS_kernel_sizeof, struct cpu_user_regs, cpsr); > > + OFFSET(UREGS_kernel_sizeof, struct cpu_user_regs, spsr_el1); > > DEFINE(UREGS_user_sizeof, sizeof(struct cpu_user_regs)); > > BLANK(); > > > > diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S > > index 9d38088..a5fd608 100644 > > --- a/xen/arch/arm/arm64/entry.S > > +++ b/xen/arch/arm/arm64/entry.S > > @@ -34,7 +34,7 @@ lr .req x30 // link register > > mrs x22, SP_el0 > > str x22, [x21] > > > > - add x21, sp, #UREGS_ELR_el1 > > + add x21, sp, #UREGS_SP_el1 > > mrs x22, SP_el1 > > mrs x23, ELR_el1 > > stp x22, x23, [x21] > > Honestly I think it would be much cleaner and easier to read if we saved > sp_el1 and elr_el1 separately.I think stp is supposed to be faster, but I''m running on a model so I''m not sure. Also there are weird quadword alignment constraints on the stack and stp is atomic from that PoV.> > > > @@ -59,7 +59,7 @@ lr .req x30 // link register > > * Save state on entry to hypervisor > > */ > > .macro entry, hyp, compat > > - sub sp, sp, #(UREGS_SPSR_el1 - UREGS_SP) > > + sub sp, sp, #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ > > push x28, x29 > > push x26, x27 > > push x24, x25 > > @@ -78,7 +78,7 @@ lr .req x30 // link register > > > > .if \hyp == 1 /* Hypervisor mode */ > > > > - add x21, sp, #(UREGS_X0 - UREGS_SP) > > + add x21, sp, #UREGS_kernel_sizeof > > > > .else /* Guest mode */ > > > > @@ -213,7 +213,8 @@ ENTRY(return_to_hypervisor) > > pop x26, x27 > > pop x28, x29 > > > > - ldr lr, [sp], #(UREGS_SPSR_el1 - UREGS_SP) > > + ldr lr, [sp], #(UREGS_SPSR_el1 - UREGS_LR) /* CPSR, PC, SP, LR */ > > + > > eret > > > > /* > > diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c > > index f369871..08bb132 100644 > > --- a/xen/arch/arm/domain.c > > +++ b/xen/arch/arm/domain.c > > @@ -419,6 +419,8 @@ int vcpu_initialise(struct vcpu *v) > > { > > int rc = 0; > > > > + BUILD_BUG_ON( sizeof(struct cpu_info) > STACK_SIZE ); > > + > > v->arch.stack = alloc_xenheap_pages(STACK_ORDER, MEMF_node(vcpu_to_node(v))); > > if ( v->arch.stack == NULL ) > > return -ENOMEM; > > diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c > > index a98a45e..6b19bc5 100644 > > --- a/xen/arch/arm/traps.c > > +++ b/xen/arch/arm/traps.c > > @@ -43,9 +43,16 @@ > > * entry.S) and struct cpu_info (which lives at the bottom of a Xen > > * stack) must be doubleword-aligned in size. */ > > static inline void check_stack_alignment_constraints(void) { > > +#ifdef CONFIG_ARM_64 > > + BUILD_BUG_ON((sizeof (struct cpu_user_regs)) & 0xf); > > + BUILD_BUG_ON((offsetof(struct cpu_user_regs, spsr_el1)) & 0xf); > > + BUILD_BUG_ON((offsetof(struct cpu_user_regs, lr)) & 0xf); > > + BUILD_BUG_ON((sizeof (struct cpu_info)) & 0xf); > > Why both spsr_el1 and lr? > From the comment on top of check_stack_alignment_constraints I would > think that only spsr_el1 is needed?You are right spsr_el1 is needed to check the alignments of the inner/outer frames. The lr check is because I had a few problems getting the inner code pushing working correctly, IIRC it relates to the use of stp (since you need to make sure the pair are correctly aligned)> > > > +#else > > BUILD_BUG_ON((sizeof (struct cpu_user_regs)) & 0x7); > > BUILD_BUG_ON((offsetof(struct cpu_user_regs, sp_usr)) & 0x7); > > BUILD_BUG_ON((sizeof (struct cpu_info)) & 0x7); > > +#endif > > } > > > > static int debug_stack_lines = 20; > > diff --git a/xen/include/asm-arm/arm64/processor.h b/xen/include/asm-arm/arm64/processor.h > > index b4602fa..bf436c8 100644 > > --- a/xen/include/asm-arm/arm64/processor.h > > +++ b/xen/include/asm-arm/arm64/processor.h > > @@ -51,6 +51,7 @@ struct cpu_user_regs > > __DECL_REG(x27, r11_fiq); > > __DECL_REG(x28, r12_fiq); > > __DECL_REG(/* x29 */ fp, /* r13_fiq */ sp_fiq); > > + > > __DECL_REG(/* x30 */ lr, /* r14_fiq */ lr_fiq); > > > > register_t sp; /* Valid for hypervisor frames */ > > @@ -59,7 +60,7 @@ struct cpu_user_regs > > __DECL_REG(pc, pc32); /* ELR_EL2 */ > > uint32_t cpsr; /* SPSR_EL2 */ > > > > - uint64_t pad0; > > + uint32_t pad0; /* Align end of kernel frame. */ > > That would be because cpsr is a uint32_t, right?Right, I think.> > > > /* Outer guest frame only from here on... */ > > > > @@ -68,7 +69,7 @@ struct cpu_user_regs > > uint32_t spsr_svc; /* AArch32 */ > > }; > > > > - uint32_t pad1; /* Align */ > > + uint32_t pad1; /* Doubleword-align the user half of the frame */ > > This one is because of the preceding union of two uint32_tYup.> > > /* AArch32 guests only */ > > uint32_t spsr_fiq, spsr_irq, spsr_und, spsr_abt; > > @@ -76,8 +77,6 @@ struct cpu_user_regs > > /* AArch64 guests only */ > > uint64_t sp_el0; > > uint64_t sp_el1, elr_el1; > > - > > - uint64_t pad2; /* Doubleword-align the user half of the frame */ > > }; > > of course padding with uint64_t is useless on arm (32 and 64)Right.
Ian Campbell
2013-Apr-10 11:59 UTC
Re: [PATCH 08/14] xen: arm: support dumping 64-bit guest stack
On Mon, 2013-04-08 at 18:29 +0100, Stefano Stabellini wrote:> On Tue, 12 Mar 2013, Ian Campbell wrote: > > From: Ian Campbell <ian.campbell@citrix.com> > > > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > > it would be nice to support more guest modes but this is undoubtedly an improvement.I implemented the one I needed to debug the issue I was facing at the time ;-) Hopefully others will do the same...> > Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> > > > > xen/arch/arm/traps.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++--- > > 1 file changed, 76 insertions(+), 4 deletions(-) > > > > diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c > > index 2f4e157..2671eba 100644 > > --- a/xen/arch/arm/traps.c > > +++ b/xen/arch/arm/traps.c > > @@ -523,9 +523,81 @@ void vcpu_show_registers(const struct vcpu *v) > > _show_registers(&v->arch.cpu_info->guest_cpu_user_regs, &ctxt, 1, v); > > } > > > > -static void show_guest_stack(struct cpu_user_regs *regs) > > +static void show_guest_stack(struct vcpu *v, struct cpu_user_regs *regs) > > { > > - printk("GUEST STACK GOES HERE\n"); > > + int i; > > + vaddr_t sp; > > + paddr_t stack_phys; > > + void *mapped; > > + unsigned long *stack, addr; > > + > > + switch ( regs->cpsr & PSR_MODE_MASK ) > > + { > > + case PSR_MODE_USR: > > + case PSR_MODE_SYS: > > +#ifdef CONFIG_ARM_64 > > + case PSR_MODE_EL0t: > > +#endif > > + printk("No stack trace for guest user-mode\n"); > > + return; > > + > > + case PSR_MODE_FIQ: > > + case PSR_MODE_IRQ: > > + case PSR_MODE_SVC: > > + case PSR_MODE_ABT: > > + case PSR_MODE_UND: > > + printk("No stack trace for 32-bit guest kernel-mode\n"); > > + return; > > + > > +#ifdef CONFIG_ARM_64 > > + case PSR_MODE_EL1t: > > + sp = regs->sp_el0; > > + break; > > + case PSR_MODE_EL1h: > > + sp = regs->sp_el1; > > + break; > > +#endif > > + > > + case PSR_MODE_HYP: > > + case PSR_MODE_MON: > > +#ifdef CONFIG_ARM_64 > > + case PSR_MODE_EL3h: > > + case PSR_MODE_EL3t: > > + case PSR_MODE_EL2h: > > + case PSR_MODE_EL2t: > > +#endif > > + default: > > + BUG(); > > + return; > > + } > > + > > + printk("Guest stack trace from sp=%"PRIvaddr":\n ", sp); > > + > > + if ( gvirt_to_maddr(sp, &stack_phys) ) > > + { > > + printk("Failed to convert stack to physical address\n"); > > + return; > > + } > > + > > + mapped = map_domain_page(stack_phys >> PAGE_SHIFT); > > + > > + stack = mapped + (sp & ~PAGE_MASK); > > + > > + for ( i = 0; i < (debug_stack_lines*stack_words_per_line); i++ ) > > + { > > + if ( (((long)stack - 1) ^ ((long)(stack + 1) - 1)) & PAGE_SIZE ) > > + break; > > + addr = *stack; > > + if ( (i != 0) && ((i % stack_words_per_line) == 0) ) > > + printk("\n "); > > + printk(" %p", _p(addr)); > > + stack++; > > + } > > + if ( i == 0 ) > > + printk("Stack empty."); > > + printk("\n"); > > + unmap_domain_page(mapped); > > + > > } > > > > #define STACK_BEFORE_EXCEPTION(regs) ((register_t*)(regs)->sp) > > @@ -589,7 +661,7 @@ void show_stack(struct cpu_user_regs *regs) > > int i; > > > > if ( guest_mode(regs) ) > > - return show_guest_stack(regs); > > + return show_guest_stack(current, regs); > > > > printk("Xen stack trace from sp=%p:\n ", stack); > > > > @@ -631,7 +703,7 @@ void vcpu_show_execution_state(struct vcpu *v) > > > > vcpu_show_registers(v); > > if ( !usr_mode(&v->arch.cpu_info->guest_cpu_user_regs) ) > > - show_guest_stack(&v->arch.cpu_info->guest_cpu_user_regs); > > + show_guest_stack(v, &v->arch.cpu_info->guest_cpu_user_regs); > > > > vcpu_unpause(v); > > } > > -- > > 1.7.10.4 > >
Ian Campbell
2013-Apr-11 09:35 UTC
Re: [PATCH 01/14] xen: arm: define 64-bit guest hypercall calling convention.
On Mon, 2013-04-08 at 12:17 +0100, Stefano Stabellini wrote:> Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>Thanks, applied.
Ian Campbell
2013-Apr-11 16:50 UTC
Re: [PATCH 02/14] xen: arm: tweak arm64 stack frame layout
On Wed, 2013-04-10 at 12:57 +0100, Ian Campbell wrote:> On Mon, 2013-04-08 at 14:31 +0100, Stefano Stabellini wrote: > > On Tue, 12 Mar 2013, Ian Campbell wrote: > > > From: Ian Campbell <ian.campbell@citrix.com> > > > > > > Correct definition of UREGS_kernel_sizeof and use it. > > > > > > Correct adjustment of stack on entry and exit. > > > > > > Add 64-bit versions of the build time checks for stack pointer alignment > > > correctness when pushing the stack frames. > > > > > > Lastly, correct the padding in the stack frames to properly align the inner and > > > outer frames and also avoid an unnecessary 64bit padding field. > > > > > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > > > --- > > > xen/arch/arm/arm64/asm-offsets.c | 2 +- > > > xen/arch/arm/arm64/entry.S | 9 +++++---- > > > xen/arch/arm/domain.c | 2 ++ > > > xen/arch/arm/traps.c | 7 +++++++ > > > xen/include/asm-arm/arm64/processor.h | 7 +++---- > > > 5 files changed, 18 insertions(+), 9 deletions(-) > > > > > > diff --git a/xen/arch/arm/arm64/asm-offsets.c b/xen/arch/arm/arm64/asm-offsets.c > > > index 7949e3e..7544082 100644 > > > --- a/xen/arch/arm/arm64/asm-offsets.c > > > +++ b/xen/arch/arm/arm64/asm-offsets.c > > > @@ -39,7 +39,7 @@ void __dummy__(void) > > > OFFSET(UREGS_SP_el1, struct cpu_user_regs, sp_el1); > > > OFFSET(UREGS_ELR_el1, struct cpu_user_regs, elr_el1); > > > > > > - OFFSET(UREGS_kernel_sizeof, struct cpu_user_regs, cpsr); > > > + OFFSET(UREGS_kernel_sizeof, struct cpu_user_regs, spsr_el1); > > > DEFINE(UREGS_user_sizeof, sizeof(struct cpu_user_regs)); > > > BLANK(); > > > > > > diff --git a/xen/arch/arm/arm64/entry.S b/xen/arch/arm/arm64/entry.S > > > index 9d38088..a5fd608 100644 > > > --- a/xen/arch/arm/arm64/entry.S > > > +++ b/xen/arch/arm/arm64/entry.S > > > @@ -34,7 +34,7 @@ lr .req x30 // link register > > > mrs x22, SP_el0 > > > str x22, [x21] > > > > > > - add x21, sp, #UREGS_ELR_el1 > > > + add x21, sp, #UREGS_SP_el1 > > > mrs x22, SP_el1 > > > mrs x23, ELR_el1 > > > stp x22, x23, [x21] > > > > Honestly I think it would be much cleaner and easier to read if we saved > > sp_el1 and elr_el1 separately. > > I think stp is supposed to be faster, but I''m running on a model so I''m > not sure. Also there are weird quadword alignment constraints on theBy "weird" I really mean "double", i.e. sp must always be 16 byte aligned.> stack and stp is atomic from that PoV.Actually we aren''t actually changing sp in this particular code so that doesn''t really matter. But because the UREGS_* constants here are too large for the immediate of a str or stp we need to precalculate the offset, the choices are smth like: add x21, sp, #UREGS_ELR_el1 mrs x22, ELR_el1 str x22, [x21] add x21, sp, #UREGS_SP_el1 mrs x22, SP_el1 str x22, [x21] which is certainly clearer but does two adds (an extra arith instruction) and an extra str for two extra instructions on a hot path. So its worse even if stp had no actual benefit from doing a 16 byte store instead of 2*8 bytes, and I''m pretty sure stp will turn out to have such benefits. (yes, we could use different registers for the two sets of adds+stores and arrange for better pipelining etc, but still). The other option is: add x21, sp, #UREGS_SP_el1 mrs x22, SP_el1 mrs x23, ELR_el1 str x22, [x21] str x23, [x21,#8] which avoids the extra add but still has the extra str and the #8 offset on the second one is about as opaque as the stp thing IMHO, so it''s slower for no gain in readability. I think what we have now (the store pair) is the best option. Ian.
Stefano Stabellini
2013-Apr-18 13:30 UTC
Re: [PATCH 04/14] xen: arm: support for loading 64-bit zImage dom0
On Wed, 10 Apr 2013, Ian Campbell wrote:> On Mon, 2013-04-08 at 12:24 +0100, Stefano Stabellini wrote: > > On Tue, 12 Mar 2013, Ian Campbell wrote: > > > +static int kernel_try_zimage64_prepare(struct kernel_info *info, > > > + paddr_t addr, paddr_t size) > > > +{ > > > this function doesn''t seem very different from kernel_try_elf_prepare: > > do we really need two of them? > > The 32- and 64-bit zImage formats are completely different, different > header fields/offsets different magic numbers etc. I thnk two functions > is the way to go.OK