Split lapic and ioapic code

This commit is contained in:
Thomas Oltmann 2026-07-08 20:45:51 +02:00
parent 398aac9e2c
commit 7ddeeeca86
5 changed files with 137 additions and 128 deletions

View file

@ -10,9 +10,9 @@ CFLAGS += -DINIT_ASSERTED
# Add new source files (C or Assembler) here,
# preferentially in alphabetical order.
KERNEL_SOURCES_x86_64 := \
src/x86_64/apic.c \
src/x86_64/cmos.c \
src/x86_64/interrupt.S \
src/x86_64/lapic.c \
src/x86_64/loadcs.S \
src/x86_64/uart.c \
src/x86_64/string.S \
@ -22,6 +22,7 @@ KERNEL_SOURCES_x86_64 := \
src/x86_64/address.c \
src/x86_64/ps2_driver.c \
src/x86_64/hwclock.c \
src/x86_64/ioapic.c \
# end of x86_64 specific kernel sources list
# Architecture-agnostic kernel sources.

View file

@ -25,15 +25,21 @@ uint64_t get_cr4(void);
#define X86_ASM_INT(value) __asm__("int $" #value :: )
// Read Model Specific Register (32 or 64 bit)
uint64_t readmsr(uint32_t msr);
// Write Model Specific Register (32 or 64 bit)
void writemsr(uint32_t msr, uint64_t value);
// write-back invalidate
void wbinvd(void);
// Read Time-Stamp Counter
static inline uint64_t
rdtsc(void)
{
uint32_t lo, hi;
__asm__ ("rdtsc\n\t" : "=a"(lo), "=d"(hi));
return lo | ((uint64_t)hi << 32);
uint32_t lo, hi;
__asm__ ("rdtsc\n\t" : "=a"(lo), "=d"(hi));
return lo | ((uint64_t)hi << 32);
}
#endif

View file

