diff --git a/headers/private/kernel/arch/x86/apic.h b/headers/private/kernel/arch/x86/apic.h index 23605e6c8c..0a3ef8d547 100644 --- a/headers/private/kernel/arch/x86/apic.h +++ b/headers/private/kernel/arch/x86/apic.h @@ -131,6 +131,7 @@ uint32 apic_lvt_error(); void apic_set_lvt_error(uint32 config); uint32 apic_lvt_initial_timer_count(); void apic_set_lvt_initial_timer_count(uint32 config); +uint32 apic_lvt_current_timer_count(); uint32 apic_lvt_timer_divide_config(); void apic_set_lvt_timer_divide_config(uint32 config); diff --git a/headers/private/kernel/arch/x86/arch_kernel_args.h b/headers/private/kernel/arch/x86/arch_kernel_args.h index e9d2e83775..91be4cd561 100644 --- a/headers/private/kernel/arch/x86/arch_kernel_args.h +++ b/headers/private/kernel/arch/x86/arch_kernel_args.h @@ -29,7 +29,7 @@ typedef struct { uint64 virtual_end; uint64 page_hole; // smp stuff - uint32 apic_time_cv_factor; // apic ticks per second + uint32 _unused; // previously: apic ticks per second uint32 apic_phys; FixedWidthPointer apic; uint32 ioapic_phys; diff --git a/src/system/boot/platform/bios_ia32/smp.cpp b/src/system/boot/platform/bios_ia32/smp.cpp index 3286b005c6..68acf3f830 100644 --- a/src/system/boot/platform/bios_ia32/smp.cpp +++ b/src/system/boot/platform/bios_ia32/smp.cpp @@ -44,8 +44,6 @@ static struct scan_spots_struct smp_scan_spots[] = { { 0, 0, 0 } }; -extern "C" void execute_n_instructions(int count); - extern "C" void smp_trampoline(void); extern "C" void smp_trampoline_end(void); @@ -319,41 +317,6 @@ smp_do_acpi_config(void) } -static void -calculate_apic_timer_conversion_factor(void) -{ - int64 t1, t2; - uint32 config; - uint32 count; - - // setup the timer - config = apic_read(APIC_LVT_TIMER); - config = (config & APIC_LVT_TIMER_MASK) + APIC_LVT_MASKED; - // timer masked, vector 0 - apic_write(APIC_LVT_TIMER, config); - - config = (apic_read(APIC_TIMER_DIVIDE_CONFIG) & ~0x0000000f); - apic_write(APIC_TIMER_DIVIDE_CONFIG, config | APIC_TIMER_DIVIDE_CONFIG_1); - // divide clock by one - - t1 = system_time(); - apic_write(APIC_INITIAL_TIMER_COUNT, 0xffffffff); // start the counter - - execute_n_instructions(128 * 20000); - - count = apic_read(APIC_CURRENT_TIMER_COUNT); - t2 = system_time(); - - count = 0xffffffff - count; - - gKernelArgs.arch_args.apic_time_cv_factor - = (uint32)((1000000.0/(t2 - t1)) * count); - - dprintf("APIC ticks/sec = %d\n", - gKernelArgs.arch_args.apic_time_cv_factor); -} - - // #pragma mark - @@ -403,9 +366,6 @@ smp_init_other_cpus(void) dprintf("smp: apic (mapped) = %p\n", (void *)gKernelArgs.arch_args.apic); - // calculate how fast the apic timer is - calculate_apic_timer_conversion_factor(); - if (gKernelArgs.num_cpus < 2) return; diff --git a/src/system/boot/platform/bios_ia32/support.S b/src/system/boot/platform/bios_ia32/support.S index 442b72dcb5..c6a70e1401 100644 --- a/src/system/boot/platform/bios_ia32/support.S +++ b/src/system/boot/platform/bios_ia32/support.S @@ -7,29 +7,6 @@ #define FUNCTION(x) .global x; .type x,@function; x -FUNCTION(execute_n_instructions): - movl 4(%esp), %ecx - shrl $4, %ecx -.again: - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - loop .again - ret - null_idt_descr: .word 0 .word 0,0 diff --git a/src/system/boot/platform/efi/arch/x86/Jamfile b/src/system/boot/platform/efi/arch/x86/Jamfile index 32e5143072..f353dfa097 100644 --- a/src/system/boot/platform/efi/arch/x86/Jamfile +++ b/src/system/boot/platform/efi/arch/x86/Jamfile @@ -20,7 +20,6 @@ for platform in [ MultiBootSubDirSetup efi ] { crt0-efi-$(TARGET_ARCH).S entry.S smp_trampoline.S - support.S relocation_func.cpp arch_mmu.cpp arch_smp.cpp diff --git a/src/system/boot/platform/efi/arch/x86/arch_smp.cpp b/src/system/boot/platform/efi/arch/x86/arch_smp.cpp index fd0f283c6b..56435b5fc3 100644 --- a/src/system/boot/platform/efi/arch/x86/arch_smp.cpp +++ b/src/system/boot/platform/efi/arch/x86/arch_smp.cpp @@ -36,8 +36,6 @@ #endif -extern "C" void execute_n_instructions(int count); - void copy_trampoline_code(uint64 trampolineCode, uint64 trampolineStack); void prepare_trampoline_args(uint64 trampolineCode, uint64 trampolineStack, uint32 pagedir, uint64 kernelEntry, addr_t virtKernelArgs, @@ -125,43 +123,6 @@ acpi_do_smp_config(void) } -static void -calculate_apic_timer_conversion_factor(void) -{ - int64 t1, t2; - uint32 config; - uint32 count; - - TRACE("calculating apic timer conversion factor\n"); - - // setup the timer - config = apic_read(APIC_LVT_TIMER); - config = (config & APIC_LVT_TIMER_MASK) + APIC_LVT_MASKED; - // timer masked, vector 0 - apic_write(APIC_LVT_TIMER, config); - - config = (apic_read(APIC_TIMER_DIVIDE_CONFIG) & ~0x0000000f); - apic_write(APIC_TIMER_DIVIDE_CONFIG, config | APIC_TIMER_DIVIDE_CONFIG_1); - // divide clock by one - - t1 = system_time(); - apic_write(APIC_INITIAL_TIMER_COUNT, 0xffffffff); // start the counter - - execute_n_instructions(128 * 20000); - - count = apic_read(APIC_CURRENT_TIMER_COUNT); - t2 = system_time(); - - count = 0xffffffff - count; - - gKernelArgs.arch_args.apic_time_cv_factor - = (uint32)((1000000.0/(t2 - t1)) * count); - - TRACE("APIC ticks/sec = %" B_PRId32 "\n", - gKernelArgs.arch_args.apic_time_cv_factor); -} - - // #pragma mark - @@ -211,9 +172,6 @@ arch_smp_init_other_cpus(void) TRACE("smp: apic (mapped) = %lx\n", (addr_t)gKernelArgs.arch_args.apic.Pointer()); - // calculate how fast the apic timer is - calculate_apic_timer_conversion_factor(); - if (gKernelArgs.num_cpus < 2) return; diff --git a/src/system/boot/platform/efi/arch/x86/support.S b/src/system/boot/platform/efi/arch/x86/support.S deleted file mode 100644 index 4fe95030bc..0000000000 --- a/src/system/boot/platform/efi/arch/x86/support.S +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2021-2022 Haiku, Inc. All rights reserved. - * Released under the terms of the MIT License. - * - * Copyright 2001, Travis Geiselbrecht. All rights reserved. - * Distributed under the terms of the NewOS License. - */ - - -#define FUNCTION(x) .global x; .type x,@function; x - - -FUNCTION(execute_n_instructions): - movl 4(%esp), %ecx - shrl $4, %ecx -.again: - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - loop .again - ret - diff --git a/src/system/boot/platform/efi/arch/x86_64/Jamfile b/src/system/boot/platform/efi/arch/x86_64/Jamfile index 57dbca2481..86bb0484f3 100644 --- a/src/system/boot/platform/efi/arch/x86_64/Jamfile +++ b/src/system/boot/platform/efi/arch/x86_64/Jamfile @@ -19,7 +19,6 @@ for platform in [ MultiBootSubDirSetup efi ] { crt0-efi-$(TARGET_ARCH).S entry.S long_smp_trampoline.S - support.S relocation_func.cpp arch_start.cpp arch_smp.cpp diff --git a/src/system/boot/platform/efi/arch/x86_64/support.S b/src/system/boot/platform/efi/arch/x86_64/support.S deleted file mode 100644 index 4c77461fae..0000000000 --- a/src/system/boot/platform/efi/arch/x86_64/support.S +++ /dev/null @@ -1,31 +0,0 @@ -/* -** Copyright 2001, Travis Geiselbrecht. All rights reserved. -** Distributed under the terms of the NewOS License. -*/ - - -#define FUNCTION(x) .global x; .type x,@function; x - - -FUNCTION(execute_n_instructions): - movl %edi, %ecx - shrl $4, %ecx -.again: - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - xorl %eax, %eax - loop .again - ret diff --git a/src/system/kernel/arch/x86/apic.cpp b/src/system/kernel/arch/x86/apic.cpp index 2226519915..e06408412f 100644 --- a/src/system/kernel/arch/x86/apic.cpp +++ b/src/system/kernel/arch/x86/apic.cpp @@ -236,6 +236,16 @@ apic_set_lvt_initial_timer_count(uint32 config) } +uint32 +apic_lvt_current_timer_count() +{ + if (sX2APIC) + return x86_read_msr(IA32_MSR_APIC_CURRENT_TIMER_COUNT); + else + return apic_read(APIC_CURRENT_TIMER_COUNT); +} + + uint32 apic_lvt_timer_divide_config() { diff --git a/src/system/kernel/arch/x86/timers/x86_apic.cpp b/src/system/kernel/arch/x86/timers/x86_apic.cpp index c8c2351acb..4116a980ad 100644 --- a/src/system/kernel/arch/x86/timers/x86_apic.cpp +++ b/src/system/kernel/arch/x86/timers/x86_apic.cpp @@ -1,6 +1,7 @@ /* + * Copyright 2025, Haiku, Inc. All rights reserved. * Copyright 2008, Dustin Howett, dustin.howett@gmail.com. All rights reserved. - * Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -106,19 +107,62 @@ apic_timer_clear_hardware_timer() } +// #pragma mark - initialization + + +static uint32 +calculate_apic_timer_conversion_factor() +{ + // setup the timer + uint32 config = apic_lvt_timer() & APIC_LVT_TIMER_MASK; + config |= APIC_LVT_MASKED; + // timer masked, vector 0 + apic_set_lvt_timer(config); + + config = (apic_lvt_timer_divide_config() & ~0xf); + apic_set_lvt_timer_divide_config(config | APIC_TIMER_DIVIDE_CONFIG_1); + // divide clock by one + + apic_set_lvt_initial_timer_count(UINT32_MAX); // start the counter + + // Use CPUID as a fence (same as in TSC calibration). + asm volatile ("cpuid" : : : "eax", "ebx", "ecx", "edx"); + int64 t1 = system_time_nsecs(); + uint32 startCount = apic_lvt_current_timer_count(); + + spin(5000); + + asm volatile ("cpuid" : : : "eax", "ebx", "ecx", "edx"); + int64 t2 = system_time_nsecs(); + uint32 endCount = apic_lvt_current_timer_count(); + + uint32 count = startCount - endCount; + + uint32 factor + = (uint32)(((double(1) * 1000 * 1000 * 1000) / (t2 - t1)) * count); + + dprintf("APIC timer frequency: %d\n", factor); + + return factor; +} + + static status_t apic_timer_init(struct kernel_args *args) { if (!apic_available()) return B_ERROR; - sApicTicsPerSec = args->arch_args.apic_time_cv_factor; + sApicTicsPerSec = calculate_apic_timer_conversion_factor(); reserve_io_interrupt_vectors(1, 0xfb - ARCH_INTERRUPT_BASE, INTERRUPT_TYPE_LOCAL_IRQ); install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, &apic_timer_interrupt, NULL, B_NO_LOCK_VECTOR); + apic_timer_per_cpu_init(args, 0); + // will be called on non-boot CPUs by apic_per_cpu_init() + return B_OK; } @@ -136,5 +180,6 @@ apic_timer_per_cpu_init(struct kernel_args *args, int32 cpu) config = apic_lvt_timer_divide_config() & 0xfffffff0; config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1 apic_set_lvt_timer_divide_config(config); + return B_OK; }