[GH-ISSUE #62] ppc: CPU/bus frequency calibration prints negative rates under QEMU mac99 #55

Closed
opened 2026-11-03 22:03:24 -07:00 by gitea-mirror · 3 comments
Owner

Originally created by @raynorpat on GitHub (Oct 17, 2026).
Original GitHub issue: https://github.com/RhapsodiOS/RhapsodiOS/issues/62

On QEMU's mac99 (a "Sawtooth" G4 to the kernel), the boot banner prints negative clock rates that change on every boot:

CPU Frequency: -136803040 Hz
BUS Frequency: -  6840152 Hz

Earlier boots showed -190059441 / -9746638, -168799220 / -8439961 and -41107836 / -1957516. The stock Mac OS X Server 1.2v3 kernel (5.6) prints the same kind of values on the same machine, so this is inherited behaviour, not something our reconstruction introduced.

Where it comes from

src/drivers-ppc/bus/drvPExpert/powermac/clock_speed.c:

  • DetermineClockSpeeds() always runs do_clock_test(). The firmware path is disabled: if (0 && IsYosemite()) derive_from_of();.
  • do_clock_test() times the decrementer against the VIA timer (run_clock_test). It derives cpu_pll from dec_ticks, and raw_cpu_freq from a 64-bit quotient stored in a 32-bit long. Under TCG the two timers don't keep realistic relative time, so the fit falls through to "return the raw bus speed" with nonsense that overflows the signed type.
  • powermac_init.c:364-365 prints the results with %9d.

It matters beyond the banner. identify_machine2() sets dec_rate = powermac_info.bus_clock_rate_hz / 4 and dec_clock_period from it, so the decrementer rate behind the kernel's timekeeping comes from the same bad number.

Suggested fix

On New World machines (IsYosemite() || IsSawtooth()), trust Open Firmware's clock-frequency, bus-frequency and timebase-frequency (the /cpus/* and root nodes carry them) and fall back to the VIA calibration only when they are missing. Also keep the arithmetic unsigned or 64-bit, so a bad measurement can't print as negative.

Found while booting our ppc kernel under QEMU (see #61).

Originally created by @raynorpat on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/RhapsodiOS/RhapsodiOS/issues/62 On QEMU's `mac99` (a "Sawtooth" G4 to the kernel), the boot banner prints negative clock rates that change on every boot: ``` CPU Frequency: -136803040 Hz BUS Frequency: - 6840152 Hz ``` Earlier boots showed `-190059441 / -9746638`, `-168799220 / -8439961` and `-41107836 / -1957516`. The stock Mac OS X Server 1.2v3 kernel (5.6) prints the same kind of values on the same machine, so this is inherited behaviour, not something our reconstruction introduced. ## Where it comes from `src/drivers-ppc/bus/drvPExpert/powermac/clock_speed.c`: - `DetermineClockSpeeds()` always runs `do_clock_test()`. The firmware path is disabled: `if (0 && IsYosemite()) derive_from_of();`. - `do_clock_test()` times the decrementer against the VIA timer (`run_clock_test`). It derives `cpu_pll` from `dec_ticks`, and `raw_cpu_freq` from a 64-bit quotient stored in a 32-bit `long`. Under TCG the two timers don't keep realistic relative time, so the fit falls through to "return the raw bus speed" with nonsense that overflows the signed type. - `powermac_init.c:364-365` prints the results with `%9d`. It matters beyond the banner. `identify_machine2()` sets `dec_rate = powermac_info.bus_clock_rate_hz / 4` and `dec_clock_period` from it, so the decrementer rate behind the kernel's timekeeping comes from the same bad number. ## Suggested fix On New World machines (`IsYosemite() || IsSawtooth()`), trust Open Firmware's `clock-frequency`, `bus-frequency` and `timebase-frequency` (the `/cpus/*` and root nodes carry them) and fall back to the VIA calibration only when they are missing. Also keep the arithmetic unsigned or 64-bit, so a bad measurement can't print as negative. Found while booting our ppc kernel under QEMU (see #61).
gitea-mirror 2026-11-03 22:03:24 -07:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@raynorpat commented on GitHub (Oct 18, 2026):

Fixed on branch ppc-qemu (local, not pushed yet). The commit is "drvPExpert: take CPU and bus clocks from Open Firmware on New World machines".

DetermineClockSpeeds() now uses derive_from_of() on New World machines (IsYosemite() || IsSawtooth()) and falls back to the VIA calibration only if /cpus lacks clock-frequency or bus-frequency. This diverges from 5.6, which always ran the VIA test; our if (0 && IsYosemite()) was faithful to that. derive_from_of() itself got two fixes:

  • it checks the lookups instead of dereferencing whatever DTGetProperty left behind
  • it computes the PLL as cpu_freq / (bus_freq / 4), because 4 * cpu_freq overflows a 32-bit long above about 536 MHz (QEMU's G4 is 900 MHz)

On QEMU mac99 (OF reports clock 900 MHz, bus 100 MHz, timebase 25 MHz):

CPU Frequency: 900000000 Hz
BUS Frequency: 100000000 Hz

The decrementer now runs at the real 25 MHz. A sleep 20 in the guest took 20 guest seconds and 22 host seconds including the telnet login, and boot to the Setup Assistant dropped from 3–7 minutes to about 75 seconds.

Leaving this open until the branch is merged.

<!-- gh-comment-id:6253292391 --> @raynorpat commented on GitHub (Oct 18, 2026): Fixed on branch `ppc-qemu` (local, not pushed yet). The commit is "drvPExpert: take CPU and bus clocks from Open Firmware on New World machines". `DetermineClockSpeeds()` now uses `derive_from_of()` on New World machines (`IsYosemite() || IsSawtooth()`) and falls back to the VIA calibration only if `/cpus` lacks `clock-frequency` or `bus-frequency`. This diverges from 5.6, which always ran the VIA test; our `if (0 && IsYosemite())` was faithful to that. `derive_from_of()` itself got two fixes: - it checks the lookups instead of dereferencing whatever `DTGetProperty` left behind - it computes the PLL as `cpu_freq / (bus_freq / 4)`, because `4 * cpu_freq` overflows a 32-bit `long` above about 536 MHz (QEMU's G4 is 900 MHz) On QEMU mac99 (OF reports clock 900 MHz, bus 100 MHz, timebase 25 MHz): ``` CPU Frequency: 900000000 Hz BUS Frequency: 100000000 Hz ``` The decrementer now runs at the real 25 MHz. A `sleep 20` in the guest took 20 guest seconds and 22 host seconds including the telnet login, and boot to the Setup Assistant dropped from 3–7 minutes to about 75 seconds. Leaving this open until the branch is merged.
Author
Owner

@raynorpat commented on GitHub (Oct 18, 2026):

Two follow-ups.

Readable output (e294eb95a). CPU, bus and L2 clocks now print in MHz below 1 GHz and in GHz from 1 GHz up. On mac99: CPU Frequency: 900.00 MHz, BUS Frequency: 100.00 MHz.

Old World still miscalibrates. I booted the 1.2v3 disk on QEMU g3beige (Gossamer, Beige G3), with both the stock 5.6 kernel and ours. The fix above only covers New World, so both kernels still run the 5.6 VIA test there, and it overflows the same way it did on mac99:

stock 5.6 ours
CPU - 11820705 Hz 4.19 GHz
BUS - 363714 Hz 4.29 GHz

These are the same wrapped values. Stock prints them signed, ours prints them unsigned. OpenBIOS on g3beige does report the clocks in /cpus/PowerPC,750: clock-frequency 266 MHz, bus-frequency 66 MHz and timebase-frequency 16.6 MHz. The decrementer rate comes from the bad bus value, and that looks like the cause of a stall: both kernels sometimes stop after hc0: device detected at port 0x810a0000 irq 21 (Heathrow IDE). Stock got past it on two of three boots.

The likely fix is to take the clocks from OF on Gossamer too, when they are present, and keep the VIA test as the fallback. This needs checking against real old-world hardware, since 5.6 deliberately used the VIA test there.

Booting g3beige also needs a workaround. OpenBIOS's load of BootX fails on that machine (No valid state has been set by load or init-program). Setting boot-command to run BootX's own boot script by hand (read hd:6,\System Folder\BootX, move the XCOFF after </CHRP-BOOT> to load-base, init-program go) boots stock 1.2v3 to the Setup Assistant.

<!-- gh-comment-id:6254380551 --> @raynorpat commented on GitHub (Oct 18, 2026): Two follow-ups. **Readable output (e294eb95a).** CPU, bus and L2 clocks now print in MHz below 1 GHz and in GHz from 1 GHz up. On mac99: `CPU Frequency: 900.00 MHz`, `BUS Frequency: 100.00 MHz`. **Old World still miscalibrates.** I booted the 1.2v3 disk on QEMU `g3beige` (Gossamer, Beige G3), with both the stock 5.6 kernel and ours. The fix above only covers New World, so both kernels still run the 5.6 VIA test there, and it overflows the same way it did on mac99: | | stock 5.6 | ours | |---|---|---| | CPU | `- 11820705 Hz` | `4.19 GHz` | | BUS | `- 363714 Hz` | `4.29 GHz` | These are the same wrapped values. Stock prints them signed, ours prints them unsigned. OpenBIOS on g3beige does report the clocks in `/cpus/PowerPC,750`: `clock-frequency` 266 MHz, `bus-frequency` 66 MHz and `timebase-frequency` 16.6 MHz. The decrementer rate comes from the bad bus value, and that looks like the cause of a stall: both kernels sometimes stop after `hc0: device detected at port 0x810a0000 irq 21` (Heathrow IDE). Stock got past it on two of three boots. The likely fix is to take the clocks from OF on Gossamer too, when they are present, and keep the VIA test as the fallback. This needs checking against real old-world hardware, since 5.6 deliberately used the VIA test there. Booting g3beige also needs a workaround. OpenBIOS's `load` of BootX fails on that machine (`No valid state has been set by load or init-program`). Setting `boot-command` to run BootX's own boot script by hand (read `hd:6,\System Folder\BootX`, move the XCOFF after `</CHRP-BOOT>` to `load-base`, `init-program go`) boots stock 1.2v3 to the Setup Assistant.
Author
Owner

@raynorpat commented on GitHub (Oct 23, 2026):

Closing. Both New World and Old World machines now take their clocks from Open Firmware on branch ppc-qemu:

  • fa78ceafc: New World (Yosemite, Sawtooth).
  • 036a053ca: Gossamer. The VIA test is still the fallback when /cpus lacks clock-frequency or bus-frequency.
  • e294eb95a: clocks print in MHz, or GHz from 1 GHz up.

Results under QEMU:

  • mac99: CPU Frequency: 900.00 MHz, BUS Frequency: 100.00 MHz.
  • g3beige: CPU Frequency: 264.00 MHz, BUS Frequency: 66.00 MHz. OF reports 266 MHz, and the PLL rounds it to 4 × 66. The stall after hc0: device detected is gone; the IDE probes with DMA, and the boot reaches the Setup Assistant in under a minute.

ppc-qemu has not been pushed yet, so these commits land with it.

<!-- gh-comment-id:6363335013 --> @raynorpat commented on GitHub (Oct 23, 2026): Closing. Both New World and Old World machines now take their clocks from Open Firmware on branch `ppc-qemu`: - `fa78ceafc`: New World (Yosemite, Sawtooth). - `036a053ca`: Gossamer. The VIA test is still the fallback when `/cpus` lacks `clock-frequency` or `bus-frequency`. - `e294eb95a`: clocks print in MHz, or GHz from 1 GHz up. Results under QEMU: - **mac99:** `CPU Frequency: 900.00 MHz`, `BUS Frequency: 100.00 MHz`. - **g3beige:** `CPU Frequency: 264.00 MHz`, `BUS Frequency: 66.00 MHz`. OF reports 266 MHz, and the PLL rounds it to 4 × 66. The stall after `hc0: device detected` is gone; the IDE probes with DMA, and the boot reaches the Setup Assistant in under a minute. `ppc-qemu` has not been pushed yet, so these commits land with it.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
github-starred/RhapsodiOS#55
No description provided.