@ -52,17 +52,17 @@ uint64_t get_cr4(void) {
return cr4;
}
uint64_t
readmsr(uint32_t msr)
{
uint32_t lo, hi;
__asm__ ("rdmsr\n\t" : "=a"(lo), "=d"(hi) : "c"(msr));
return lo | ((uint64_t)hi << 32);
uint64_t readmsr(uint32_t msr) {
uint32_t lo, hi;
__asm__ ("rdmsr\n\t" : "=a"(lo), "=d"(hi) : "c"(msr));
return lo | ((uint64_t)hi << 32);
}
void
writemsr(uint32_t msr, uint64_t value)
{
uint32_t lo = value, hi = value >> 32;
__asm__ ("wrmsr\n\t" :: "c"(msr), "a"(lo), "d"(hi));
void writemsr(uint32_t msr, uint64_t value) {
uint32_t lo = value, hi = value >> 32;
__asm__ ("wrmsr\n\t" :: "c"(msr), "a"(lo), "d"(hi));
}
void wbinvd(void) {
__asm__ volatile ("wbinvd" ::: "memory");
}

View file

@ -1,4 +1,4 @@
#define SUBSYSTEM "apic"
#define SUBSYSTEM "ioapic"
#include "x86_64/asm.h"
#include "x86_64/apic.h"
#include "address.h"
@ -7,118 +7,6 @@
#include "acpi.h"
#include "std.h"
#define LAPIC_BASE_PHYS 0xFEE00000
#define SPURIOUS_VECTOR_APIC_ENABLE 0x100
#define LVT_TIMER_PERIODIC_BIT (1 << 17)
static inline void
wbinvd(void)
{
__asm__ volatile ("wbinvd" : : : "memory");
}
struct lapic_register {
uint32_t value;
uint32_t padding[3];
};
struct lapic {
struct lapic_register reserved0[2];
struct lapic_register lapic_id;
struct lapic_register lapic_version;
struct lapic_register reserved1[4];
struct lapic_register task_priority;
struct lapic_register arbitration_priority;
struct lapic_register processor_priority;
struct lapic_register eoi;
struct lapic_register remote_read;
struct lapic_register logical_destination;
struct lapic_register destination_format;
struct lapic_register spurious_vector;
struct lapic_register in_service[8];
struct lapic_register trigger_mode[8];
struct lapic_register request[8];
struct lapic_register error_status;
struct lapic_register reserved2[6];
struct lapic_register cmci;
struct lapic_register command[2];
struct lapic_register lvt_timer;
struct lapic_register lvt_thermal_sensor;
struct lapic_register lvt_perfmon_counter;
struct lapic_register lvt_lint0;
struct lapic_register lvt_lint1;
struct lapic_register lvt_error;
struct lapic_register timer_initial;
struct lapic_register timer_current;
struct lapic_register reserved3[4];
struct lapic_register timer_divisor;
struct lapic_register reserved4[1];
};
STATIC_ASSERT(sizeof (struct lapic) == 0x400);
#define LAPIC_ADDR ((volatile struct lapic *)pa_to_pointer(pa_from_value(LAPIC_BASE_PHYS)))
void lapic_init(void)
{
ASSERT((LAPIC_ADDR->lapic_version.value & 0xff) <= 0x15);
LAPIC_ADDR->spurious_vector.value = SPURIOUS_VECTOR_APIC_ENABLE | 0xff;
wbinvd();
}
unsigned lapic_get_id(void)
{
return LAPIC_ADDR->lapic_id.value >> 24;
}
unsigned int cpu_get_core_id(void) {
return lapic_get_id();
}
void lapic_eoi(void)
{
LAPIC_ADDR->eoi.value = 0;
wbinvd();
}
void lapic_unset_timer(void)
{
LAPIC_ADDR->lvt_timer.value = 0xFF | (1 << 16);
wbinvd();
}
void lapic_set_timer_periodic(int vector, uint32_t count)
{
LAPIC_ADDR->timer_divisor.value = 0xb;
wbinvd();
LAPIC_ADDR->lvt_timer.value = vector | LVT_TIMER_PERIODIC_BIT;
wbinvd();
LAPIC_ADDR->timer_initial.value = count;
wbinvd();
}
void lapic_set_timer_oneshot(int vector, uint32_t count)
{
LAPIC_ADDR->timer_divisor.value = 0xb;
wbinvd();
LAPIC_ADDR->lvt_timer.value = vector;
wbinvd();
LAPIC_ADDR->timer_initial.value = count;
wbinvd();
}
uint32_t lapic_get_timer_value(void)
{
return LAPIC_ADDR->timer_current.value;
}
uint32_t lapic_get_timer_initial(void)
{
return LAPIC_ADDR->timer_initial.value;
}
#define IOAPICID 0x00
#define IOAPICVER 0x01
#define IOAPICARB 0x02

114
src/x86_64/lapic.c Normal file
View file

@ -0,0 +1,114 @@
#define SUBSYSTEM "lapic"
#include "x86_64/asm.h"
#include "x86_64/apic.h"
#include "address.h"
#include "x86_64/interrupt.h"
#include "x86_64/asm.h"
#include "acpi.h"
#include "std.h"
#define LAPIC_BASE_PHYS 0xFEE00000
#define SPURIOUS_VECTOR_APIC_ENABLE 0x100
#define LVT_TIMER_PERIODIC_BIT (1 << 17)
struct lapic_register {
uint32_t value;
uint32_t padding[3];
};
struct lapic {
struct lapic_register reserved0[2];
struct lapic_register lapic_id;
struct lapic_register lapic_version;
struct lapic_register reserved1[4];
struct lapic_register task_priority;
struct lapic_register arbitration_priority;
struct lapic_register processor_priority;
struct lapic_register eoi;
struct lapic_register remote_read;
struct lapic_register logical_destination;
struct lapic_register destination_format;
struct lapic_register spurious_vector;
struct lapic_register in_service[8];
struct lapic_register trigger_mode[8];
struct lapic_register request[8];
struct lapic_register error_status;
struct lapic_register reserved2[6];
struct lapic_register cmci;
struct lapic_register command[2];
struct lapic_register lvt_timer;
struct lapic_register lvt_thermal_sensor;
struct lapic_register lvt_perfmon_counter;
struct lapic_register lvt_lint0;
struct lapic_register lvt_lint1;
struct lapic_register lvt_error;
struct lapic_register timer_initial;
struct lapic_register timer_current;
struct lapic_register reserved3[4];
struct lapic_register timer_divisor;
struct lapic_register reserved4[1];
};
STATIC_ASSERT(sizeof (struct lapic) == 0x400);
#define LAPIC_ADDR ((volatile struct lapic *)pa_to_pointer(pa_from_value(LAPIC_BASE_PHYS)))
void lapic_init(void)
{
ASSERT((LAPIC_ADDR->lapic_version.value & 0xff) <= 0x15);
LAPIC_ADDR->spurious_vector.value = SPURIOUS_VECTOR_APIC_ENABLE | 0xff;
wbinvd();
}
unsigned lapic_get_id(void)
{
return LAPIC_ADDR->lapic_id.value >> 24;
}
unsigned int cpu_get_core_id(void) {
return lapic_get_id();
}
void lapic_eoi(void)
{
LAPIC_ADDR->eoi.value = 0;
wbinvd();
}
void lapic_unset_timer(void)
{
LAPIC_ADDR->lvt_timer.value = 0xFF | (1 << 16);
wbinvd();
}
void lapic_set_timer_periodic(int vector, uint32_t count)
{
LAPIC_ADDR->timer_divisor.value = 0xb;
wbinvd();
LAPIC_ADDR->lvt_timer.value = vector | LVT_TIMER_PERIODIC_BIT;
wbinvd();
LAPIC_ADDR->timer_initial.value = count;
wbinvd();
}
void lapic_set_timer_oneshot(int vector, uint32_t count)
{
LAPIC_ADDR->timer_divisor.value = 0xb;
wbinvd();
LAPIC_ADDR->lvt_timer.value = vector;
wbinvd();
LAPIC_ADDR->timer_initial.value = count;
wbinvd();
}
uint32_t lapic_get_timer_value(void)
{
return LAPIC_ADDR->timer_current.value;
}
uint32_t lapic_get_timer_initial(void)
{
return LAPIC_ADDR->timer_initial.value;
}