diff --git a/src/system/boot/platform/bios_ia32/cpu.h b/headers/private/kernel/boot/arch/x86/arch_cpu.h similarity index 67% rename from src/system/boot/platform/bios_ia32/cpu.h rename to headers/private/kernel/boot/arch/x86/arch_cpu.h index f8eff4f44a..771f11a6d1 100644 --- a/src/system/boot/platform/bios_ia32/cpu.h +++ b/headers/private/kernel/boot/arch/x86/arch_cpu.h @@ -2,8 +2,8 @@ * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. */ -#ifndef CPU_H -#define CPU_H +#ifndef BOOT_ARCH_CPU_H +#define BOOT_ARCH_CPU_H #include @@ -15,8 +15,11 @@ extern "C" { extern void cpu_init(void); +void calculate_cpu_conversion_factor(uint8 channel); + + #ifdef __cplusplus } #endif -#endif /* CPU_H */ +#endif /* BOOT_ARCH_CPU_H */ diff --git a/src/system/boot/arch/x86/Jamfile b/src/system/boot/arch/x86/Jamfile index 8bf9087dab..448a50b4be 100644 --- a/src/system/boot/arch/x86/Jamfile +++ b/src/system/boot/arch/x86/Jamfile @@ -28,6 +28,7 @@ for platform in [ MultiBootSubDirSetup bios_ia32 efi pxe_ia32 ] { $(kernelArchSpecificSources) $(kernelLibArchSpecificSources) $(librootOsArchSources) + cpu.cpp : -std=c++11 # additional flags ; diff --git a/src/system/boot/arch/x86/cpu.cpp b/src/system/boot/arch/x86/cpu.cpp new file mode 100644 index 0000000000..3541daf6c7 --- /dev/null +++ b/src/system/boot/arch/x86/cpu.cpp @@ -0,0 +1,318 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + * + * calculate_cpu_conversion_factor() was written by Travis Geiselbrecht and + * licensed under the NewOS license. + */ + + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + + +extern "C" uint64 rdtsc(); + +uint32 gTimeConversionFactor; + +// PIT definitions +#define TIMER_CLKNUM_HZ (14318180 / 12) + +// PIT IO Ports +#define PIT_CHANNEL_PORT_BASE 0x40 +#define PIT_CONTROL 0x43 + +// Channel selection +#define PIT_SELECT_CHANNEL_SHIFT 6 + +// Access mode +#define PIT_ACCESS_LATCH_COUNTER (0 << 4) +#define PIT_ACCESS_LOW_BYTE_ONLY (1 << 4) +#define PIT_ACCESS_HIGH_BYTE_ONLY (2 << 4) +#define PIT_ACCESS_LOW_THEN_HIGH_BYTE (3 << 4) + +// Operating modes +#define PIT_MODE_INTERRUPT_ON_0 (0 << 1) +#define PIT_MODE_HARDWARE_COUNTDOWN (1 << 1) +#define PIT_MODE_RATE_GENERATOR (2 << 1) +#define PIT_MODE_SQUARE_WAVE_GENERATOR (3 << 1) +#define PIT_MODE_SOFTWARE_STROBE (4 << 1) +#define PIT_MODE_HARDWARE_STROBE (5 << 1) + +// BCD/Binary mode +#define PIT_BINARY_MODE 0 +#define PIT_BCD_MODE 1 + +// Channel 2 control (speaker) +#define PIT_CHANNEL_2_CONTROL 0x61 +#define PIT_CHANNEL_2_GATE_HIGH 0x01 +#define PIT_CHANNEL_2_SPEAKER_OFF_MASK ~0x02 + +// Maximum values +#define MAX_QUICK_SAMPLES 20 +#define MAX_SLOW_SAMPLES 20 + // TODO: These are arbitrary. They are here to avoid spinning indefinitely + // if the TSC just isn't stable and we can't get our desired error range. + + +struct uint128 { + uint128(uint64 low, uint64 high = 0) + : + low(low), + high(high) + { + } + + bool operator<(const uint128& other) const + { + return high < other.high || (high == other.high && low < other.low); + } + + bool operator<=(const uint128& other) const + { + return !(other < *this); + } + + uint128 operator<<(int count) const + { + if (count == 0) + return *this; + + if (count >= 128) + return 0; + + if (count >= 64) + return uint128(0, low << (count - 64)); + + return uint128(low << count, (high << count) | (low >> (64 - count))); + } + + uint128 operator>>(int count) const + { + if (count == 0) + return *this; + + if (count >= 128) + return 0; + + if (count >= 64) + return uint128(high >> (count - 64), 0); + + return uint128((low >> count) | (high << (64 - count)), high >> count); + } + + uint128 operator+(const uint128& other) const + { + uint64 resultLow = low + other.low; + return uint128(resultLow, + high + other.high + (resultLow < low ? 1 : 0)); + } + + uint128 operator-(const uint128& other) const + { + uint64 resultLow = low - other.low; + return uint128(resultLow, + high - other.high - (resultLow > low ? 1 : 0)); + } + + uint128 operator*(uint32 other) const + { + uint64 resultMid = (low >> 32) * other; + uint64 resultLow = (low & 0xffffffff) * other + (resultMid << 32); + return uint128(resultLow, + high * other + (resultMid >> 32) + + (resultLow < resultMid << 32 ? 1 : 0)); + } + + uint128 operator/(const uint128& other) const + { + int shift = 0; + uint128 shiftedDivider = other; + while (shiftedDivider.high >> 63 == 0 && shiftedDivider < *this) { + shiftedDivider = shiftedDivider << 1; + shift++; + } + + uint128 result = 0; + uint128 temp = *this; + for (; shift >= 0; shift--, shiftedDivider = shiftedDivider >> 1) { + if (shiftedDivider <= temp) { + result = result + (uint128(1) << shift); + temp = temp - shiftedDivider; + } + } + + return result; + } + + operator uint64() const + { + return low; + } + +private: + uint64 low; + uint64 high; +}; + + +static inline void +calibration_loop(uint8 desiredHighByte, uint8 channel, uint64& tscDelta, + double& conversionFactor, uint16& expired) +{ + uint8 select = channel << PIT_SELECT_CHANNEL_SHIFT; + out8(select | PIT_ACCESS_LOW_THEN_HIGH_BYTE | PIT_MODE_INTERRUPT_ON_0 + | PIT_BINARY_MODE, PIT_CONTROL); + + // Fill in count of 0xffff, low then high byte + uint8 channelPort = PIT_CHANNEL_PORT_BASE + channel; + out8(0xff, channelPort); + out8(0xff, channelPort); + + // Read the count back once to delay the start. This ensures that we've + // waited long enough for the counter to actually start counting down, as + // this only happens on the next clock cycle after reload. + in8(channelPort); + in8(channelPort); + + // We're expecting the PIT to be at the starting position (high byte 0xff) + // as we just programmed it, but if it isn't we wait for it to wrap. + uint8 startLow; + uint8 startHigh; + do { + out8(select | PIT_ACCESS_LATCH_COUNTER, PIT_CONTROL); + startLow = in8(channelPort); + startHigh = in8(channelPort); + } while (startHigh != 255); + + // Read in the first TSC value + uint64 startTSC = rdtsc(); + + // Wait for the PIT to count down to our desired value + uint8 endLow; + uint8 endHigh; + do { + out8(select | PIT_ACCESS_LATCH_COUNTER, PIT_CONTROL); + endLow = in8(channelPort); + endHigh = in8(channelPort); + } while (endHigh > desiredHighByte); + + // And read the second TSC value + uint64 endTSC = rdtsc(); + + tscDelta = endTSC - startTSC; + expired = ((startHigh << 8) | startLow) - ((endHigh << 8) | endLow); + conversionFactor = (double)tscDelta / (double)expired; +} + + +void +calculate_cpu_conversion_factor(uint8 channel) +{ + // When using channel 2, enable the input and disable the speaker. + if (channel == 2) { + uint8 control = in8(PIT_CHANNEL_2_CONTROL); + control &= PIT_CHANNEL_2_SPEAKER_OFF_MASK; + control |= PIT_CHANNEL_2_GATE_HIGH; + out8(control, PIT_CHANNEL_2_CONTROL); + } + + uint64 tscDeltaQuick, tscDeltaSlower, tscDeltaSlow; + double conversionFactorQuick, conversionFactorSlower, conversionFactorSlow; + uint16 expired; + + uint32 quickSampleCount = 1; + uint32 slowSampleCount = 1; + +quick_sample: + calibration_loop(224, channel, tscDeltaQuick, conversionFactorQuick, + expired); + +slower_sample: + calibration_loop(192, channel, tscDeltaSlower, conversionFactorSlower, + expired); + + double deviation = conversionFactorQuick / conversionFactorSlower; + if (deviation < 0.99 || deviation > 1.01) { + // We might have been hit by a SMI or were otherwise stalled + if (quickSampleCount++ < MAX_QUICK_SAMPLES) + goto quick_sample; + } + + // Slow sample + calibration_loop(128, channel, tscDeltaSlow, conversionFactorSlow, + expired); + + deviation = conversionFactorSlower / conversionFactorSlow; + if (deviation < 0.99 || deviation > 1.01) { + // We might have been hit by a SMI or were otherwise stalled + if (slowSampleCount++ < MAX_SLOW_SAMPLES) + goto slower_sample; + } + + // Scale the TSC delta to timer units + tscDeltaSlow *= TIMER_CLKNUM_HZ; + + uint64 clockSpeed = tscDeltaSlow / expired; + gTimeConversionFactor = ((uint128(expired) * uint32(1000000)) << 32) + / uint128(tscDeltaSlow); + +#ifdef TRACE_CPU + if (clockSpeed > 1000000000LL) { + dprintf("CPU at %Ld.%03Ld GHz\n", clockSpeed / 1000000000LL, + (clockSpeed % 1000000000LL) / 1000000LL); + } else { + dprintf("CPU at %Ld.%03Ld MHz\n", clockSpeed / 1000000LL, + (clockSpeed % 1000000LL) / 1000LL); + } +#endif + + gKernelArgs.arch_args.system_time_cv_factor = gTimeConversionFactor; + gKernelArgs.arch_args.cpu_clock_speed = clockSpeed; + //dprintf("factors: %lu %llu\n", gTimeConversionFactor, clockSpeed); + + if (quickSampleCount > 1) { + dprintf("needed %" B_PRIu32 " quick samples for TSC calibration\n", + quickSampleCount); + } + + if (slowSampleCount > 1) { + dprintf("needed %" B_PRIu32 " slow samples for TSC calibration\n", + slowSampleCount); + } + + if (channel == 2) { + // Set the gate low again + out8(in8(PIT_CHANNEL_2_CONTROL) & ~PIT_CHANNEL_2_GATE_HIGH, + PIT_CHANNEL_2_CONTROL); + } +} + + +extern "C" bigtime_t +system_time() +{ + return rdtsc() * gTimeConversionFactor; +} + + +extern "C" void +spin(bigtime_t microseconds) +{ + bigtime_t time = system_time(); + + while ((system_time() - time) < microseconds) + asm volatile ("pause;"); +} diff --git a/src/system/boot/platform/amiga_m68k/cpu.cpp b/src/system/boot/platform/amiga_m68k/cpu.cpp index 31fb6d4dac..5432f1d87d 100644 --- a/src/system/boot/platform/amiga_m68k/cpu.cpp +++ b/src/system/boot/platform/amiga_m68k/cpu.cpp @@ -1,9 +1,6 @@ /* * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. - * - * calculate_cpu_conversion_factor() was written by Travis Geiselbrecht and - * licensed under the NewOS license. */ diff --git a/src/system/boot/platform/bios_ia32/cpu.cpp b/src/system/boot/platform/bios_ia32/cpu.cpp index cc70cbaba9..2d9e00f11e 100644 --- a/src/system/boot/platform/bios_ia32/cpu.cpp +++ b/src/system/boot/platform/bios_ia32/cpu.cpp @@ -2,20 +2,18 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. - * - * calculate_cpu_conversion_factor() was written by Travis Geiselbrecht and - * licensed under the NewOS license. */ -#include "cpu.h" - #include -#include -#include + +#include #include +#include #include -#include +#include + +#include #include #include @@ -30,291 +28,10 @@ #endif -extern "C" uint64 rdtsc(); - -uint32 gTimeConversionFactor; - -// PIT definitions -#define TIMER_CLKNUM_HZ (14318180 / 12) - -// PIT IO Ports -#define PIT_CHANNEL_PORT_BASE 0x40 -#define PIT_CONTROL 0x43 - -// Channel selection -#define PIT_SELECT_CHANNEL_SHIFT 6 - -// Access mode -#define PIT_ACCESS_LATCH_COUNTER (0 << 4) -#define PIT_ACCESS_LOW_BYTE_ONLY (1 << 4) -#define PIT_ACCESS_HIGH_BYTE_ONLY (2 << 4) -#define PIT_ACCESS_LOW_THEN_HIGH_BYTE (3 << 4) - -// Operating modes -#define PIT_MODE_INTERRUPT_ON_0 (0 << 1) -#define PIT_MODE_HARDWARE_COUNTDOWN (1 << 1) -#define PIT_MODE_RATE_GENERATOR (2 << 1) -#define PIT_MODE_SQUARE_WAVE_GENERATOR (3 << 1) -#define PIT_MODE_SOFTWARE_STROBE (4 << 1) -#define PIT_MODE_HARDWARE_STROBE (5 << 1) - -// BCD/Binary mode -#define PIT_BINARY_MODE 0 -#define PIT_BCD_MODE 1 - -// Channel 2 control (speaker) -#define PIT_CHANNEL_2_CONTROL 0x61 -#define PIT_CHANNEL_2_GATE_HIGH 0x01 -#define PIT_CHANNEL_2_SPEAKER_OFF_MASK ~0x02 - - -// Maximum values -#define MAX_QUICK_SAMPLES 20 -#define MAX_SLOW_SAMPLES 20 - // TODO: These are arbitrary. They are here to avoid spinning indefinitely - // if the TSC just isn't stable and we can't get our desired error range. - - #define CPUID_EFLAGS (1UL << 21) #define RDTSC_FEATURE (1UL << 4) -struct uint128 { - uint128(uint64 low, uint64 high = 0) - : - low(low), - high(high) - { - } - - bool operator<(const uint128& other) const - { - return high < other.high || (high == other.high && low < other.low); - } - - bool operator<=(const uint128& other) const - { - return !(other < *this); - } - - uint128 operator<<(int count) const - { - if (count == 0) - return *this; - - if (count >= 128) - return 0; - - if (count >= 64) - return uint128(0, low << (count - 64)); - - return uint128(low << count, (high << count) | (low >> (64 - count))); - } - - uint128 operator>>(int count) const - { - if (count == 0) - return *this; - - if (count >= 128) - return 0; - - if (count >= 64) - return uint128(high >> (count - 64), 0); - - return uint128((low >> count) | (high << (64 - count)), high >> count); - } - - uint128 operator+(const uint128& other) const - { - uint64 resultLow = low + other.low; - return uint128(resultLow, - high + other.high + (resultLow < low ? 1 : 0)); - } - - uint128 operator-(const uint128& other) const - { - uint64 resultLow = low - other.low; - return uint128(resultLow, - high - other.high - (resultLow > low ? 1 : 0)); - } - - uint128 operator*(uint32 other) const - { - uint64 resultMid = (low >> 32) * other; - uint64 resultLow = (low & 0xffffffff) * other + (resultMid << 32); - return uint128(resultLow, - high * other + (resultMid >> 32) - + (resultLow < resultMid << 32 ? 1 : 0)); - } - - uint128 operator/(const uint128& other) const - { - int shift = 0; - uint128 shiftedDivider = other; - while (shiftedDivider.high >> 63 == 0 && shiftedDivider < *this) { - shiftedDivider = shiftedDivider << 1; - shift++; - } - - uint128 result = 0; - uint128 temp = *this; - for (; shift >= 0; shift--, shiftedDivider = shiftedDivider >> 1) { - if (shiftedDivider <= temp) { - result = result + (uint128(1) << shift); - temp = temp - shiftedDivider; - } - } - - return result; - } - - operator uint64() const - { - return low; - } - -private: - uint64 low; - uint64 high; -}; - - -static inline void -calibration_loop(uint8 desiredHighByte, uint8 channel, uint64& tscDelta, - double& conversionFactor, uint16& expired) -{ - uint8 select = channel << PIT_SELECT_CHANNEL_SHIFT; - out8(select | PIT_ACCESS_LOW_THEN_HIGH_BYTE | PIT_MODE_INTERRUPT_ON_0 - | PIT_BINARY_MODE, PIT_CONTROL); - - // Fill in count of 0xffff, low then high byte - uint8 channelPort = PIT_CHANNEL_PORT_BASE + channel; - out8(0xff, channelPort); - out8(0xff, channelPort); - - // Read the count back once to delay the start. This ensures that we've - // waited long enough for the counter to actually start counting down, as - // this only happens on the next clock cycle after reload. - in8(channelPort); - in8(channelPort); - - // We're expecting the PIT to be at the starting position (high byte 0xff) - // as we just programmed it, but if it isn't we wait for it to wrap. - uint8 startLow; - uint8 startHigh; - do { - out8(select | PIT_ACCESS_LATCH_COUNTER, PIT_CONTROL); - startLow = in8(channelPort); - startHigh = in8(channelPort); - } while (startHigh != 255); - - // Read in the first TSC value - uint64 startTSC = rdtsc(); - - // Wait for the PIT to count down to our desired value - uint8 endLow; - uint8 endHigh; - do { - out8(select | PIT_ACCESS_LATCH_COUNTER, PIT_CONTROL); - endLow = in8(channelPort); - endHigh = in8(channelPort); - } while (endHigh > desiredHighByte); - - // And read the second TSC value - uint64 endTSC = rdtsc(); - - tscDelta = endTSC - startTSC; - expired = ((startHigh << 8) | startLow) - ((endHigh << 8) | endLow); - conversionFactor = (double)tscDelta / (double)expired; -} - - -static void -calculate_cpu_conversion_factor() -{ - uint8 channel = 0; - - // When using channel 2, enable the input and disable the speaker. - if (channel == 2) { - uint8 control = in8(PIT_CHANNEL_2_CONTROL); - control &= PIT_CHANNEL_2_SPEAKER_OFF_MASK; - control |= PIT_CHANNEL_2_GATE_HIGH; - out8(control, PIT_CHANNEL_2_CONTROL); - } - - uint64 tscDeltaQuick, tscDeltaSlower, tscDeltaSlow; - double conversionFactorQuick, conversionFactorSlower, conversionFactorSlow; - uint16 expired; - - uint32 quickSampleCount = 1; - uint32 slowSampleCount = 1; - -quick_sample: - calibration_loop(224, channel, tscDeltaQuick, conversionFactorQuick, - expired); - -slower_sample: - calibration_loop(192, channel, tscDeltaSlower, conversionFactorSlower, - expired); - - double deviation = conversionFactorQuick / conversionFactorSlower; - if (deviation < 0.99 || deviation > 1.01) { - // We might have been hit by a SMI or were otherwise stalled - if (quickSampleCount++ < MAX_QUICK_SAMPLES) - goto quick_sample; - } - - // Slow sample - calibration_loop(128, channel, tscDeltaSlow, conversionFactorSlow, - expired); - - deviation = conversionFactorSlower / conversionFactorSlow; - if (deviation < 0.99 || deviation > 1.01) { - // We might have been hit by a SMI or were otherwise stalled - if (slowSampleCount++ < MAX_SLOW_SAMPLES) - goto slower_sample; - } - - // Scale the TSC delta to timer units - tscDeltaSlow *= TIMER_CLKNUM_HZ; - - uint64 clockSpeed = tscDeltaSlow / expired; - gTimeConversionFactor = ((uint128(expired) * uint32(1000000)) << 32) - / uint128(tscDeltaSlow); - -#ifdef TRACE_CPU - if (clockSpeed > 1000000000LL) { - dprintf("CPU at %Ld.%03Ld GHz\n", clockSpeed / 1000000000LL, - (clockSpeed % 1000000000LL) / 1000000LL); - } else { - dprintf("CPU at %Ld.%03Ld MHz\n", clockSpeed / 1000000LL, - (clockSpeed % 1000000LL) / 1000LL); - } -#endif - - gKernelArgs.arch_args.system_time_cv_factor = gTimeConversionFactor; - gKernelArgs.arch_args.cpu_clock_speed = clockSpeed; - //dprintf("factors: %lu %llu\n", gTimeConversionFactor, clockSpeed); - - if (quickSampleCount > 1) { - dprintf("needed %lu quick samples for TSC calibration\n", - quickSampleCount); - } - - if (slowSampleCount > 1) { - dprintf("needed %lu slow samples for TSC calibration\n", - slowSampleCount); - } - - if (channel == 2) { - // Set the gate low again - out8(in8(PIT_CHANNEL_2_CONTROL) & ~PIT_CHANNEL_2_GATE_HIGH, - PIT_CHANNEL_2_CONTROL); - } -} - - static status_t check_cpu_features() { @@ -342,25 +59,14 @@ check_cpu_features() // #pragma mark - -extern "C" void -spin(bigtime_t microseconds) -{ - bigtime_t time = system_time(); - - while ((system_time() - time) < microseconds) - asm volatile ("pause;"); -} - - extern "C" void cpu_init() { if (check_cpu_features() != B_OK) panic("You need a Pentium or higher in order to boot!\n"); - calculate_cpu_conversion_factor(); + calculate_cpu_conversion_factor(0); gKernelArgs.num_cpus = 1; // this will eventually be corrected later on } - diff --git a/src/system/boot/platform/bios_ia32/start.cpp b/src/system/boot/platform/bios_ia32/start.cpp index 7222ff377c..5c788750f8 100644 --- a/src/system/boot/platform/bios_ia32/start.cpp +++ b/src/system/boot/platform/bios_ia32/start.cpp @@ -8,7 +8,9 @@ #include -#include +#include + +#include #include #include #include @@ -17,7 +19,6 @@ #include "apm.h" #include "bios.h" #include "console.h" -#include "cpu.h" #include "debug.h" #include "hpet.h" #include "interrupts.h" diff --git a/src/system/boot/platform/bios_ia32/support.S b/src/system/boot/platform/bios_ia32/support.S index 525faf588d..ce89d6d892 100644 --- a/src/system/boot/platform/bios_ia32/support.S +++ b/src/system/boot/platform/bios_ia32/support.S @@ -35,25 +35,6 @@ FUNCTION(execute_n_instructions): loop .again ret -FUNCTION(system_time): - /* load 64-bit factor into %eax (low), %edx (high) */ - /* hand-assemble rdtsc -- read time stamp counter */ - rdtsc /* time in %edx,%eax */ - - pushl %ebx - movl gTimeConversionFactor, %ebx - movl %edx, %ecx /* save high half */ - mull %ebx /* truncate %eax, but keep %edx */ - movl %ecx, %eax - movl %edx, %ecx /* save high half of low */ - mull %ebx /*, %eax*/ - /* now compute [%edx, %eax] + [%ecx], propagating carry */ - subl %ebx, %ebx /* need zero to propagate carry */ - addl %ecx, %eax - adc %ebx, %edx - popl %ebx - ret - null_idt_descr: .word 0 .word 0,0 diff --git a/src/system/boot/platform/efi/cpu.cpp b/src/system/boot/platform/efi/cpu.cpp index 66f8748cc9..5093cfe322 100644 --- a/src/system/boot/platform/efi/cpu.cpp +++ b/src/system/boot/platform/efi/cpu.cpp @@ -2,347 +2,19 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. - * - * calculate_cpu_conversion_factor() was written by Travis Geiselbrecht and - * licensed under the NewOS license. */ -#include "cpu.h" - -#include "efi_platform.h" - -#include -#include -#include #include #include #include -#include -#include - -#include - - -//#define TRACE_CPU -#ifdef TRACE_CPU -# define TRACE(x) dprintf x -#else -# define TRACE(x) ; -#endif - - -extern "C" uint64 rdtsc(); - -uint32 gTimeConversionFactor; - -// PIT definitions -#define TIMER_CLKNUM_HZ (14318180 / 12) - -// PIT IO Ports -#define PIT_CHANNEL_PORT_BASE 0x40 -#define PIT_CONTROL 0x43 - -// Channel selection -#define PIT_SELECT_CHANNEL_SHIFT 6 - -// Access mode -#define PIT_ACCESS_LATCH_COUNTER (0 << 4) -#define PIT_ACCESS_LOW_BYTE_ONLY (1 << 4) -#define PIT_ACCESS_HIGH_BYTE_ONLY (2 << 4) -#define PIT_ACCESS_LOW_THEN_HIGH_BYTE (3 << 4) - -// Operating modes -#define PIT_MODE_INTERRUPT_ON_0 (0 << 1) -#define PIT_MODE_HARDWARE_COUNTDOWN (1 << 1) -#define PIT_MODE_RATE_GENERATOR (2 << 1) -#define PIT_MODE_SQUARE_WAVE_GENERATOR (3 << 1) -#define PIT_MODE_SOFTWARE_STROBE (4 << 1) -#define PIT_MODE_HARDWARE_STROBE (5 << 1) - -// BCD/Binary mode -#define PIT_BINARY_MODE 0 -#define PIT_BCD_MODE 1 - -// Channel 2 control (speaker) -#define PIT_CHANNEL_2_CONTROL 0x61 -#define PIT_CHANNEL_2_GATE_HIGH 0x01 -#define PIT_CHANNEL_2_SPEAKER_OFF_MASK ~0x02 - - -// Maximum values -#define MAX_QUICK_SAMPLES 20 -#define MAX_SLOW_SAMPLES 20 - // TODO: These are arbitrary. They are here to avoid spinning indefinitely - // if the TSC just isn't stable and we can't get our desired error range. - - -#define CPUID_EFLAGS (1UL << 21) -#define RDTSC_FEATURE (1UL << 4) - - -struct uint128 { - uint128(uint64 low, uint64 high = 0) - : - low(low), - high(high) - { - } - - bool operator<(const uint128& other) const - { - return high < other.high || (high == other.high && low < other.low); - } - - bool operator<=(const uint128& other) const - { - return !(other < *this); - } - - uint128 operator<<(int count) const - { - if (count == 0) - return *this; - - if (count >= 128) - return 0; - - if (count >= 64) - return uint128(0, low << (count - 64)); - - return uint128(low << count, (high << count) | (low >> (64 - count))); - } - - uint128 operator>>(int count) const - { - if (count == 0) - return *this; - - if (count >= 128) - return 0; - - if (count >= 64) - return uint128(high >> (count - 64), 0); - - return uint128((low >> count) | (high << (64 - count)), high >> count); - } - - uint128 operator+(const uint128& other) const - { - uint64 resultLow = low + other.low; - return uint128(resultLow, - high + other.high + (resultLow < low ? 1 : 0)); - } - - uint128 operator-(const uint128& other) const - { - uint64 resultLow = low - other.low; - return uint128(resultLow, - high - other.high - (resultLow > low ? 1 : 0)); - } - - uint128 operator*(uint32 other) const - { - uint64 resultMid = (low >> 32) * other; - uint64 resultLow = (low & 0xffffffff) * other + (resultMid << 32); - return uint128(resultLow, - high * other + (resultMid >> 32) - + (resultLow < resultMid << 32 ? 1 : 0)); - } - - uint128 operator/(const uint128& other) const - { - int shift = 0; - uint128 shiftedDivider = other; - while (shiftedDivider.high >> 63 == 0 && shiftedDivider < *this) { - shiftedDivider = shiftedDivider << 1; - shift++; - } - - uint128 result = 0; - uint128 temp = *this; - for (; shift >= 0; shift--, shiftedDivider = shiftedDivider >> 1) { - if (shiftedDivider <= temp) { - result = result + (uint128(1) << shift); - temp = temp - shiftedDivider; - } - } - - return result; - } - - operator uint64() const - { - return low; - } - -private: - uint64 low; - uint64 high; -}; - - -static inline void -calibration_loop(uint8 desiredHighByte, uint8 channel, uint64& tscDelta, - double& conversionFactor, uint16& expired) -{ - uint8 select = channel << PIT_SELECT_CHANNEL_SHIFT; - out8(select | PIT_ACCESS_LOW_THEN_HIGH_BYTE | PIT_MODE_INTERRUPT_ON_0 - | PIT_BINARY_MODE, PIT_CONTROL); - - // Fill in count of 0xffff, low then high byte - uint8 channelPort = PIT_CHANNEL_PORT_BASE + channel; - out8(0xff, channelPort); - out8(0xff, channelPort); - - // Read the count back once to delay the start. This ensures that we've - // waited long enough for the counter to actually start counting down, as - // this only happens on the next clock cycle after reload. - in8(channelPort); - in8(channelPort); - - // We're expecting the PIT to be at the starting position (high byte 0xff) - // as we just programmed it, but if it isn't we wait for it to wrap. - uint8 startLow; - uint8 startHigh; - do { - out8(select | PIT_ACCESS_LATCH_COUNTER, PIT_CONTROL); - startLow = in8(channelPort); - startHigh = in8(channelPort); - } while (startHigh != 255); - - // Read in the first TSC value - uint64 startTSC = rdtsc(); - - // Wait for the PIT to count down to our desired value - uint8 endLow; - uint8 endHigh; - do { - out8(select | PIT_ACCESS_LATCH_COUNTER, PIT_CONTROL); - endLow = in8(channelPort); - endHigh = in8(channelPort); - } while (endHigh > desiredHighByte); - - // And read the second TSC value - uint64 endTSC = rdtsc(); - - tscDelta = endTSC - startTSC; - expired = ((startHigh << 8) | startLow) - ((endHigh << 8) | endLow); - conversionFactor = (double)tscDelta / (double)expired; -} - - -static void -calculate_cpu_conversion_factor() -{ - uint8 channel = 2; - - // When using channel 2, enable the input and disable the speaker. - if (channel == 2) { - uint8 control = in8(PIT_CHANNEL_2_CONTROL); - control &= PIT_CHANNEL_2_SPEAKER_OFF_MASK; - control |= PIT_CHANNEL_2_GATE_HIGH; - out8(control, PIT_CHANNEL_2_CONTROL); - } - - uint64 tscDeltaQuick, tscDeltaSlower, tscDeltaSlow; - double conversionFactorQuick, conversionFactorSlower, conversionFactorSlow; - uint16 expired; - - uint32 quickSampleCount = 1; - uint32 slowSampleCount = 1; - -quick_sample: - calibration_loop(224, channel, tscDeltaQuick, conversionFactorQuick, - expired); - -slower_sample: - calibration_loop(192, channel, tscDeltaSlower, conversionFactorSlower, - expired); - - double deviation = conversionFactorQuick / conversionFactorSlower; - if (deviation < 0.99 || deviation > 1.01) { - // We might have been hit by a SMI or were otherwise stalled - if (quickSampleCount++ < MAX_QUICK_SAMPLES) - goto quick_sample; - } - - // Slow sample - calibration_loop(128, channel, tscDeltaSlow, conversionFactorSlow, - expired); - - deviation = conversionFactorSlower / conversionFactorSlow; - if (deviation < 0.99 || deviation > 1.01) { - // We might have been hit by a SMI or were otherwise stalled - if (slowSampleCount++ < MAX_SLOW_SAMPLES) - goto slower_sample; - } - - // Scale the TSC delta to timer units - tscDeltaSlow *= TIMER_CLKNUM_HZ; - - uint64 clockSpeed = tscDeltaSlow / expired; - gTimeConversionFactor = ((uint128(expired) * uint32(1000000)) << 32) - / uint128(tscDeltaSlow); - -#ifdef TRACE_CPU - if (clockSpeed > 1000000000LL) { - dprintf("CPU at %Ld.%03Ld GHz\n", clockSpeed / 1000000000LL, - (clockSpeed % 1000000000LL) / 1000000LL); - } else { - dprintf("CPU at %Ld.%03Ld MHz\n", clockSpeed / 1000000LL, - (clockSpeed % 1000000LL) / 1000LL); - } -#endif - - gKernelArgs.arch_args.system_time_cv_factor = gTimeConversionFactor; - gKernelArgs.arch_args.cpu_clock_speed = clockSpeed; - //dprintf("factors: %lu %llu\n", gTimeConversionFactor, clockSpeed); - - if (quickSampleCount > 1) { - dprintf("needed %u quick samples for TSC calibration\n", - quickSampleCount); - } - - if (slowSampleCount > 1) { - dprintf("needed %u slow samples for TSC calibration\n", - slowSampleCount); - } - - if (channel == 2) { - // Set the gate low again - out8(in8(PIT_CHANNEL_2_CONTROL) & ~PIT_CHANNEL_2_GATE_HIGH, - PIT_CHANNEL_2_CONTROL); - } -} - - -// #pragma mark - - - -extern "C" bigtime_t -system_time() -{ - uint64 lo, hi; - asm("rdtsc": "=a"(lo), "=d"(hi)); - return ((lo * gTimeConversionFactor) >> 32) + hi * gTimeConversionFactor; -} - - -extern "C" void -spin(bigtime_t microseconds) -{ - bigtime_t time = system_time(); - - while ((system_time() - time) < microseconds) - asm volatile ("pause;"); -} +#include extern "C" void cpu_init() { - calculate_cpu_conversion_factor(); + calculate_cpu_conversion_factor(2); gKernelArgs.num_cpus = 1; // this will eventually be corrected later on diff --git a/src/system/boot/platform/efi/cpu.h b/src/system/boot/platform/efi/cpu.h deleted file mode 100644 index f8eff4f44a..0000000000 --- a/src/system/boot/platform/efi/cpu.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. - * Distributed under the terms of the MIT License. - */ -#ifndef CPU_H -#define CPU_H - - -#include - - -#ifdef __cplusplus -extern "C" { -#endif - -extern void cpu_init(void); - -#ifdef __cplusplus -} -#endif - -#endif /* CPU_H */ diff --git a/src/system/boot/platform/efi/start.cpp b/src/system/boot/platform/efi/start.cpp index 4b9d794061..dc48a55fff 100644 --- a/src/system/boot/platform/efi/start.cpp +++ b/src/system/boot/platform/efi/start.cpp @@ -12,17 +12,18 @@ #include #include +#include + +#include #include #include #include #include -#include #include "arch_mmu.h" #include "acpi.h" #include "console.h" #include "efi_platform.h" -#include "cpu.h" #include "mmu.h" #include "serial.h" #include "smp.h" diff --git a/src/system/boot/platform/u-boot/arch/ppc/arch_cpu.cpp b/src/system/boot/platform/u-boot/arch/ppc/arch_cpu.cpp index 5ec43c1d4f..68c338e8f5 100644 --- a/src/system/boot/platform/u-boot/arch/ppc/arch_cpu.cpp +++ b/src/system/boot/platform/u-boot/arch/ppc/arch_cpu.cpp @@ -1,9 +1,6 @@ /* * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. - * - * calculate_cpu_conversion_factor() was written by Travis Geiselbrecht and - * licensed under the NewOS license. */ diff --git a/src/system/boot/platform/u-boot/cpu.cpp b/src/system/boot/platform/u-boot/cpu.cpp index 5df276f07d..96c4265552 100644 --- a/src/system/boot/platform/u-boot/cpu.cpp +++ b/src/system/boot/platform/u-boot/cpu.cpp @@ -1,9 +1,6 @@ /* * Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. - * - * calculate_cpu_conversion_factor() was written by Travis Geiselbrecht and - * licensed under the NewOS license. */