From patchwork Mon Apr 12 13:30:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Anthony PERARD X-Patchwork-Id: 12198063 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-18.8 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6EFA3C433ED for ; Mon, 12 Apr 2021 13:30:45 +0000 (UTC) Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 04FBC6128B for ; Mon, 12 Apr 2021 13:30:44 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 04FBC6128B Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=citrix.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=xen-devel-bounces@lists.xenproject.org Received: from list by lists.xenproject.org with outflank-mailman.109098.208263 (Exim 4.92) (envelope-from ) id 1lVweC-0000Tu-B1; Mon, 12 Apr 2021 13:30:36 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version Received: by outflank-mailman (output) from mailman id 109098.208263; Mon, 12 Apr 2021 13:30:36 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1lVweC-0000Tl-6s; Mon, 12 Apr 2021 13:30:36 +0000 Received: by outflank-mailman (input) for mailman id 109098; Mon, 12 Apr 2021 13:30:34 +0000 Received: from all-amaz-eas1.inumbo.com ([34.197.232.57] helo=us1-amaz-eas2.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1lVweA-0000NV-JT for xen-devel@lists.xenproject.org; Mon, 12 Apr 2021 13:30:34 +0000 Received: from esa3.hc3370-68.iphmx.com (unknown [216.71.145.155]) by us1-amaz-eas2.inumbo.com (Halon) with ESMTPS id cc970c17-cdd8-4be9-b534-428bc5a2b458; Mon, 12 Apr 2021 13:30:31 +0000 (UTC) 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" X-Inumbo-ID: cc970c17-cdd8-4be9-b534-428bc5a2b458 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=citrix.com; s=securemail; t=1618234231; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=YMwvpxjol+5XMA2+kpnSOFwEAYxNgKgPugLl5J8fKTA=; b=FJQkaSMOE4ycIdPV05yuVTewO8skOu9KPGBbcDEsYNF6S7ex5EJxRnY5 UJWIt326UYclgo/kwvPh/gdKtZuCvJGr4qnyRkZuoy1Q2EVNzAD8Tmldv XhsMXpDdWiXbWVMzzMtsftMtEsgUAPM2Emnv8l90PkcQwe2Eg4t52RHlm w=; Authentication-Results: esa3.hc3370-68.iphmx.com; dkim=none (message not signed) header.i=none IronPort-SDR: cBmtvDv21tXItbUsYqKtim7utUFFFwb5H9VT4Z5BcR2sMNrSA16OQ/BWAWCqrDN+fDjGNqkknV O77ifgn/z5AwO8Si0Q6gAspg2Oyy5oIWXaeO3R8uprQkghj4DY7/crFNhPWqIOFPMIUMlYAx1S uIVNruyt7xmQa4QNeZOMgnQo0MoMmP41qxjN9McKkENtRYN4P7PXZsrxVcwqarBzNkEQFAVBr2 SiVYCKkg2vIYKfoJ/wPAxEUO9nxaGxL7GZcXXF9YKxXKp8leFauLqndfOG42IFJEX5mH/0CKSK YSw= X-SBRS: 4.0 X-MesageID: 41388431 X-Ironport-Server: esa3.hc3370-68.iphmx.com X-Remote-IP: 162.221.158.21 X-Policy: $RELAYED IronPort-HdrOrdr: A9a23:YviZnKyL9o/2HgrWLQfPKrPwr71zdoIgy1knxilNYDZ+G/b2q+ mFmvMH2RjozAsLUHY7ltyafIWGS3XQ9Zl6iLNhW4uKdg/gpWeuMcVe/ZLvqgeQfBHW2+ZB2c 5bEpRWJ8b3CTFB4PrSwA79KNo4xcnCzabAv5a9815IbSVHL55t9B14DAHzKDwTeCBjCYAiHJ SRouprzgDBRV0tYs62BmYIUoH4zrWh/q7OWhIICwUq7wODl1qTmdvHOiOVwwsEVHd3yaoimF K16jDR3LmpsP2w13bnuVP70pI+orfc4+oGIMSNj8QPQw+c6TqVWA== X-IronPort-AV: E=Sophos;i="5.82,216,1613451600"; d="scan'208";a="41388431" From: Anthony PERARD To: CC: Laszlo Ersek , Jordan Justen , Ard Biesheuvel , , Anthony PERARD , Julien Grall , =?utf-8?q?Roger_Pau_Monn=C3=A9?= Subject: [PATCH v3 6/7] OvmfPkg/XenPlatformPei: Calibrate APIC timer frequency Date: Mon, 12 Apr 2021 14:30:02 +0100 Message-ID: <20210412133003.146438-7-anthony.perard@citrix.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210412133003.146438-1-anthony.perard@citrix.com> References: <20210412133003.146438-1-anthony.perard@citrix.com> MIME-Version: 1.0 Calculate the frequency of the APIC timer that Xen provides. Even though the frequency is currently hard-coded, it isn't part of the public ABI that Xen provides and thus may change at any time. OVMF needs to determine the frequency by an other mean. Fortunately, Xen provides a way to determines the frequency of the TSC, so we can use TSC to calibrate the frequency of the APIC timer. That information is found in the shared_info page which we map and unmap once done (XenBusDxe is going to map the page somewhere else). The shared_info page is mapped at the highest physical address allowed as it doesn't need to be in the RAM, thus there's a call to update the page table. The calculated frequency is only logged in this patch, it will be used in a following patch. Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2490 Signed-off-by: Anthony PERARD Acked-by: Laszlo Ersek --- Notes: CC: Roger Pau Monné v3: - fix debug format strings - fix coding style v2: - fix CamelCases - Use U64 multiplication and division helpers - don't read TscShift from the SharedInfo page again - change the location of the shared info page to be outside of the ram - check for overflow in XenDelay - check for overflow when calculating the calculating APIC frequency OvmfPkg/XenPlatformPei/XenPlatformPei.inf | 2 + OvmfPkg/XenPlatformPei/Platform.h | 5 + OvmfPkg/XenPlatformPei/Platform.c | 1 + OvmfPkg/XenPlatformPei/Xen.c | 177 ++++++++++++++++++++++ 4 files changed, 185 insertions(+) diff --git a/OvmfPkg/XenPlatformPei/XenPlatformPei.inf b/OvmfPkg/XenPlatformPei/XenPlatformPei.inf index 8790d907d3ec..5732d2188871 100644 --- a/OvmfPkg/XenPlatformPei/XenPlatformPei.inf +++ b/OvmfPkg/XenPlatformPei/XenPlatformPei.inf @@ -52,6 +52,7 @@ [LibraryClasses] DebugLib HobLib IoLib + LocalApicLib PciLib ResourcePublicationLib PeiServicesLib @@ -59,6 +60,7 @@ [LibraryClasses] MtrrLib MemEncryptSevLib PcdLib + SafeIntLib XenHypercallLib [Pcd] diff --git a/OvmfPkg/XenPlatformPei/Platform.h b/OvmfPkg/XenPlatformPei/Platform.h index e70ca58078eb..77d88fc159d7 100644 --- a/OvmfPkg/XenPlatformPei/Platform.h +++ b/OvmfPkg/XenPlatformPei/Platform.h @@ -132,6 +132,11 @@ PhysicalAddressIdentityMapping ( IN EFI_PHYSICAL_ADDRESS AddressToMap ); +VOID +CalibrateLapicTimer ( + VOID + ); + extern EFI_BOOT_MODE mBootMode; extern UINT8 mPhysMemAddressWidth; diff --git a/OvmfPkg/XenPlatformPei/Platform.c b/OvmfPkg/XenPlatformPei/Platform.c index 717fd0ab1a45..e9511eb40c62 100644 --- a/OvmfPkg/XenPlatformPei/Platform.c +++ b/OvmfPkg/XenPlatformPei/Platform.c @@ -448,6 +448,7 @@ InitializeXenPlatform ( InitializeRamRegions (); InitializeXen (); + CalibrateLapicTimer (); if (mBootMode != BOOT_ON_S3_RESUME) { ReserveEmuVariableNvStore (); diff --git a/OvmfPkg/XenPlatformPei/Xen.c b/OvmfPkg/XenPlatformPei/Xen.c index b2a7d1c21dac..8b06bebd7731 100644 --- a/OvmfPkg/XenPlatformPei/Xen.c +++ b/OvmfPkg/XenPlatformPei/Xen.c @@ -21,8 +21,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -457,3 +459,178 @@ PhysicalAddressIdentityMapping ( return EFI_SUCCESS; } + +STATIC +EFI_STATUS +MapSharedInfoPage ( + IN VOID *PagePtr + ) +{ + xen_add_to_physmap_t Parameters; + INTN ReturnCode; + + Parameters.domid = DOMID_SELF; + Parameters.space = XENMAPSPACE_shared_info; + Parameters.idx = 0; + Parameters.gpfn = (UINTN)PagePtr >> EFI_PAGE_SHIFT; + ReturnCode = XenHypercallMemoryOp (XENMEM_add_to_physmap, &Parameters); + if (ReturnCode != 0) { + return EFI_NO_MAPPING; + } + return EFI_SUCCESS; +} + +STATIC +VOID +UnmapXenPage ( + IN VOID *PagePtr + ) +{ + xen_remove_from_physmap_t Parameters; + INTN ReturnCode; + + Parameters.domid = DOMID_SELF; + Parameters.gpfn = (UINTN)PagePtr >> EFI_PAGE_SHIFT; + ReturnCode = XenHypercallMemoryOp (XENMEM_remove_from_physmap, &Parameters); + ASSERT (ReturnCode == 0); +} + + +STATIC +UINT64 +GetCpuFreq ( + IN XEN_VCPU_TIME_INFO *VcpuTime + ) +{ + UINT32 Version; + UINT32 TscToSystemMultiplier; + INT8 TscShift; + UINT64 CpuFreq; + + do { + Version = VcpuTime->Version; + MemoryFence (); + TscToSystemMultiplier = VcpuTime->TscToSystemMultiplier; + TscShift = VcpuTime->TscShift; + MemoryFence (); + } while (((Version & 1) != 0) && (Version != VcpuTime->Version)); + + CpuFreq = DivU64x32 (LShiftU64 (1000000000ULL, 32), TscToSystemMultiplier); + if (TscShift >= 0) { + CpuFreq = RShiftU64 (CpuFreq, TscShift); + } else { + CpuFreq = LShiftU64 (CpuFreq, -TscShift); + } + return CpuFreq; +} + +STATIC +VOID +XenDelay ( + IN XEN_VCPU_TIME_INFO *VcpuTimeInfo, + IN UINT64 DelayNs + ) +{ + UINT64 Tick; + UINT64 CpuFreq; + UINT64 Delay; + UINT64 DelayTick; + UINT64 NewTick; + RETURN_STATUS Status; + + Tick = AsmReadTsc (); + + CpuFreq = GetCpuFreq (VcpuTimeInfo); + Status = SafeUint64Mult (DelayNs, CpuFreq, &Delay); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "XenDelay (%lu ns): delay too big in relation to CPU freq %lu Hz\n", + DelayNs, CpuFreq)); + ASSERT_EFI_ERROR (Status); + CpuDeadLoop (); + } + + DelayTick = DivU64x32 (Delay, 1000000000); + + NewTick = Tick + DelayTick; + + // + // Check for overflow + // + if (NewTick < Tick) { + // + // Overflow, wait for TSC to also overflow + // + while (AsmReadTsc () >= Tick) { + CpuPause (); + } + } + + while (AsmReadTsc () <= NewTick) { + CpuPause (); + } +} + + +/** + Calculate the frequency of the Local Apic Timer +**/ +VOID +CalibrateLapicTimer ( + VOID + ) +{ + XEN_SHARED_INFO *SharedInfo; + XEN_VCPU_TIME_INFO *VcpuTimeInfo; + UINT32 TimerTick, TimerTick2, DiffTimer; + UINT64 TscTick, TscTick2; + UINT64 Freq; + UINT64 Dividend; + EFI_STATUS Status; + + + SharedInfo = (VOID*)((1ULL << mPhysMemAddressWidth) - EFI_PAGE_SIZE); + Status = PhysicalAddressIdentityMapping ((EFI_PHYSICAL_ADDRESS)SharedInfo); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, + "Failed to add page table entry for Xen shared info page: %r\n", + Status)); + ASSERT_EFI_ERROR (Status); + return; + } + + Status = MapSharedInfoPage (SharedInfo); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to map Xen's shared info page: %r\n", + Status)); + ASSERT_EFI_ERROR (Status); + return; + } + + VcpuTimeInfo = &SharedInfo->VcpuInfo[0].Time; + + InitializeApicTimer (1, MAX_UINT32, TRUE, 0); + DisableApicTimerInterrupt (); + + TimerTick = GetApicTimerCurrentCount (); + TscTick = AsmReadTsc (); + XenDelay (VcpuTimeInfo, 1000000ULL); + TimerTick2 = GetApicTimerCurrentCount (); + TscTick2 = AsmReadTsc (); + + + DiffTimer = TimerTick - TimerTick2; + Status = SafeUint64Mult (GetCpuFreq (VcpuTimeInfo), DiffTimer, &Dividend); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "overflow while calculating APIC frequency\n")); + DEBUG ((DEBUG_ERROR, "CPU freq: %lu Hz; APIC timer tick count for 1 ms: %u\n", + GetCpuFreq (VcpuTimeInfo), DiffTimer)); + ASSERT_EFI_ERROR (Status); + CpuDeadLoop (); + } + + Freq = DivU64x64Remainder (Dividend, TscTick2 - TscTick, NULL); + DEBUG ((DEBUG_INFO, "APIC Freq % 8lu Hz\n", Freq)); + + UnmapXenPage (SharedInfo); +}