MOS Source Code
Loading...
Searching...
No Matches
lapic.c
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
5#include <mos/mos_global.h>
7#include <mos/syslog/printk.h>
8#include <mos/x86/acpi/madt.h>
9#include <mos/x86/cpu/cpu.h>
10#include <mos/x86/cpu/cpuid.h>
14
15#define APIC_REG_LAPIC_VERSION 0x30
16#define APIC_REG_PRIO_TASK 0x80
17#define APIC_REG_PRIO_ARBITRATION 0x90
18#define APIC_REG_PRIO_PROCESSOR 0xA0
19#define APIC_REG_EOI 0xB0
20#define APIC_REG_REMOTE_READ 0xC0
21#define APIC_REG_LOGICAL_DEST 0xD0
22#define APIC_REG_DEST_FORMAT 0xE0
23#define APIC_REG_SPURIOUS_INTR_VEC 0xF0
24#define APIC_REG_ERROR_STATUS 0x280
25#define APIC_REG_TIMER_INITIAL_COUNT 0x380
26#define APIC_REG_TIMER_CURRENT_COUNT 0x390
27#define APIC_REG_TIMER_DIVIDE_CONFIG 0x3E0
28
29#define APIC_REG_LVT_CMCI_INTR 0x2F0
30#define APIC_REG_LVT_TIMER 0x320
31#define APIC_REG_LVT_THERMAL_SENSOR 0x330
32#define APIC_REG_LVT_PERF_MON_CTR 0x340
33#define APIC_REG_LVT_LINT0 0x350
34#define APIC_REG_LVT_LINT1 0x360
35#define APIC_REG_LVT_ERROR 0x370
36
37#define APIC_IN_SERVICE_REG_BEGIN 0x100
38#define APIC_IN_SERVICE_REG_END 0x170
39
40#define APIC_TRIGGER_MODE_REG_BEGIN 0x180
41#define APIC_TRIGGER_MODE_REG_END 0x1F0
42
43#define APIC_TRIGGER_MODE_REG_TMR_BEGIN 0x180
44#define APIC_TRIGGER_MODE_REG_TMR_END 0x1F0
45
46#define APIC_INTERRUPT_REQUEST_REG_BEGIN 0x200
47#define APIC_INTERRUPT_REQUEST_REG_END 0x270
48
49#define APIC_INTERRUPT_COMMAND_REG_BEGIN 0x300
50#define APIC_INTERRUPT_COMMAND_REG_END 0x310
51
52#define IA32_APIC_BASE_MSR 0x1B
53
54static ptr_t lapic_regs = 0;
55
57{
59 pr_dinfo2(x86_lapic, "reading reg: %x, ptr: " PTR_FMT, offset, lapic_regs + offset);
60 return *(volatile u32 *) (lapic_regs + offset);
61}
62
64{
66 pr_dinfo2(x86_lapic, "reading reg: %x, ptr: " PTR_FMT, offset, lapic_regs + offset);
67 const u32 high = *(volatile u32 *) (lapic_regs + offset + 0x10);
68 const u32 low = *(volatile u32 *) (lapic_regs + offset);
69 return ((u64) high << 32) | low;
70}
71
72void lapic_write32(u32 offset, u32 value)
73{
75 pr_dinfo2(x86_lapic, "writing reg: %x, value: 0x%.8x, ptr: " PTR_FMT, offset, value, lapic_regs + offset);
76 *(volatile u32 *) (lapic_regs + offset) = value;
77}
78
79void lapic_write64(u32 offset, u64 value)
80{
82 pr_dinfo2(x86_lapic, "writing reg: %x, value: 0x%.16llx, ptr: " PTR_FMT, offset, value, lapic_regs + offset);
83 *(volatile u32 *) (lapic_regs + offset + 0x10) = value >> 32;
84 *(volatile u32 *) (lapic_regs + offset) = value;
85}
86
87static void lapic_wait_sent(void)
88{
89 // Wait for the delivery status bit to be set
91 ;
92}
93
94void lapic_interrupt_full(u8 vec, u8 dest, lapic_delivery_mode_t delivery_mode, lapic_dest_mode_t dest_mode, bool level, bool trigger, lapic_shorthand_t shorthand)
95{
96 u64 value = 0;
97 value |= SET_BITS(0, 8, vec); // Interrupt Vector
98 value |= SET_BITS(8, 3, delivery_mode); // Delivery mode
99 value |= SET_BITS(11, 1, dest_mode); // Logical destination mode
100 value |= SET_BITS(12, 1, 0); // Delivery status (0)
101 value |= SET_BITS(14, 1, level); // Level
102 value |= SET_BITS(15, 1, trigger); // Trigger mode
103 value |= SET_BITS(18, 2, shorthand); // Destination shorthand
104 value |= SET_BITS(56, 8, (u64) dest); // Destination
105
109}
110
111void lapic_interrupt(u8 vec, u8 dest, lapic_delivery_mode_t delivery_mode, lapic_dest_mode_t dest_mode, lapic_shorthand_t shorthand)
112{
113 lapic_interrupt_full(vec, dest, delivery_mode, dest_mode, true, false, shorthand);
114}
115
116static void lapic_memory_setup(void)
117{
119 mos_panic("APIC is not supported");
120
122 mos_panic("MSR is not supported");
123
124 const ptr_t base_addr = x86_acpi_madt->lapic_addr;
125 pr_dinfo2(x86_lapic, "base address: " PTR_FMT, base_addr);
126
127 if (!pmm_find_reserved_region(base_addr))
128 {
129 pr_info("LAPIC: reserve " PTR_FMT, base_addr);
130 pmm_reserve_address(base_addr);
131 }
132
133 lapic_regs = pa_va(base_addr);
134}
135
136void lapic_enable(void)
137{
138 if (once())
140
141 // (https://wiki.osdev.org/APIC#Local_APIC_configuration)
142 // To enable the Local APIC to receive interrupts it is necessary to configure the "Spurious Interrupt Vector Register".
143 // The correct value for this field is
144 // - the IRQ number that you want to map the spurious interrupts to within the lowest 8 bits, and
145 // - the 8th bit set to 1
146 // to actually enable the APIC
147 const u32 spurious_intr_vec = lapic_read32(APIC_REG_SPURIOUS_INTR_VEC) | 0x100;
148 lapic_write32(APIC_REG_SPURIOUS_INTR_VEC, spurious_intr_vec);
149}
150
151void lapic_set_timer(u32 initial_count)
152{
153 lapic_write32(APIC_REG_TIMER_DIVIDE_CONFIG, 0x3); // divide by 16
154 lapic_write32(APIC_REG_LVT_TIMER, 0x20000 | 32); // periodic timer mode
155 lapic_write32(APIC_REG_TIMER_INITIAL_COUNT, initial_count); // start the timer
156}
157
158void lapic_eoi(void)
159{
161}
lapic_delivery_mode_t
Definition apic.h:10
lapic_shorthand_t
Definition apic.h:27
lapic_dest_mode_t
Definition apic.h:21
#define MOS_ASSERT(cond)
Definition assert.h:14
#define CPU_FEATURE_APIC
Definition cpuid.h:18
#define cpu_has_feature(feat)
Definition cpuid.h:79
#define CPU_FEATURE_MSR
Definition cpuid.h:14
const reg32_t low
Definition fpu_context.c:23
const reg32_t high
Definition fpu_context.c:24
#define pa_va(pa)
Definition mm.h:80
pmm_region_t * pmm_find_reserved_region(ptr_t needle)
Find a region in the physical memory manager.
Definition pmm.c:131
#define pmm_reserve_address(paddr)
Definition pmm.h:116
static ptr_t lapic_regs
Definition lapic.c:54
#define APIC_REG_EOI
Definition lapic.c:19
void lapic_interrupt_full(u8 vec, u8 dest, lapic_delivery_mode_t delivery_mode, lapic_dest_mode_t dest_mode, bool level, bool trigger, lapic_shorthand_t shorthand)
Definition lapic.c:94
void lapic_interrupt(u8 vec, u8 dest, lapic_delivery_mode_t delivery_mode, lapic_dest_mode_t dest_mode, lapic_shorthand_t shorthand)
Definition lapic.c:111
#define APIC_INTERRUPT_COMMAND_REG_BEGIN
Definition lapic.c:49
void lapic_set_timer(u32 initial_count)
Definition lapic.c:151
void lapic_eoi(void)
Definition lapic.c:158
void lapic_write32(u32 offset, u32 value)
Definition lapic.c:72
static void lapic_memory_setup(void)
Definition lapic.c:116
u32 lapic_read32(u32 offset)
Definition lapic.c:56
#define APIC_REG_ERROR_STATUS
Definition lapic.c:24
#define APIC_REG_TIMER_INITIAL_COUNT
Definition lapic.c:25
void lapic_write64(u32 offset, u64 value)
Definition lapic.c:79
u64 lapic_read64(u32 offset)
Definition lapic.c:63
#define APIC_REG_LVT_TIMER
Definition lapic.c:30
void lapic_enable(void)
Definition lapic.c:136
#define APIC_REG_TIMER_DIVIDE_CONFIG
Definition lapic.c:27
#define APIC_REG_SPURIOUS_INTR_VEC
Definition lapic.c:23
static void lapic_wait_sent(void)
Definition lapic.c:87
const acpi_madt_t * x86_acpi_madt
Definition madt.c:11
#define SET_BITS(bit, width, value)
Definition mos_global.h:59
#define BIT(x)
Definition mos_global.h:97
#define once()
Returns true for the first call, false for all subsequent calls.
Definition mos_global.h:114
#define mos_panic(fmt,...)
Definition panic.h:55
#define pr_info(fmt,...)
Definition printk.h:35
#define pr_dinfo2(feat, fmt,...)
Definition printk.h:27
unsigned int u32
Definition types.h:21
#define PTR_FMT
Definition types.h:33
unsigned long ptr_t
Definition types.h:25
unsigned long long u64
Definition types.h:23
unsigned char u8
Definition types.h:19