lkml.org 
[lkml]   [2020]   [Feb]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.5 090/120] KVM: arm64: Treat emulated TVAL TimerValue as a signed 32-bit integer
    Date
    From: Alexandru Elisei <alexandru.elisei@arm.com>

    commit 4a267aa707953a9a73d1f5dc7f894dd9024a92be upstream.

    According to the ARM ARM, registers CNT{P,V}_TVAL_EL0 have bits [63:32]
    RES0 [1]. When reading the register, the value is truncated to the least
    significant 32 bits [2], and on writes, TimerValue is treated as a signed
    32-bit integer [1, 2].

    When the guest behaves correctly and writes 32-bit values, treating TVAL
    as an unsigned 64 bit register works as expected. However, things start
    to break down when the guest writes larger values, because
    (u64)0x1_ffff_ffff = 8589934591. but (s32)0x1_ffff_ffff = -1, and the
    former will cause the timer interrupt to be asserted in the future, but
    the latter will cause it to be asserted now. Let's treat TVAL as a
    signed 32-bit register on writes, to match the behaviour described in
    the architecture, and the behaviour experimentally exhibited by the
    virtual timer on a non-vhe host.

    [1] Arm DDI 0487E.a, section D13.8.18
    [2] Arm DDI 0487E.a, section D11.2.4

    Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
    [maz: replaced the read-side mask with lower_32_bits]
    Signed-off-by: Marc Zyngier <maz@kernel.org>
    Fixes: 8fa761624871 ("KVM: arm/arm64: arch_timer: Fix CNTP_TVAL calculation")
    Link: https://lore.kernel.org/r/20200127103652.2326-1-alexandru.elisei@arm.com
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    virt/kvm/arm/arch_timer.c | 3 ++-
    1 file changed, 2 insertions(+), 1 deletion(-)

    --- a/virt/kvm/arm/arch_timer.c
    +++ b/virt/kvm/arm/arch_timer.c
    @@ -805,6 +805,7 @@ static u64 kvm_arm_timer_read(struct kvm
    switch (treg) {
    case TIMER_REG_TVAL:
    val = timer->cnt_cval - kvm_phys_timer_read() + timer->cntvoff;
    + val &= lower_32_bits(val);
    break;

    case TIMER_REG_CTL:
    @@ -850,7 +851,7 @@ static void kvm_arm_timer_write(struct k
    {
    switch (treg) {
    case TIMER_REG_TVAL:
    - timer->cnt_cval = kvm_phys_timer_read() - timer->cntvoff + val;
    + timer->cnt_cval = kvm_phys_timer_read() - timer->cntvoff + (s32)val;
    break;

    case TIMER_REG_CTL:

    \
     
     \ /
      Last update: 2020-02-13 16:35    [W:4.093 / U:0.076 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site