-
Notifications
You must be signed in to change notification settings - Fork 45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ART Frequency, CPU Frequency and Clock Drift #448
Comments
Cpu->CPUFrequency = MultU64x32 (BASE_ART_CLOCK_SOURCE, (UINT32) DivU64x32 (CpuidEbx, CpuidEax)); with Cpu->CPUFrequency = MultThenDivU64x64x32 (BASE_ART_CLOCK_SOURCE, CpuidEbx, CpuidEax); You will need to use this function (taken from PciRootBridge.c). /**
Return the result of (Multiplicand * Multiplier / Divisor).
@param Multiplicand A 64-bit unsigned value.
@param Multiplier A 64-bit unsigned value.
@param Divisor A 32-bit unsigned value.
@param Remainder A pointer to a 32-bit unsigned value. This parameter is
optional and may be NULL.
@return Multiplicand * Multiplier / Divisor.
**/
UINT64
MultThenDivU64x64x32 (
IN UINT64 Multiplicand,
IN UINT64 Multiplier,
IN UINT32 Divisor,
OUT UINT32 *Remainder OPTIONAL
)
{
UINT64 Uint64;
UINT32 LocalRemainder;
UINT32 Uint32;
if (Multiplicand > DivU64x64Remainder (MAX_UINT64, Multiplier, NULL)) {
//
// Make sure Multiplicand is the bigger one.
//
if (Multiplicand < Multiplier) {
Uint64 = Multiplicand;
Multiplicand = Multiplier;
Multiplier = Uint64;
}
//
// Because Multiplicand * Multiplier overflows,
// Multiplicand * Multiplier / Divisor
// = (2 * Multiplicand' + 1) * Multiplier / Divisor
// = 2 * (Multiplicand' * Multiplier / Divisor) + Multiplier / Divisor
//
Uint64 = MultThenDivU64x64x32 (RShiftU64 (Multiplicand, 1), Multiplier, Divisor, &LocalRemainder);
Uint64 = LShiftU64 (Uint64, 1);
Uint32 = 0;
if ((Multiplicand & 0x1) == 1) {
Uint64 += DivU64x32Remainder (Multiplier, Divisor, &Uint32);
}
return Uint64 + DivU64x32Remainder (Uint32 + LShiftU64 (LocalRemainder, 1), Divisor, Remainder);
} else {
return DivU64x32Remainder (MultU64x64 (Multiplicand, Multiplier), Divisor, Remainder);
}
} |
Hmm... are you sure? The numbers from the calculation are fortunately in
the log (kudos to whoever did that!). 240000000*240/2 isn’t going to
overflow at the multiplication step nor is the division fractional. I don’t
think order of operations is going to matter at all unless I’m missing
something?
|
I haven’t studied the rest of the code but looking at the XNU source you
linked, they are setting the TSC frequency based on that calculation, not
the CPU frequency. Maybe that’s the issue?
|
I see now the values, and they look crazy. Let me clarify things a little though, because there is a lot of confusion here in addition to code being somewhat wrong as well. XNU kernel expects us pass up to two parameters
Notes for OpenCore
So basically there should be an equation:
After the refactoring the names and fixing
So, while this makes things very ugly for us, it should still be doable:
It will be great if you could prepare a draft patch as we do not have the hardware to properly test the changes. Thanks! |
Wow, thanks for the very detailed explanation and the deep dive! I’ll get
started on a patch and should have something for you later on today.
|
Made a draft of the changes and tested it on my setup. |
Thanks, replied in the pull request! |
Alright, this is now merged in master, and I also ensured that ARTFrequency is properly passed to the system when it is different from 24 MHz. Please report that everything works fine and close this issue. Thanks a lot for your help & patience! |
Seems to be working! I'll keep an eye on long-term clock drift, as it may be an unrelated issue. |
After a longer evaluation, the system clock is now running slower than realtime. It drifted about 2 minutes behind over 24 hours. Any suggestions for where to start looking? I can file a separate issue for it and work on a patch. |
Hmmm, that is likely a bug in XNU. I really wonder whether XNU is can work with 25 MHz crystal clock. Could you try leaving 24 MHz |
I'll give it a try and let you know. |
@mrmiller I reopened this. Any news on the matter? |
Yes, ran for long stretches with the lines commented out. Is there any way to verify from the OS what I’m seeing the same drift, with the system clocking running about 2 min/day slower than real-time. This seems to be the same as with those lines in place. This behavior is slightly different from before any of these changes, though, where I believe the clock was running faster than real-time, and at a faster rate. |
Currently we have a belief that |
Actually, I think this is relevant:
|
Confirmed that whether
Those numbers do seem to line up with the drift I'm seeing. Do you think there's a solution at this point or just out of luck? |
Well, it will work fine if you set ARTFrequency to 24937500 (25 MHz - 0.25%) or calculate it from measured TSCFrequency. Currently I am a bit at a loss how actually we can workaround this design wise. My primary thought is that we can measure ARTFrequency just like TSCFrequency on Xeon W Server, but the question is, does it only apply to Xeon W Server or more CPUs as the patch description is not perfectly clear, and I cannot find any reference for that "EMI reduction circuit". I will try looking for more information this week, let me know if you find anything else as well. Also check the |
Ok, I googled a bit more, and it looks like this thing is configurable. Have a look on the bugreport preceding the hardcoded frequency removal: There is a reference to spread spectrum state in BIOS, which I believe can be related to this optin description: Could you please check your firmware settings and look for something similar? |
Hmm... that's very interesting. It seems like they settled on basing it off the TSC timer instead of hard-coding the 25 Mhz. I should probably see what value that gets and if it's close to the 25 Mhz - 0.25% value.
I think that particular clock spread spectrum is specific to memory timing; maybe we're looking for a different clock spread spectrum? Same principle and motivation, presumably. I found some spread spectrum settings in my BIOS ROM but they're all hidden so I'll modify that and give it a spin. Given the Linux kernel's approach, though, I wonder if it's worth modifying our approach to filling For our purposes, I'm proposing modifying step 4 from our original scheme:
Instead, we should calculate
It's in the ballpark of that estimated -0.25% spread spectrum hit. I've got this patch mocked up so I'll give it a spin tomorrow and see how it holds up. |
I believe that the exact option I found is likely to be different, but I expect this to be named similarly if it exists. Let me know whether the options you found actually do anything. It is probably relatively easy to test them by measuring TSC. I do not like the idea of measuring ARTFrequency through TSC, but I do like the idea of not using However, there are two issues here:
This situation makes it kind of problematic, so I am leaning to special-case just the Xeon W family and not the rest until more information is known. |
That does seem to be what Linux is doing, though, right? They use I was under the impression that the ratios in
It's not explicit, but that's currently how I believe it behaves implicitly. The Skylake and Kabylake CPUS should both never make it to step 4, because they are special-cased to |
Right, I partially forgot about existing value table. Well, okay, if this approach works I am fine to merge it. |
Alternatively, we could treat this as a refinement step for CPUs that have an idealized |
Next generation currently has 0 TSC frequency, so as long as we handle it, it will most likely work fine. |
If that's the case, then the TSC-derived |
Good, then it should work fine. |
@mrmiller we are going to make a release by the end of this week, will you submit a patch on this and does the discussed approach work for you? |
I’m still testing my patch but will let you know tomorrow if it’s working. |
Okay, so the good news is that with my patch to calculate the adjusted I'll create a pull request later today. I'm not sure it needs to be rushed into the upcoming release, as it probably only really affects me at the moment. |
@mrmiller glad to hear that! I also think that we do not particularly need to rush it, but if it is ready I am fine to merge it as well. |
OCCPU is misreporting my CPU's frequency. I believe it's also causing the macOS system clock to run fast:
Looking at
OcCpu.c
, the following lines look suspect to me:https://github.com/acidanthera/OcSupportPkg/blob/3e98de1f89a9e946f026ecc24e4856e2096dc338/Library/OcCpuLib/OcCpuLib.c#L667
Should that be storing to
Cpu->ARTFrequency
instead? I tested by making this change and settingCpu->CPUFrequency
fromCpu->TSCFrequency
.About this Mac
now reports the correct frequency (3Ghz instead of 2.88Ghz). Also, the clock no longer drifts whereas it used to run a few seconds per minute faster than real-time.The text was updated successfully, but these errors were encountered: