kernel/x86: Avoid using any initial values in APIC timer registers.

We should just be zeroing any unknown bits, not trying to preserve them.
If the BIOS or other mechanisms left the timer in some other mode
besides "one-shot" like we need, then we might incorrectly preserve
those bits.

This also has the advantage of avoiding config reads in set_hardware_timer.
This commit is contained in:
Augustin Cavalier
2026-05-21 15:01:17 -04:00
parent faa27a36dd
commit 5dfc0663d5
2 changed files with 29 additions and 38 deletions
-3
View File
@@ -68,9 +68,6 @@
/* Local Vector Table defines */
#define APIC_LVT_MASKED (1 << 16)
// timer defines
#define APIC_LVT_TIMER_MASK 0xfffcef00
// LINT0/1 defines
#define APIC_LVT_LINT_MASK 0xfffe0800
#define APIC_LVT_LINT_INPUT_POLARITY (1 << 13)
+29 -35
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2025, Haiku, Inc. All rights reserved.
* Copyright 2025-2026, Haiku, Inc. All rights reserved.
* Copyright 2008, Dustin Howett, [email protected]. All rights reserved.
* Copyright 2002-2010, Axel Dörfler, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
@@ -28,21 +28,8 @@
#endif
/* Method Prototypes */
static int apic_timer_get_priority();
static status_t apic_timer_set_hardware_timer(bigtime_t relativeTimeout);
static status_t apic_timer_clear_hardware_timer();
static status_t apic_timer_init(struct kernel_args *args);
static uint32 sApicTicsPerSec = 0;
struct timer_info gAPICTimer = {
"APIC",
&apic_timer_get_priority,
&apic_timer_set_hardware_timer,
&apic_timer_clear_hardware_timer,
&apic_timer_init
};
static uint32 sApicTimerConfigBase = 0;
static int
@@ -72,13 +59,13 @@ apic_timer_set_hardware_timer(bigtime_t relativeTimeout)
cpu_status state = disable_interrupts();
uint32 config = apic_lvt_timer() | APIC_LVT_MASKED; // mask the timer
apic_set_lvt_timer(config);
// mask the timer
apic_set_lvt_timer(sApicTimerConfigBase | APIC_LVT_MASKED);
apic_set_lvt_initial_timer_count(0); // zero out the timer
config &= ~APIC_LVT_MASKED; // unmask the timer
apic_set_lvt_timer(config);
// unmask the timer
apic_set_lvt_timer(sApicTimerConfigBase);
TRACE("arch_smp_set_apic_timer: config 0x%" B_PRIx32 ", timeout %" B_PRIdBIGTIME
", tics/sec %" B_PRIu32 ", tics %" B_PRId64 "\n", config, relativeTimeout,
@@ -97,11 +84,11 @@ apic_timer_clear_hardware_timer()
{
cpu_status state = disable_interrupts();
uint32 config = apic_lvt_timer() | APIC_LVT_MASKED;
// mask the timer
apic_set_lvt_timer(config);
// mask the timer
apic_set_lvt_timer(sApicTimerConfigBase | APIC_LVT_MASKED);
apic_set_lvt_initial_timer_count(0); // zero out the timer
// zero out the timer
apic_set_lvt_initial_timer_count(0);
restore_interrupts(state);
return B_OK;
@@ -115,13 +102,11 @@ static uint32
calculate_apic_timer_conversion_factor()
{
// setup the timer
uint32 config = apic_lvt_timer() & APIC_LVT_TIMER_MASK;
config |= APIC_LVT_MASKED;
uint32 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);
apic_set_lvt_timer_divide_config(APIC_TIMER_DIVIDE_CONFIG_1);
// divide clock by one
apic_set_lvt_initial_timer_count(UINT32_MAX); // start the counter
@@ -181,6 +166,8 @@ apic_timer_init(struct kernel_args *args)
install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE,
&apic_timer_interrupt, NULL, B_NO_LOCK_VECTOR);
sApicTimerConfigBase = 0xfb; // one-shot mode, vector 0xfb
apic_timer_per_cpu_init(args, 0);
// will be called on non-boot CPUs by apic_per_cpu_init()
@@ -191,16 +178,23 @@ apic_timer_init(struct kernel_args *args)
status_t
apic_timer_per_cpu_init(struct kernel_args *args, int32 cpu)
{
/* setup timer */
uint32 config = apic_lvt_timer() & APIC_LVT_TIMER_MASK;
config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked
apic_set_lvt_timer(config);
// setup timer
apic_set_lvt_timer(sApicTimerConfigBase | APIC_LVT_MASKED);
apic_set_lvt_initial_timer_count(0); // zero out the clock
// zero out the clock
apic_set_lvt_initial_timer_count(0);
config = apic_lvt_timer_divide_config() & 0xfffffff0;
config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1
apic_set_lvt_timer_divide_config(config);
// clock division by 1
apic_set_lvt_timer_divide_config(APIC_TIMER_DIVIDE_CONFIG_1);
return B_OK;
}
struct timer_info gAPICTimer = {
"APIC",
&apic_timer_get_priority,
&apic_timer_set_hardware_timer,
&apic_timer_clear_hardware_timer,
&apic_timer_init
};