From nobody Sun Apr 12 22:43:29 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1775835949; cv=none; d=zohomail.com; s=zohoarc; b=DIYOd+jq5jCOnqnxpCUSZWCsLMzuUkLfe7uVQC4dNV0x6Kbl6BnhhqTWkOwOHUNO30K2b6WnGv0pcMIzA8hsgHpCKpP487DVpStmMuH0BdG3ygxIyJW39qNIDRmiyp9RkWVuq5Sd84bl0BwqYVx4K21jkC47fsyGYRKg3Px/UA8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1775835949; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=92qdXREBVwsG+a0SGoPjpWEPYqqewbVtYm4T62FIQ3Y=; b=byORbgtLT2zfBMkpGmipzgxh0smOsjRfypmyAOeOf3UNUnKGnuGbXw68du6AMiDMd9StMsgpaSpA74iLL6q0mvl6IupbYTxgVils22Woawzf7+VykMQ3DJ9ThWaQxAgl7LLN7AYs7Fd5jUeaIOzAJIwIPzKkExOd1o8yY7QxnWg= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1775835949815849.3845731523586; Fri, 10 Apr 2026 08:45:49 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1279396.1563824 (Exim 4.92) (envelope-from ) id 1wBE2v-0004uJ-IH; Fri, 10 Apr 2026 15:45:25 +0000 Received: by outflank-mailman (output) from mailman id 1279396.1563824; Fri, 10 Apr 2026 15:45:25 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wBE2v-0004uC-FB; Fri, 10 Apr 2026 15:45:25 +0000 Received: by outflank-mailman (input) for mailman id 1279396; Fri, 10 Apr 2026 15:45:24 +0000 Received: from mx.expurgate.net ([195.190.135.10]) by lists.xenproject.org with esmtp (Exim 4.92) id 1wBE2u-0004u6-8R for xen-devel@lists.xenproject.org; Fri, 10 Apr 2026 15:45:24 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wBE2t-009K4U-KT for xen-devel@lists.xenproject.org; Fri, 10 Apr 2026 17:45:23 +0200 Received: from [10.42.69.3] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 69d91b00-bab6-0a2a0a5309dd-0a2a4503b300-48 for ; Fri, 10 Apr 2026 17:45:23 +0200 Received: from [209.85.128.51] (helo=mail-wm1-f51.google.com) by tlsNG-33051d.mxtls.expurgate.net with ESMTPS (eXpurgate 4.56.0) (envelope-from ) id 69d91b13-02b3-0a2a45030019-d1558033d46b-3 for ; Fri, 10 Apr 2026 17:45:23 +0200 Received: by mail-wm1-f51.google.com with SMTP id 5b1f17b1804b1-4852a9c6309so21049325e9.0 for ; Fri, 10 Apr 2026 08:45:23 -0700 (PDT) Received: from fedora (user-109-243-69-121.play-internet.pl. [109.243.69.121]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-488d58a8445sm77111195e9.6.2026.04.10.08.45.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Apr 2026 08:45:22 -0700 (PDT) X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=20251104 header.d=gmail.com header.i="@gmail.com" header.h="Content-Transfer-Encoding:MIME-Version:Message-ID:Date:Subject:Cc:To:From" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1775835923; x=1776440723; darn=lists.xenproject.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=92qdXREBVwsG+a0SGoPjpWEPYqqewbVtYm4T62FIQ3Y=; b=eL9rg+y53pajxd9Lvfi9yQXdtJchUuCyuXn1DvtbdRnEOe7PgEtPtz6pLlESVcLHPI y1R0uSWUDQi6Ef/KuHM2nAI1DiUcjAQOfVgDedntv/E2UiOE5Qx/b4N2nJf0LZ5cLrbK ja3HPaJ7u+n3XPENjiXIhLm13PmA2l+RzKc/tQBaOFoVXXzu65bVkiDk5XsDXy/ahtIL E4f5UO4swk0qjBkqUyaxRq5OIaqELYVYjEhUGn19CEONcqRJiZ3lC7vv7BLxqyb7u8/3 rZnC/0Xmpvu1f/+icviFbRfDsDYS6IcgMWA0SIdQhTXtOjMy8KjaOt/uQ1eYvj1dQx5M ZSVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775835923; x=1776440723; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=92qdXREBVwsG+a0SGoPjpWEPYqqewbVtYm4T62FIQ3Y=; b=lvLgOYPRH2dHDvxxxj7CYFWCv1ZnSRpAozYnrDtk05Gd1Q8/NpK/z7nGatjMCmwi6C EYeuFE9K6pbgxmK8Ev6bw7YXC+sso7UHPvvzgsaJtaMS1584d5bVUpUlPlsy3uY7cxzd l8GWbmUHjoS+e9FSOtY+pfMGoBT0uDIhITLQaKwbvG2pTzvPYjmOIWE5qysQuNaRHpJm kPoC9ODNqFJtcVXm1hro4NCEq/c0ywDevV5AFpENmhC8/WpibKQDif6Nb+VnxqC1rO2d bfc/ipYJpG4gvxAm31dBtVIjp2yE3wrLvtQiEMt7nug2mOe1ZdhlTuormVblyBA1bSeE tBXg== X-Gm-Message-State: AOJu0YwAtqSWnkdFRkeb8OAXg5RYirMg4UfM1MmDpeizpAAa37+c6aSq 2PCNQVjNAk52xfllxEYcgxmOjaiATlqYkNhPiDrj6wjayiE2a68VHOTm8KJaRQ== X-Gm-Gg: AeBDies/dmz7DqYl1Hwd942MeSQylK34PbygMNuFM0vuHTsmP1JnNFfz/hqDQipsapp 6DOuzaIg91e2IgSC9SFeWCDAn4aDhok7iYLjIyFUAN3S9ngJyVzeGxn9XSE0VPypzftMrNQHr2T alOOnufkHlBERTjKTAZXGRxrmN1Edt85jzbJd8JZ2mK1RGLudR4HpB5+IgJrhj01n6JpJBXq+5x yAdqcLbYwyKKlfeFHMkVnvyl62LkLHEyp5mPKmIY7aTveHYZU30gxdUN0VBVbB1l0w4uJ5z1Ua1 GHxEisAofPVeD/X5BKlo4t0ao7AJ5fyAWOMsD4eXyFGcSXqNOC5PzwjW4KXHkHRsdO31lxZuClK 2x+zwLVovmecKAuRDopcCYAoV2SE8X1c44+Xd8EomexlkCdBVZbh1D4fVZ4g9dAFu6rxjmq0gIU aaLFj+4mqAAnu6EtXAuxoZTvEHwdmBq88S6BBHlYiJGfOZeyH40aAUvnSKrRNDEaEt0A== X-Received: by 2002:a05:600d:d:b0:485:ae14:8191 with SMTP id 5b1f17b1804b1-488d67b8da2mr38326035e9.5.1775835922606; Fri, 10 Apr 2026 08:45:22 -0700 (PDT) From: Oleksii Kurochko To: xen-devel@lists.xenproject.org Cc: Romain Caritey , Oleksii Kurochko , Alistair Francis , Connor Davis , Andrew Cooper , Anthony PERARD , Michal Orzel , Jan Beulich , Julien Grall , =?UTF-8?q?Roger=20Pau=20Monn=C3=A9?= , Stefano Stabellini Subject: [PATCH] xen/riscv: allow Xen to use SSTC while hiding it from guests Date: Fri, 10 Apr 2026 17:45:12 +0200 Message-ID: X-Mailer: git-send-email 2.53.0 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-purgate-ID: tlsNG-33051d/1775835923-41914C9A-FA4B47EF/10/73395122804 X-purgate-type: spam X-purgate-size: 13274 X-ZohoMail-DKIM: pass (identity @gmail.com) X-ZM-MESSAGEID: 1775835951673154100 Content-Type: text/plain; charset="utf-8" OpenSBI currently does not advertise the SSTC extension via the device tree, so if SSTC support is detected by Xen the riscv_isa bitmap is updated manually. Furthermore, removing the "sstc" string from riscv,isa is not a reliable way to disable SSTC, because OpenSBI probes support by attempting to access CSR_STIMECMP. Introduce a runtime probe in Xen to determine whether SSTC is available. The probe attempts to read CSR_STIMECMP using csr_read_safe(). If the access succeeds, SSTC is considered available; if a trap occurs, it is treated as unsupported. When SSTC is detected, Xen may use it internally to program timers. However, the extension is not exposed to guests because the required context switch handling for the SSTC CSRs is not yet implemented. Note: clearing RISCV_ISA_EXT_sstc from the DTS riscv,isa property is deferred to a follow-up patch. Also, the corresponding HENVCFG bit is not set so guests fall back to the SBI timer interface. Timer requests are then handled by Xen via the usual SBI interception path. Introduce set_xen_timer() to abstract how the timer is programmed, either via the SSTC extension or an SBI call. Drop sbi_set_timer() as it is more than enough to have only introduced set_xen_timer(). Drop "SBI v0.2 TIME extension detected" message to avoid confusion which set timer function is really used. Signed-off-by: Oleksii Kurochko --- CI tests: https://gitlab.com/xen-project/people/olkur/xen/-/pipelines/24377= 72678 Also, I've manually ran QEMU with SSTC=3Don/off and built Xen with a newer = RISC-V compileer (in comparison with the version used by CI's docker container) to verify CONFIG_CC_HAS_ASM_GOTO_OUTPUT branch inside csr_read_safe(). --- Changes in v3: - Reword print message when SSTC extension is detected. - s/__clear_bit/__set_bit() for the case when SSTC is detected in riscv_fill_hwcap(). Update also the comment above __set_bit(). - Drop BUG_ON()s in vtimer.c. - s/printk/dprintk for the message: SSTC detected... - Drop sbi_set_timer global variable, it is enough just to have set_xen_ti= mer. - As we set bit in riscv_isa bitmap there is no need to use csr_read_safe(= CSR_STIMECMP) second time. - Move init of CSR_VSTIMECMP in preinit_xen_time as it looks more correct = place. - Update the commit message. --- Changes in v2: - Minor style fixes. - Drop from vcpu_csr_init() setting of SSTC bit in HENVCFG register. Add it back when SSTC for guests will be available. - Add static to set_xen_timer function pointer. - Refactor sstc_set_xen_timer(). - s/csr_allowed_read/csr_read_safe() --- xen/arch/riscv/cpufeature.c | 18 ++++++++ xen/arch/riscv/include/asm/cpufeature.h | 1 + xen/arch/riscv/include/asm/riscv_encoding.h | 2 + xen/arch/riscv/include/asm/sbi.h | 18 -------- xen/arch/riscv/include/asm/time.h | 3 ++ xen/arch/riscv/sbi.c | 29 ++++++++++--- xen/arch/riscv/time.c | 48 ++++++++++++++------- xen/arch/riscv/vtimer.c | 1 + 8 files changed, 81 insertions(+), 39 deletions(-) diff --git a/xen/arch/riscv/cpufeature.c b/xen/arch/riscv/cpufeature.c index 03e27b037be0..92235fdfd5ab 100644 --- a/xen/arch/riscv/cpufeature.c +++ b/xen/arch/riscv/cpufeature.c @@ -17,6 +17,7 @@ #include =20 #include +#include =20 #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_e= xt[] =3D { 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 =3D ARRAY_SIZE(required_extensions); bool all_extns_available =3D true; + unsigned long tmp; =20 riscv_fill_hwcap_from_isa_string(); =20 @@ -495,6 +498,21 @@ void __init riscv_fill_hwcap(void) panic("HW capabilities parsing failed: %s\n", failure_msg); } =20 + 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,i= sa + * property by OpenSBI(it doesn't add it now) or whatever ran befo= re + * Xen, it is needed to set this bit manually. + * + * Guest isolation is maintained by not setting ENVCFG_STCE in hen= vcfg. + */ + __set_bit(RISCV_ISA_EXT_sstc, riscv_isa); + } + for ( i =3D 0; i < req_extns_amount; i++ ) { const struct riscv_isa_ext_data ext =3D required_extensions[i]; diff --git a/xen/arch/riscv/include/asm/cpufeature.h b/xen/arch/riscv/inclu= de/asm/cpufeature.h index ef02a3e26d2c..0c48d57a03bb 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/riscv_encoding.h b/xen/arch/riscv/i= nclude/asm/riscv_encoding.h index dd15731a86fa..d0d60ba15e62 100644 --- a/xen/arch/riscv/include/asm/riscv_encoding.h +++ b/xen/arch/riscv/include/asm/riscv_encoding.h @@ -396,6 +396,8 @@ #define CSR_VSTVAL 0x243 #define CSR_VSIP 0x244 #define CSR_VSATP 0x280 +#define CSR_VSTIMECMP 0x24d +#define CSR_VSTIMECMPH 0x25d =20 /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */ #define CSR_HVIEN 0x608 diff --git a/xen/arch/riscv/include/asm/sbi.h b/xen/arch/riscv/include/asm/= sbi.h index ed7af200288f..1952868e963c 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 =20 #include -#include =20 /* 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); =20 -/* - * Programs the clock for next event at (or after) stime_value. stime_valu= e 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 schedulin= g 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 nega= tive - * 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 be3875b9984e..4d68900151a7 100644 --- a/xen/arch/riscv/include/asm/time.h +++ b/xen/arch/riscv/include/asm/time.h @@ -4,6 +4,7 @@ =20 #include #include +#include =20 #include =20 @@ -26,6 +27,8 @@ static inline cycles_t get_cycles(void) =20 void preinit_xen_time(void); =20 +extern int (* __ro_after_init set_xen_timer)(uint64_t deadline); + #endif /* ASM__RISCV__TIME_H */ =20 /* diff --git a/xen/arch/riscv/sbi.c b/xen/arch/riscv/sbi.c index b4a7ae6940c1..3576e26033a5 100644 --- a/xen/arch/riscv/sbi.c +++ b/xen/arch/riscv/sbi.c @@ -22,6 +22,7 @@ =20 #include #include +#include =20 static unsigned long __ro_after_init sbi_spec_version =3D SBI_SPEC_VERSION= _DEFAULT; =20 @@ -249,6 +250,21 @@ static int (* __ro_after_init sbi_rfence)(unsigned lon= g fid, unsigned long arg4, unsigned long arg5); =20 +/* + * Programs the clock for next event at (or after) stime_value. stime_valu= e 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 schedulin= g 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 nega= tive + * 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_v= alue) return sbi_err_map_xen_errno(ret.error); } =20 +/* + * 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_va= lue) return sbi_err_map_xen_errno(ret.error); } =20 -int (* __ro_after_init sbi_set_timer)(uint64_t stime_value) =3D sbi_set_ti= mer_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) } =20 if ( sbi_probe_extension(SBI_EXT_TIME) > 0 ) - { - sbi_set_timer =3D sbi_set_timer_v02; - dprintk(XENLOG_INFO, "SBI v0.2 TIME extension detected\n"); - } + set_xen_timer =3D sbi_set_timer_v02; + else + set_xen_timer =3D 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 7efa76fdbcb1..80f0e9ddae6a 100644 --- a/xen/arch/riscv/time.c +++ b/xen/arch/riscv/time.c @@ -7,12 +7,24 @@ #include #include =20 +#include #include -#include =20 unsigned long __ro_after_init cpu_khz; /* CPU clock frequency in kHz. */ uint64_t __ro_after_init boot_clock_cycles; =20 +static int cf_check sstc_set_xen_timer(uint64_t deadline) +{ + csr_write(CSR_STIMECMP, deadline); +#ifdef CONFIG_RISCV_32 + csr_write(CSR_STIMECMPH, deadline >> 32); +#endif + + return 0; +} + +int (* __ro_after_init set_xen_timer)(uint64_t deadline); + s_time_t get_s_time(void) { uint64_t ticks =3D get_cycles() - boot_clock_cycles; @@ -61,20 +73,7 @@ int reprogram_timer(s_time_t timeout) if ( deadline <=3D now ) return 0; =20 - /* - * 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 implementat= ion. - * For example, it is not ideal to panic() if sbi_set_timer() re= turns - * 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 =3D sbi_set_timer(deadline)) ) + if ( (rc =3D set_xen_timer(deadline)) ) panic("%s: timer wasn't set because: %d\n", __func__, rc); =20 /* Enable timer interrupt */ @@ -91,4 +90,23 @@ void __init preinit_xen_time(void) panic("%s: ACPI isn't supported\n", __func__); =20 boot_clock_cycles =3D 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 =3D 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_write(CSR_VSTIMECMP, ULONG_MAX); +#ifdef CONFIG_RISCV_32 + csr_write(CSR_VSTIMECMPH, ULONG_MAX); +#endif + } } diff --git a/xen/arch/riscv/vtimer.c b/xen/arch/riscv/vtimer.c index afd8a53a7387..d5a8dfcb2edb 100644 --- a/xen/arch/riscv/vtimer.c +++ b/xen/arch/riscv/vtimer.c @@ -4,6 +4,7 @@ #include #include =20 +#include #include =20 static void vtimer_expired(void *data) --=20 2.53.0