diff --git a/tools/golang/xenlight/helpers.gen.go b/tools/golang/xenlight/helpers.gen.go index 18ab0731ef..6ab23a708f 100644 --- a/tools/golang/xenlight/helpers.gen.go +++ b/tools/golang/xenlight/helpers.gen.go @@ -3702,6 +3702,7 @@ x.CapVpmu = bool(xc.cap_vpmu) x.CapGnttabV1 = bool(xc.cap_gnttab_v1) x.CapGnttabV2 = bool(xc.cap_gnttab_v2) x.ArchCapabilities = uint32(xc.arch_capabilities) +x.ArmClockFrequencyHz = uint32(xc.arm_clock_frequency_hz) return nil} @@ -3737,6 +3738,7 @@ xc.cap_vpmu = C.bool(x.CapVpmu) xc.cap_gnttab_v1 = C.bool(x.CapGnttabV1) xc.cap_gnttab_v2 = C.bool(x.CapGnttabV2) xc.arch_capabilities = C.uint32_t(x.ArchCapabilities) +xc.arm_clock_frequency_hz = C.uint32_t(x.ArmClockFrequencyHz) return nil } diff --git a/tools/golang/xenlight/types.gen.go b/tools/golang/xenlight/types.gen.go index 3d3bcc1382..39bf9962d1 100644 --- a/tools/golang/xenlight/types.gen.go +++ b/tools/golang/xenlight/types.gen.go @@ -1150,6 +1150,7 @@ CapVpmu bool CapGnttabV1 bool CapGnttabV2 bool ArchCapabilities uint32 +ArmClockFrequencyHz uint32 } type Connectorinfo struct { diff --git a/tools/include/xen-tools/arm-arch-capabilities.h b/tools/include/xen-tools/arm-arch-capabilities.h index 21e3c73bd1..a927bc4703 100644 --- a/tools/include/xen-tools/arm-arch-capabilities.h +++ b/tools/include/xen-tools/arm-arch-capabilities.h @@ -46,4 +46,14 @@ bool arch_capabilities_arm_gic_v3(unsigned int arch_capabilities) #endif } +static inline +bool arch_capabilities_arm_timer_dt_freq(unsigned int arch_capabilities) +{ +#if defined(__arm__) || defined(__aarch64__) + return MASK_EXTR(arch_capabilities, XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ); +#else + return false; +#endif +} + #endif /* ARM_ARCH_CAPABILITIES_H */ diff --git a/tools/libs/light/libxl.c b/tools/libs/light/libxl.c index a1fe16274d..98c7f0fdb3 100644 --- a/tools/libs/light/libxl.c +++ b/tools/libs/light/libxl.c @@ -410,6 +410,7 @@ int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo) physinfo->cap_gnttab_v2 = !!(xcphysinfo.capabilities & XEN_SYSCTL_PHYSCAP_gnttab_v2); physinfo->arch_capabilities = xcphysinfo.arch_capabilities; + physinfo->arm_clock_frequency_hz = xcphysinfo.arm_clock_frequency_hz; GC_FREE; return 0; diff --git a/tools/libs/light/libxl_arm.c b/tools/libs/light/libxl_arm.c index b9c0c820d6..47b662ea5c 100644 --- a/tools/libs/light/libxl_arm.c +++ b/tools/libs/light/libxl_arm.c @@ -252,6 +252,16 @@ int libxl__arch_domain_save_config(libxl__gc *gc, libxl__domain_build_state *state, const struct xen_domctl_createdomain *config) { + libxl_physinfo info; + int rc; + + libxl_physinfo_init(&info); + rc = libxl_get_physinfo(CTX, &info); + if (rc) { + LOG(ERROR, "failed to get physinfo"); + goto out; + } + switch (config->arch.gic_version) { case XEN_DOMCTL_CONFIG_GIC_V2: d_config->b_info.arch_arm.gic_version = LIBXL_GIC_VERSION_V2; @@ -261,12 +271,25 @@ int libxl__arch_domain_save_config(libxl__gc *gc, break; default: LOG(ERROR, "Unexpected gic version %u", config->arch.gic_version); - return ERROR_FAIL; + rc = ERROR_FAIL; + goto out; } - state->clock_frequency = config->arch.clock_frequency; + /* + * Pass the timer frequency on to the guest DT only when Xen took it from + * the host DT (XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ). Otherwise the guest + * gets the right value from CNTFRQ_EL0. + */ + if (arch_capabilities_arm_timer_dt_freq(info.arch_capabilities)) + state->clock_frequency = info.arm_clock_frequency_hz; + else + state->clock_frequency = 0; - return 0; + rc = 0; +out: + libxl_physinfo_dispose(&info); + + return rc; } int libxl__arch_domain_create(libxl__gc *gc, diff --git a/tools/libs/light/libxl_types.idl b/tools/libs/light/libxl_types.idl index 27755801d1..ce697303b6 100644 --- a/tools/libs/light/libxl_types.idl +++ b/tools/libs/light/libxl_types.idl @@ -1202,6 +1202,7 @@ libxl_physinfo = Struct("physinfo", [ ("cap_gnttab_v1", bool), ("cap_gnttab_v2", bool), ("arch_capabilities", uint32), + ("arm_clock_frequency_hz", uint32), ], dir=DIR_OUT) libxl_connectorinfo = Struct("connectorinfo", [ diff --git a/tools/ocaml/libs/xc/xenctrl.ml b/tools/ocaml/libs/xc/xenctrl.ml index 147afa62c2..582897af6d 100644 --- a/tools/ocaml/libs/xc/xenctrl.ml +++ b/tools/ocaml/libs/xc/xenctrl.ml @@ -32,7 +32,6 @@ type xen_arm_arch_domainconfig = { gic_version: int; nr_spis: int; - clock_frequency: int32; } type x86_arch_emulation_flags = diff --git a/tools/ocaml/libs/xc/xenctrl.mli b/tools/ocaml/libs/xc/xenctrl.mli index 9fccb2c2c2..9414b87164 100644 --- a/tools/ocaml/libs/xc/xenctrl.mli +++ b/tools/ocaml/libs/xc/xenctrl.mli @@ -26,7 +26,6 @@ type vcpuinfo = { type xen_arm_arch_domainconfig = { gic_version: int; nr_spis: int; - clock_frequency: int32; } type x86_arch_emulation_flags = diff --git a/tools/ocaml/libs/xc/xenctrl_stubs.c b/tools/ocaml/libs/xc/xenctrl_stubs.c index 4a45a31c28..180f2fbf45 100644 --- a/tools/ocaml/libs/xc/xenctrl_stubs.c +++ b/tools/ocaml/libs/xc/xenctrl_stubs.c @@ -449,13 +449,10 @@ static value alloc_domaininfo(xc_domaininfo_t * info) tag = 0; /* tag ARM */ /* xen_arm_arch_domainconfig */ - arch_config = caml_alloc_tuple(3); + arch_config = caml_alloc_tuple(2); Field(arch_config, 0) = Val_int(info->arch_config.gic_version); Field(arch_config, 1) = Val_int(info->arch_config.nr_spis); - tmp = caml_copy_int32(info->arch_config.clock_frequency); - Field(arch_config, 2) = tmp; - #elif defined(__i386__) || defined(__x86_64__) tag = 1; /* tag x86 */ diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 5678ee3fe0..4ca3a3749f 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -714,7 +714,7 @@ int arch_domain_create(struct domain *d, if ( (rc = domain_vgic_init(d, config->arch.nr_spis)) != 0 ) goto fail; - if ( (rc = domain_vtimer_init(d, &config->arch)) != 0 ) + if ( (rc = domain_vtimer_init(d)) != 0 ) goto fail; if ( (rc = tee_domain_init(d, config->arch.tee_type)) != 0 ) diff --git a/xen/arch/arm/include/asm/time.h b/xen/arch/arm/include/asm/time.h index c194dbb9f5..fd79dd31eb 100644 --- a/xen/arch/arm/include/asm/time.h +++ b/xen/arch/arm/include/asm/time.h @@ -87,10 +87,11 @@ enum timer_ppi }; /* - * Value of "clock-frequency" in the DT timer node if present. - * 0 means the property doesn't exist. + * The timer frequency, in Hz, that Xen ended up using, and whether it came + * from the DT "clock-frequency" property rather than CNTFRQ_EL0. */ -extern uint32_t timer_dt_clock_frequency; +extern uint32_t timer_clock_frequency_hz; +extern bool timer_clock_frequency_from_dt; /* Get one of the timer IRQ number */ unsigned int timer_get_irq(enum timer_ppi ppi); diff --git a/xen/arch/arm/include/asm/vtimer.h b/xen/arch/arm/include/asm/vtimer.h index 9d4fb4c6e8..6bbfcf4e69 100644 --- a/xen/arch/arm/include/asm/vtimer.h +++ b/xen/arch/arm/include/asm/vtimer.h @@ -20,8 +20,7 @@ #ifndef __ARCH_ARM_VTIMER_H__ #define __ARCH_ARM_VTIMER_H__ -extern int domain_vtimer_init(struct domain *d, - struct xen_arch_domainconfig *config); +extern int domain_vtimer_init(struct domain *d); extern int vcpu_vtimer_init(struct vcpu *v); extern bool vtimer_emulate(struct cpu_user_regs *regs, union hsr hsr); extern void virt_timer_save(struct vcpu *v); diff --git a/xen/arch/arm/sysctl.c b/xen/arch/arm/sysctl.c index 8de4027b9c..cc42d1b532 100644 --- a/xen/arch/arm/sysctl.c +++ b/xen/arch/arm/sysctl.c @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -26,6 +27,10 @@ void arch_do_physinfo(struct xen_sysctl_physinfo *pi) pi->arch_capabilities |= MASK_INSR(sve_encode_vl(get_sys_vl_len()), XEN_SYSCTL_PHYSCAP_ARM_SVE_MASK); + pi->arm_clock_frequency_hz = timer_clock_frequency_hz; + if ( timer_clock_frequency_from_dt ) + pi->arch_capabilities |= XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ; + switch ( gic_hw_version() ) { case GIC_V2: diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c index ccfb76e20f..295afa685a 100644 --- a/xen/arch/arm/time.c +++ b/xen/arch/arm/time.c @@ -35,7 +35,8 @@ uint64_t __read_mostly boot_count; * register-mapped time source in the SoC. */ unsigned long __read_mostly cpu_khz; /* CPU clock frequency in kHz. */ -uint32_t __read_mostly timer_dt_clock_frequency; +uint32_t __read_mostly timer_clock_frequency_hz; +bool __read_mostly timer_clock_frequency_from_dt; static unsigned int timer_irq[MAX_TIMER_PPI]; @@ -130,7 +131,8 @@ static void __init preinit_dt_xen_time(void) { cpu_khz = DIV_ROUND(rate, 1000); validate_timer_frequency(); - timer_dt_clock_frequency = rate; + timer_clock_frequency_hz = rate; + timer_clock_frequency_from_dt = true; } } @@ -146,7 +148,8 @@ void __init preinit_xen_time(void) if ( !cpu_khz ) { - cpu_khz = DIV_ROUND(READ_SYSREG(CNTFRQ_EL0) & CNTFRQ_MASK, 1000); + timer_clock_frequency_hz = READ_SYSREG(CNTFRQ_EL0) & CNTFRQ_MASK; + cpu_khz = DIV_ROUND(timer_clock_frequency_hz, 1000); validate_timer_frequency(); } diff --git a/xen/arch/arm/vtimer.c b/xen/arch/arm/vtimer.c index 2e85ff2b6e..18f5676158 100644 --- a/xen/arch/arm/vtimer.c +++ b/xen/arch/arm/vtimer.c @@ -52,7 +52,7 @@ static void virt_timer_expired(void *data) perfc_incr(vtimer_virt_inject); } -int domain_vtimer_init(struct domain *d, struct xen_arch_domainconfig *config) +int domain_vtimer_init(struct domain *d) { d->arch.virt_timer_base.offset = get_cycles(); d->arch.virt_timer_base.nanoseconds = @@ -60,8 +60,6 @@ int domain_vtimer_init(struct domain *d, struct xen_arch_domainconfig *config) d->time_offset.seconds = d->arch.virt_timer_base.nanoseconds; do_div(d->time_offset.seconds, 1000000000); - config->clock_frequency = timer_dt_clock_frequency; - /* * Per the ACPI specification, providing a secure EL1 timer * interrupt is optional and will be ignored by non-secure OS. diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h index 44c26fdc38..5d15f572c7 100644 --- a/xen/include/public/arch-arm.h +++ b/xen/include/public/arch-arm.h @@ -343,20 +343,6 @@ struct xen_arch_domainconfig { uint16_t tee_type; /* IN */ uint32_t nr_spis; - /* - * OUT - * Based on the property clock-frequency in the DT timer node. - * The property may be present when the bootloader/firmware doesn't - * set correctly CNTFRQ which hold the timer frequency. - * - * As it's not possible to trap this register, we have to replicate - * the value in the guest DT. - * - * = 0 => property not present - * > 0 => Value of the property - * - */ - uint32_t clock_frequency; /* IN */ uint8_t arm_sci_type; /* IN */ diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 510300bb67..4ca8a2d7ca 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -30,9 +30,9 @@ * fields) don't require a change of the version. * Stable ops are NOT covered by XEN_DOMCTL_INTERFACE_VERSION! * - * Last version bump: Xen 4.22 + * Last version bump: Xen 4.23 */ -#define XEN_DOMCTL_INTERFACE_VERSION 0x00000018 +#define XEN_DOMCTL_INTERFACE_VERSION 0x00000019 /* * NB. xen_domctl.domain is an IN/OUT parameter for this operation. diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h index a1216d7287..6f9b1624ad 100644 --- a/xen/include/public/sysctl.h +++ b/xen/include/public/sysctl.h @@ -108,6 +108,8 @@ struct xen_sysctl_tbuf_op { #define XEN_SYSCTL_PHYSCAP_ARM_SVE_MASK (0x1FU) #define XEN_SYSCTL_PHYSCAP_ARM_GIC_V2 (1U << 5) #define XEN_SYSCTL_PHYSCAP_ARM_GIC_V3 (1U << 6) +/* See arm_clock_frequency_hz in struct xen_sysctl_physinfo. */ +#define XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ (1U << 7) #endif struct xen_sysctl_physinfo { @@ -120,7 +122,23 @@ struct xen_sysctl_physinfo { uint32_t cpu_khz; uint32_t capabilities;/* XEN_SYSCTL_PHYSCAP_??? */ uint32_t arch_capabilities;/* XEN_SYSCTL_PHYSCAP_{X86,ARM,...}_??? */ - uint32_t pad; + + /* + * ARM only. The timer frequency, in Hz, that Xen is using, taken either + * from the host DT timer node's "clock-frequency" property or from a + * direct CNTFRQ_EL0 read. + * + * XEN_SYSCTL_PHYSCAP_ARM_TIMER_DT_FREQ is set in the former case. The host + * DT overrides CNTFRQ_EL0 (the usual way a wrong bootloader/firmware value + * is corrected), so the toolstack must carry the same override into the + * guest's timer node, since CNTFRQ_EL0 cannot be trapped and fixed up per + * guest. + * + * = 0 => Non-ARM. On ARM the frequency is validated at boot and is + * always non-zero. + * > 0 => The frequency, in Hz. + */ + uint32_t arm_clock_frequency_hz; uint64_aligned_t total_pages; uint64_aligned_t free_pages; uint64_aligned_t scrub_pages;