diff --git a/xen/arch/riscv/cpufeature.c b/xen/arch/riscv/cpufeature.c index 03e27b037b..92235fdfd5 100644 --- a/xen/arch/riscv/cpufeature.c +++ b/xen/arch/riscv/cpufeature.c @@ -17,6 +17,7 @@ #include #include +#include #ifdef CONFIG_ACPI # error "cpufeature.c functions should be updated to support ACPI" @@ -139,6 +140,7 @@ const struct riscv_isa_ext_data __initconst riscv_isa_ext[] = { RISCV_ISA_EXT_DATA(smaia), RISCV_ISA_EXT_DATA(smstateen), RISCV_ISA_EXT_DATA(ssaia), + RISCV_ISA_EXT_DATA(sstc), RISCV_ISA_EXT_DATA(svade), RISCV_ISA_EXT_DATA(svpbmt), }; @@ -483,6 +485,7 @@ void __init riscv_fill_hwcap(void) unsigned int i; const size_t req_extns_amount = ARRAY_SIZE(required_extensions); bool all_extns_available = true; + unsigned long tmp; riscv_fill_hwcap_from_isa_string(); @@ -495,6 +498,21 @@ void __init riscv_fill_hwcap(void) panic("HW capabilities parsing failed: %s\n", failure_msg); } + if ( csr_read_safe(CSR_STIMECMP, &tmp) ) + { + dprintk(XENLOG_DEBUG, + "SSTC detected; supported for Xen use, but not for guests\n"); + + /* + * As there is no any guarantee that SSTC will be added to riscv,isa + * property by OpenSBI(it doesn't add it now) or whatever ran before + * Xen, it is needed to set this bit manually. + * + * Guest isolation is maintained by not setting ENVCFG_STCE in henvcfg. + */ + __set_bit(RISCV_ISA_EXT_sstc, riscv_isa); + } + for ( i = 0; i < req_extns_amount; i++ ) { const struct riscv_isa_ext_data ext = required_extensions[i]; diff --git a/xen/arch/riscv/include/asm/cpufeature.h b/xen/arch/riscv/include/asm/cpufeature.h index ef02a3e26d..0c48d57a03 100644 --- a/xen/arch/riscv/include/asm/cpufeature.h +++ b/xen/arch/riscv/include/asm/cpufeature.h @@ -38,6 +38,7 @@ enum riscv_isa_ext_id { RISCV_ISA_EXT_smaia, RISCV_ISA_EXT_smstateen, RISCV_ISA_EXT_ssaia, + RISCV_ISA_EXT_sstc, RISCV_ISA_EXT_svade, RISCV_ISA_EXT_svpbmt, RISCV_ISA_EXT_MAX diff --git a/xen/arch/riscv/include/asm/csr.h b/xen/arch/riscv/include/asm/csr.h index 27d4b7942f..888d6a2a86 100644 --- a/xen/arch/riscv/include/asm/csr.h +++ b/xen/arch/riscv/include/asm/csr.h @@ -32,6 +32,21 @@ : "memory" ); \ }) +#ifdef CONFIG_RISCV_32 +#define csr_write64(csr, val) \ +({ \ + uint64_t v_ = (val); \ + csr_write(csr, v_); \ + csr_write(csr ## H, v_ >> 32); \ +}) +#else +#define csr_write64(csr, val) \ +({ \ + csr_write(csr, val); \ + (void)csr ## H; \ +}) +#endif + #define csr_swap(csr, val) \ ({ \ unsigned long __v = (unsigned long)(val); \ diff --git a/xen/arch/riscv/include/asm/riscv_encoding.h b/xen/arch/riscv/include/asm/riscv_encoding.h index dd15731a86..03e186bcdb 100644 --- a/xen/arch/riscv/include/asm/riscv_encoding.h +++ b/xen/arch/riscv/include/asm/riscv_encoding.h @@ -395,6 +395,8 @@ #define CSR_VSCAUSE 0x242 #define CSR_VSTVAL 0x243 #define CSR_VSIP 0x244 +#define CSR_VSTIMECMP 0x24d +#define CSR_VSTIMECMPH 0x25d #define CSR_VSATP 0x280 /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */ diff --git a/xen/arch/riscv/include/asm/sbi.h b/xen/arch/riscv/include/asm/sbi.h index ed7af20028..1952868e96 100644 --- a/xen/arch/riscv/include/asm/sbi.h +++ b/xen/arch/riscv/include/asm/sbi.h @@ -13,7 +13,6 @@ #define ASM__RISCV__SBI_H #include -#include /* SBI-defined implementation ID */ #define SBI_XEN_IMPID 7 @@ -139,23 +138,6 @@ int sbi_remote_hfence_gvma(const cpumask_t *cpu_mask, vaddr_t start, int sbi_remote_hfence_gvma_vmid(const cpumask_t *cpu_mask, vaddr_t start, size_t size, unsigned long vmid); -/* - * Programs the clock for next event at (or after) stime_value. stime_value is - * in absolute time. This function must clear the pending timer interrupt bit - * as well. - * - * If the supervisor wishes to clear the timer interrupt without scheduling the - * next timer event, it can either request a timer interrupt infinitely far - * into the future (i.e., (uint64_t)-1), or it can instead mask the timer - * interrupt by clearing sie.STIE CSR bit. - * - * The stime_value parameter represents absolute time measured in ticks. - * - * This SBI call returns 0 upon success or an implementation specific negative - * error code. - */ -extern int (* __ro_after_init sbi_set_timer)(uint64_t stime_value); - /* * Initialize SBI library * diff --git a/xen/arch/riscv/include/asm/time.h b/xen/arch/riscv/include/asm/time.h index be3875b998..4d68900151 100644 --- a/xen/arch/riscv/include/asm/time.h +++ b/xen/arch/riscv/include/asm/time.h @@ -4,6 +4,7 @@ #include #include +#include #include @@ -26,6 +27,8 @@ static inline cycles_t get_cycles(void) void preinit_xen_time(void); +extern int (* __ro_after_init set_xen_timer)(uint64_t deadline); + #endif /* ASM__RISCV__TIME_H */ /* diff --git a/xen/arch/riscv/sbi.c b/xen/arch/riscv/sbi.c index b4a7ae6940..3576e26033 100644 --- a/xen/arch/riscv/sbi.c +++ b/xen/arch/riscv/sbi.c @@ -22,6 +22,7 @@ #include #include +#include static unsigned long __ro_after_init sbi_spec_version = SBI_SPEC_VERSION_DEFAULT; @@ -249,6 +250,21 @@ static int (* __ro_after_init sbi_rfence)(unsigned long fid, unsigned long arg4, unsigned long arg5); +/* + * Programs the clock for next event at (or after) stime_value. stime_value is + * in absolute time. This function must clear the pending timer interrupt bit + * as well. + * + * If the supervisor wishes to clear the timer interrupt without scheduling the + * next timer event, it can either request a timer interrupt infinitely far + * into the future (i.e., (uint64_t)-1), or it can instead mask the timer + * interrupt by clearing sie.STIE CSR bit. + * + * The stime_value parameter represents absolute time measured in ticks. + * + * This SBI call returns 0 upon success or an implementation specific negative + * error code. + */ static int cf_check sbi_set_timer_v02(uint64_t stime_value) { struct sbiret ret; @@ -264,6 +280,10 @@ static int cf_check sbi_set_timer_v02(uint64_t stime_value) return sbi_err_map_xen_errno(ret.error); } +/* + * Legacy SBI v0.1 SET_TIMER; functionally equivalent to sbi_set_timer_v02 + * from Xen's perspective. + */ static int cf_check sbi_set_timer_v01(uint64_t stime_value) { struct sbiret ret; @@ -279,8 +299,6 @@ static int cf_check sbi_set_timer_v01(uint64_t stime_value) return sbi_err_map_xen_errno(ret.error); } -int (* __ro_after_init sbi_set_timer)(uint64_t stime_value) = sbi_set_timer_v01; - int sbi_remote_sfence_vma(const cpumask_t *cpu_mask, vaddr_t start, size_t size) { @@ -360,10 +378,9 @@ int __init sbi_init(void) } if ( sbi_probe_extension(SBI_EXT_TIME) > 0 ) - { - sbi_set_timer = sbi_set_timer_v02; - dprintk(XENLOG_INFO, "SBI v0.2 TIME extension detected\n"); - } + set_xen_timer = sbi_set_timer_v02; + else + set_xen_timer = sbi_set_timer_v01; } else panic("Ooops. SBI spec version 0.1 detected. Need to add support"); diff --git a/xen/arch/riscv/time.c b/xen/arch/riscv/time.c index 698ab49d12..8769709e52 100644 --- a/xen/arch/riscv/time.c +++ b/xen/arch/riscv/time.c @@ -7,12 +7,21 @@ #include #include +#include #include -#include unsigned long __ro_after_init cpu_khz; /* CPU clock frequency in kHz. */ uint64_t __ro_after_init boot_clock_cycles; +static int cf_check sstc_set_xen_timer(uint64_t deadline) +{ + csr_write64(CSR_STIMECMP, deadline); + + return 0; +} + +int (* __ro_after_init set_xen_timer)(uint64_t deadline); + s_time_t get_s_time(void) { uint64_t ticks = get_cycles() - boot_clock_cycles; @@ -61,20 +70,7 @@ int reprogram_timer(s_time_t timeout) if ( deadline <= now ) return 0; - /* - * TODO: When the SSTC extension is supported, it would be preferable to - * use the supervisor timer registers directly here for better - * performance, since an SBI call and mode switch would no longer - * be required. - * - * This would also reduce reliance on a specific SBI implementation. - * For example, it is not ideal to panic() if sbi_set_timer() returns - * a non-zero value. Currently it can return 0 or -ENOSUPP, and - * without SSTC we still need an implementation because only the - * M-mode timer is available, and it can only be programmed in - * M-mode. - */ - if ( (rc = sbi_set_timer(deadline)) ) + if ( (rc = set_xen_timer(deadline)) ) panic("%s: timer wasn't set because: %d\n", __func__, rc); /* Enable timer interrupt */ @@ -91,4 +87,20 @@ void __init preinit_xen_time(void) panic("%s: ACPI isn't supported\n", __func__); boot_clock_cycles = get_cycles(); + + /* set_xen_timer must have been set by sbi_init() already */ + ASSERT(set_xen_timer); + + if ( riscv_isa_extension_available(NULL, RISCV_ISA_EXT_sstc) ) + { + set_xen_timer = sstc_set_xen_timer; + + /* + * A VS-timer interrupt becomes pending whenever the value of + * (time + htimedelta) is greater than or equal to vstimecmp CSR. + * Thereby to avoid spurious VS-timer irqs set vstimecmp CSR to + * ULONG_MAX. + */ + csr_write64(CSR_STIMECMP, ULONG_MAX); + } } diff --git a/xen/arch/riscv/vtimer.c b/xen/arch/riscv/vtimer.c index afd8a53a73..d5a8dfcb2e 100644 --- a/xen/arch/riscv/vtimer.c +++ b/xen/arch/riscv/vtimer.c @@ -4,6 +4,7 @@ #include #include +#include #include static void vtimer_expired(void *data)