From patchwork Fri Jan 20 14:20:43 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ard Biesheuvel X-Patchwork-Id: 92086 Delivered-To: patch@linaro.org Received: by 10.140.20.99 with SMTP id 90csp39672qgi; Fri, 20 Jan 2017 06:20:54 -0800 (PST) X-Received: by 10.99.178.21 with SMTP id x21mr16955670pge.48.1484922054909; Fri, 20 Jan 2017 06:20:54 -0800 (PST) Return-Path: Received: from ml01.01.org (ml01.01.org. [198.145.21.10]) by mx.google.com with ESMTPS id u22si6988127plk.137.2017.01.20.06.20.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 20 Jan 2017 06:20:54 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) client-ip=198.145.21.10; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=pass (google.com: best guess record for domain of edk2-devel-bounces@lists.01.org designates 198.145.21.10 as permitted sender) smtp.mailfrom=edk2-devel-bounces@lists.01.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from [127.0.0.1] (localhost [IPv6:::1]) by ml01.01.org (Postfix) with ESMTP id 32B9381E9F; Fri, 20 Jan 2017 06:20:54 -0800 (PST) X-Original-To: edk2-devel@lists.01.org Delivered-To: edk2-devel@lists.01.org Received: from mail-wm0-x236.google.com (mail-wm0-x236.google.com [IPv6:2a00:1450:400c:c09::236]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id CED6181E9E for ; Fri, 20 Jan 2017 06:20:52 -0800 (PST) Received: by mail-wm0-x236.google.com with SMTP id r144so45600257wme.1 for ; Fri, 20 Jan 2017 06:20:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=g3XgqtE4/Tf1tU2Ekj3zAjRzJM8G+WUnf7louACwGCc=; b=hf8CZ6tK28rjAKt1b/DEFvFWxYxtZgcuJsT1jokv+P9Zsl4xCzBe9hmsh4sLd2pmOJ tNLNrgD3IkFZK+fZD3yjPXJ+LhlTWG3EwSVsoFvfFZ2//XfBcAiW6bLlpszSTCMhECFU vPzcZhY+qrCY6ivEQznqAe9cVBP9UwNA2RW2Q= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=g3XgqtE4/Tf1tU2Ekj3zAjRzJM8G+WUnf7louACwGCc=; b=DKUW1vwGn0F2Az9Z8gvKaBHhSMptESTFMWmskRV+9dtoCSls90SCB4PxI8PKNoQqpY +1CJ9daFU1XciAXhHjdcqrv1czRJezgXXeWb8ydS7rVTLY7qzdYCVu+ogyel4izGHNG2 Nmua2XBrwik0or7gO82GYijqDAyK7nybBbA3RMYUH09F3UPcZuAJy7eY34/TqT36krlS DTZZwMoKerJmSftUMp8QEc3d2xP8Wfw4qWWbNMmml65i10nQzLWf4QJh0qhFa6bSgIUl aI6FLeYCWTG3sHVTYCNJLISsRCQ9R+eJ9VPXQNPLbTu5ym926XQijASjsz3fjv6obR/U 63HA== X-Gm-Message-State: AIkVDXLuy8wm6tm3GCASQtENljRwinoBk+2iMvPLRhVbFnI4bIQHUcW6dJV0ID4sW43B92r4 X-Received: by 10.223.165.138 with SMTP id g10mr10006249wrc.105.1484922051177; Fri, 20 Jan 2017 06:20:51 -0800 (PST) Received: from localhost.localdomain ([160.168.254.151]) by smtp.gmail.com with ESMTPSA id g197sm6407876wmd.15.2017.01.20.06.20.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 20 Jan 2017 06:20:50 -0800 (PST) From: Ard Biesheuvel To: edk2-devel@lists.01.org Date: Fri, 20 Jan 2017 14:20:43 +0000 Message-Id: <1484922043-21762-1-git-send-email-ard.biesheuvel@linaro.org> X-Mailer: git-send-email 2.7.4 Subject: [edk2] [PATCH] ArmPkg/ArmGenericTimerVirtCounterLib: deal with broken generic timers X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: ryan.harkin@linaro.org, leif.lindholm@linaro.org, Ard Biesheuvel MIME-Version: 1.0 Errors-To: edk2-devel-bounces@lists.01.org Sender: "edk2-devel" Users of ArmGenericTimerVirtCounterLib may execute under virtualization, which implies that they may be affected by core errata of the host. Some implementations of the ARM Generic Timer are affected by errata where reads of the counter and reads or writes to the timer value may execute incorrectly when issued around the time the counter is incremented by the hardware. Since we can easily work around this without affecting performance too much, implement an unconditional workaround that compares two subsequent reads of the counter to ensure the value is correct. Note that the number for attempts should be limited to avoid breaking platforms such as QEMU with TCG emulation, since that has been observed never to return the same value from back to back reads of the counter register. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel --- Note that this patch applies on top of the patch 'ArmPkg/ArmLib: remove indirection layer from timer register accessors' that I send out earlier today. ArmPkg/Library/ArmGenericTimerVirtCounterLib/ArmGenericTimerVirtCounterLib.c | 51 ++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) -- 2.7.4 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel diff --git a/ArmPkg/Library/ArmGenericTimerVirtCounterLib/ArmGenericTimerVirtCounterLib.c b/ArmPkg/Library/ArmGenericTimerVirtCounterLib/ArmGenericTimerVirtCounterLib.c index 69a4ceb62db6..9fe673e8222c 100644 --- a/ArmPkg/Library/ArmGenericTimerVirtCounterLib/ArmGenericTimerVirtCounterLib.c +++ b/ArmPkg/Library/ArmGenericTimerVirtCounterLib/ArmGenericTimerVirtCounterLib.c @@ -70,13 +70,36 @@ ArmGenericTimerGetTimerFreq ( return ArmReadCntFrq (); } +// +// The virtual counter may be used under virtualization on a host that +// is affected by one of the various errata where reads to the counter +// register may return incorrect values when the access occurs at the exact +// time that the counter is incremented by the hardware. This affects the +// timer as well as the counter. +// So repeat the read until we get the same value twice. Unfortunately, +// platforms such as QEMU with TCG emulation (i.e., non-virtualized) appear +// never to return the same value twice, so we need to set a retry limit. +// +#define MAX_RETRIES 200 + UINTN EFIAPI ArmGenericTimerGetTimerVal ( VOID ) { - return ArmReadCntvTval (); + UINTN Result; + UINTN Tries; + + Tries = 0; + do { + // + // Keep reading until we see the same value twice in a row. See above. + // + Result = ArmReadCntvTval (); + } while (Result != ArmReadCntvTval () && ++Tries < MAX_RETRIES); + + return Result; } @@ -86,7 +109,18 @@ ArmGenericTimerSetTimerVal ( IN UINTN Value ) { - ArmWriteCntvTval (Value); + UINTN CounterVal; + UINTN Tries; + + Tries = 0; + do { + // + // Read the counter before and after the write to TVAL, to ensure that + // the write to TVAL did not involve a corrupted sample of the counter. + // + CounterVal = ArmReadCntvCt (); + ArmWriteCntvTval (Value); + } while (CounterVal != ArmReadCntvCt () && ++Tries < MAX_RETRIES); } UINT64 @@ -95,7 +129,18 @@ ArmGenericTimerGetSystemCount ( VOID ) { - return ArmReadCntvCt (); + UINT64 Result; + UINTN Tries; + + Tries = 0; + do { + // + // Keep reading until we see the same value twice in a row. See above. + // + Result = ArmReadCntvCt (); + } while (Result != ArmReadCntvCt () && ++Tries < MAX_RETRIES); + + return Result; } UINTN