提交 a62cdf2e 编写于 作者: V vit9696

OcCpuLib: Implement ASM CPU frequency calculation for HSW and lower

上级 cd5bd939
......@@ -3,6 +3,7 @@ OpenCore Changelog
#### v0.6.7
- Fixed ocvalidate return code to be non-zero when issues are found
- Added `OEM` values to `PlatformInfo` in `Automatic` mode
- Improved CPU frequency calculation on Haswell and earlier
#### v0.6.6
- Added keyboard and pointer entry scroll support in OpenCanopy
......
......@@ -129,15 +129,14 @@ InternalCalculateTSCFromPMTimer (
//
STATIC UINT64 TSCFrequency = 0;
UINTN TimerAddr;
UINT16 TimerAddr;
UINTN VariableSize;
UINT64 Tsc0;
UINT64 Tsc1;
UINT64 TscTicksDelta;
UINT32 AcpiTick0;
UINT32 AcpiTick1;
UINT32 AcpiTicksDelta;
UINT32 AcpiTicksTarget;
UINT32 TimerResolution;
UINT32 AcpiTicksDuration;
BOOLEAN HasInterrupts;
EFI_TPL PrevTpl;
EFI_STATUS Status;
......@@ -169,8 +168,7 @@ InternalCalculateTSCFromPMTimer (
}
if (TSCFrequency == 0) {
TimerAddr = InternalGetPmTimerAddr (NULL);
TimerResolution = 10;
TimerAddr = (UINT16) InternalGetPmTimerAddr (NULL);
if (TimerAddr != 0) {
//
......@@ -187,63 +185,24 @@ InternalCalculateTSCFromPMTimer (
// The code below can handle overflow with AcpiTicksTarget of up to 24-bit size,
// on both available sizes of ACPI PM Timers (24-bit and 32-bit).
//
// 357954 clocks of ACPI timer (100ms)
// 357954 clocks of ACPI timer (200ms)
//
AcpiTicksTarget = V_ACPI_TMR_FREQUENCY / TimerResolution;
AcpiTicksDuration = V_ACPI_TMR_FREQUENCY / 10;
//
// Disable all events to ensure that nobody interrupts us.
//
PrevTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
HasInterrupts = SaveAndDisableInterrupts ();
AsmMeasureTicks (AcpiTicksDuration, TimerAddr, &AcpiTicksDelta, &TscTicksDelta);
if (HasInterrupts) {
EnableInterrupts ();
}
gBS->RestoreTPL (PrevTpl);
AcpiTick0 = IoRead32 (TimerAddr);
Tsc0 = AsmReadTsc ();
do {
CpuPause ();
//
// Check how many AcpiTicks have passed since we started.
//
AcpiTick1 = IoRead32 (TimerAddr);
if (AcpiTick0 <= AcpiTick1) {
//
// No overflow.
//
AcpiTicksDelta = AcpiTick1 - AcpiTick0;
} else if (AcpiTick0 - AcpiTick1 <= 0x00FFFFFF) {
//
// Overflow, 24-bit timer.
//
AcpiTicksDelta = 0x00FFFFFF - AcpiTick0 + AcpiTick1;
} else {
//
// Overflow, 32-bit timer.
//
AcpiTicksDelta = MAX_UINT32 - AcpiTick0 + AcpiTick1;
}
//
// Keep checking AcpiTicks until target is reached.
//
} while (AcpiTicksDelta < AcpiTicksTarget);
Tsc1 = AsmReadTsc ();
//
// On some systems we may end up waiting for notably longer than 100ms,
// despite disabling all events. Divide by actual time passed as suggested
// by asava's Clover patch r2668.
//
TSCFrequency = DivU64x32 (
MultU64x32 (Tsc1 - Tsc0, V_ACPI_TMR_FREQUENCY), AcpiTicksDelta
MultU64x32 (TscTicksDelta, V_ACPI_TMR_FREQUENCY), AcpiTicksDelta
);
//
// Restore to normal TPL.
//
gBS->RestoreTPL (PrevTpl);
}
}
......
/** @file
Copyright (C) 2020, vit9696. All rights reserved.
All rights reserved.
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "OcCpuInternals.h"
#include <Library/BaseLib.h>
#include <Library/IoLib.h>
VOID
EFIAPI
AsmMeasureTicks (
IN UINT32 AcpiTicksDuration,
IN UINT16 TimerAddr,
OUT UINT32 *AcpiTicksDelta,
OUT UINT64 *TscTicksDelta
)
{
UINT32 AcpiTick0;
UINT32 AcpiTick1;
UINT32 AcpiCurrentDelta;
UINT64 Tsc0;
UINT64 Tsc1;
AcpiTick0 = IoRead32 (TimerAddr);
Tsc0 = AsmReadTsc ();
do {
CpuPause ();
//
// Check how many AcpiTicks have passed since we started.
//
AcpiTick1 = IoRead32 (TimerAddr);
if (AcpiTick0 <= AcpiTick1) {
//
// No overflow.
//
AcpiCurrentDelta = AcpiTick1 - AcpiTick0;
} else if (AcpiTick0 - AcpiTick1 <= 0x00FFFFFF) {
//
// Overflow, 24-bit timer.
//
AcpiCurrentDelta = 0x00FFFFFF - AcpiTick0 + AcpiTick1;
} else {
//
// Overflow, 32-bit timer.
//
AcpiCurrentDelta = MAX_UINT32 - AcpiTick0 + AcpiTick1;
}
//
// Keep checking AcpiTicks until target is reached.
//
} while (AcpiCurrentDelta < AcpiTicksDuration);
Tsc1 = AsmReadTsc ();
//
// On some systems we may end up waiting for notably longer than 100ms,
// despite disabling all events. Divide by actual time passed as suggested
// by asava's Clover patch r2668.
//
*TscTicksDelta = Tsc1 - Tsc0;
*AcpiTicksDelta = AcpiCurrentDelta;
}
......@@ -41,6 +41,23 @@ AsmReadIntelMicrocodeRevision (
VOID
);
/**
Measures TSC and ACPI ticks over specified ACPI tick amount.
@param[in] AcpiTicksDuration Number of ACPI ticks for calculation.
@param[in] TimerAddr ACPI timer address.
@param[out] AcpiTicksDelta Reported ACPI ticks delta.
@param[out] TscTicksDelta Reported TSC ticks delta.
**/
VOID
EFIAPI
AsmMeasureTicks (
IN UINT32 AcpiTicksDuration,
IN UINT16 TimerAddr,
OUT UINT32 *AcpiTicksDelta,
OUT UINT64 *TscTicksDelta
);
/**
Detect Apple CPU major type.
......
......@@ -52,8 +52,10 @@
[Sources.Ia32]
Ia32/Atomic.nasm
Ia32/MeasureTicks.c
Ia32/Microcode.nasm
[Sources.X64]
X64/Atomic.nasm
X64/MeasureTicks.nasm
X64/Microcode.nasm
;------------------------------------------------------------------------------
; @file
; Copyright (C) 2020, vit9696. All rights reserved.
;
; All rights reserved.
;
; This program and the accompanying materials
; are licensed and made available under the terms and conditions of the BSD License
; which accompanies this distribution. The full text of the license may be found at
; http://opensource.org/licenses/bsd-license.php
;
; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
;------------------------------------------------------------------------------
BITS 64
DEFAULT REL
SECTION .text
;------------------------------------------------------------------------------
; VOID
; EFIAPI
; AsmMeasureTicks (
; IN UINT32 AcpiTicksDuration, ///< ecx
; IN UINT16 TimerAddr, ///< dx
; OUT UINT32 *AcpiTicksDelta, ///< r8
; OUT UINT64 *TscTicksDelta ///< r9
; );
;------------------------------------------------------------------------------
global ASM_PFX(AsmMeasureTicks)
ASM_PFX(AsmMeasureTicks):
; Push preserved registers.
push rsi
push rdi
push rbp
push rbx
; Preserve TimerAddr in r11d as rdtsc overrides edx.
mov r11d, edx
; Read AcpiTicks0 into ebx.
in eax, dx
mov ebx, eax
; Read Tsc0 into r10.
rdtsc
shl rdx, 32
or rax, rdx
mov r10, rax
; Store MAX_UINT32 - AcpiTick0 into ebp.
mov ebp, ebx
not ebp
; Store MAX_UINT24 - AcpiTick0 into edi.
mov edi, 0x00ffffff
sub edi, ebx
CalculationLoop:
nop ; or pause.
; Read AcpiTicks1 into esi.
mov edx, r11d
in eax, dx
mov esi, eax
; Calculate AcpiTicks0 - AcpiTicks1 into eax.
mov eax, ebx
sub eax, esi
jbe NoOverflow
; Check for 32-bit overflow.
cmp eax, 0x00ffffff
ja Overflow32
Overflow24:
; AcpiCurrentDelta (esi) = AcpiTicks1 (esi) + MAX_UINT24 - AcpiTick0 (edi)
add esi, edi
jmp ContinueLoop
NoOverflow:
; AcpiCurrentDelta (esi) = AcpiTicks1 (esi) - AcpiTicks0 (ebx)
sub esi, ebx
jmp ContinueLoop
Overflow32:
; AcpiCurrentDelta (esi) = AcpiTicks1 (esi) + MAX_UINT32 - AcpiTick0 (ebp)
add esi, ebp
ContinueLoop:
cmp esi, ecx
jb CalculationLoop
; Read Tsc1 into rax.
rdtsc
shl rdx, 32
or rax, rdx
; Calculate TscDelta into rax.
sub rax, r10
; Store TscDelta and AcpiDelta.
mov qword [r9], rax
mov dword [r8], esi
; Pop preserved registers & return.
pop rbx
pop rbp
pop rdi
pop rsi
ret
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册