PatchworkOS
Loading...
Searching...
No Matches
apic.c
Go to the documentation of this file.
2
4#include <kernel/cpu/cpu.h>
5#include <kernel/cpu/smp.h>
8#include <kernel/log/log.h>
9#include <kernel/log/panic.h>
10#include <kernel/mem/vmm.h>
11#include <kernel/sched/timer.h>
12#include <kernel/utils/utils.h>
13
14#include <assert.h>
15#include <kernel/defs.h>
16
17static bool initialized = false;
18static madt_t* madt;
20
21static uint64_t lapic_init(void)
22{
23 void* lapicPhysAddr = (void*)(uint64_t)madt->localInterruptControllerAddress;
24 if (lapicPhysAddr == NULL)
25 {
26 LOG_ERR("madt has invalid lapic address\n");
27 return ERR;
28 }
29
30 lapicBase = (uintptr_t)PML_LOWER_TO_HIGHER(lapicPhysAddr);
31 if (vmm_map(NULL, (void*)lapicBase, lapicPhysAddr, PAGE_SIZE, PML_WRITE | PML_GLOBAL | PML_PRESENT, NULL, NULL) ==
32 NULL)
33 {
34 LOG_ERR("failed to map local apic\n");
35 return ERR;
36 }
37
38 LOG_INFO("local apic mapped base=0x%016lx phys=0x%016lx\n", lapicBase, lapicPhysAddr);
39 return 0;
40}
41
43{
45
46 ioapic_t* ioapic;
47 MADT_FOR_EACH(madt, ioapic)
48 {
50 {
51 continue;
52 }
53
54 void* physAddr = (void*)(uint64_t)ioapic->ioApicAddress;
55 void* virtAddr = (void*)PML_LOWER_TO_HIGHER(physAddr);
56 if (vmm_map(NULL, virtAddr, physAddr, PAGE_SIZE, PML_WRITE | PML_GLOBAL | PML_PRESENT, NULL, NULL) == NULL)
57 {
58 LOG_ERR("failed to map io apic\n");
59 return ERR;
60 }
61
62 uint32_t maxRedirs = ioapic_get_version(ioapic).maxRedirs;
63 // Mask all interrupts.
64 for (uint32_t i = 0; i < maxRedirs; i++)
65 {
66 ioapic_redirect_entry_t maskedEntry = {.mask = 1};
67 ioapic_write(ioapic, IOAPIC_REG_REDIRECTION(i, 0), maskedEntry.raw.low);
68 ioapic_write(ioapic, IOAPIC_REG_REDIRECTION(i, 1), maskedEntry.raw.high);
69 }
70
71 LOG_INFO("io apic initialized base=0x%016lx gsiBase=%u maxRedirs=%u\n", virtAddr,
72 ioapic->globalSystemInterruptBase, maxRedirs);
73 }
74
75 return 0;
76}
77
79{
80 madt = (madt_t*)table;
81 if (initialized)
82 {
83 LOG_ERR("multiple MADT tables found\n");
84 return ERR;
85 }
86 initialized = true;
87
88 if (lapic_init() == ERR)
89 {
90 LOG_ERR("failed to initialize local apic\n");
91 return ERR;
92 }
93
94 if (ioapic_all_init() == ERR)
95 {
96 LOG_ERR("failed to initialize ioapics\n");
97 return ERR;
98 }
99
100 return 0;
101}
102
104
118
120{
121 if (!initialized)
122 {
123 panic(NULL, "apic timer calibration used before apic initialized");
124 }
125
127
131
133
135
139
140 uint64_t ticksPerNs = (ticks << APIC_TIMER_TICKS_FIXED_POINT_OFFSET) / 10000000ULL;
141
142 LOG_DEBUG("timer calibration ticks=%llu ticks_per_ns=%llu\n", ticks, ticksPerNs);
144 return ticksPerNs;
145}
146
170
172{
173 if (!initialized)
174 {
175 panic(NULL, "local apic used before apic initialized");
176 }
177
179}
180
182{
183 if (!initialized)
184 {
185 panic(NULL, "local apic used before apic initialized");
186 }
187
188 WRITE_32(lapicBase + reg, value);
189}
190
192{
193 if (!initialized)
194 {
195 panic(NULL, "local apic used before apic initialized");
196 }
197
198 return READ_32(lapicBase + reg);
199}
200
202{
203 if (!initialized)
204 {
205 panic(NULL, "local apic used before apic initialized");
206 }
207
210}
211
212void lapic_send_sipi(lapic_id_t id, void* entryPoint)
213{
214 if (!initialized)
215 {
216 panic(NULL, "local apic used before apic initialized");
217 }
218
219 assert((uintptr_t)entryPoint % PAGE_SIZE == 0);
220
223}
224
226{
227 if (!initialized)
228 {
229 panic(NULL, "local apic used before apic initialized");
230 }
231
234}
235
236void lapic_eoi(void)
237{
238 if (!initialized)
239 {
240 panic(NULL, "local apic used before apic initialized");
241 }
242
244}
245
247{
248 if (!initialized)
249 {
250 panic(NULL, "ioapic used before apic initialized");
251 }
252
254 WRITE_32(base + IOAPIC_MMIO_REG_SELECT, reg);
255 return READ_32(base + IOAPIC_MMIO_REG_DATA);
256}
257
259{
260 if (!initialized)
261 {
262 panic(NULL, "ioapic used before apic initialized");
263 }
264
266 WRITE_32(base + IOAPIC_MMIO_REG_SELECT, reg);
267 WRITE_32(base + IOAPIC_MMIO_REG_DATA, value);
268}
269
271{
272 if (!initialized)
273 {
274 panic(NULL, "ioapic used before apic initialized");
275 }
276
277 ioapic_version_t version;
278 version.raw = ioapic_read(ioapic, IOAPIC_REG_VERSION);
279 return version;
280}
281
283{
284 if (!initialized)
285 {
286 panic(NULL, "ioapic used before apic initialized");
287 }
288
289 ioapic_t* ioapic;
290 MADT_FOR_EACH(madt, ioapic)
291 {
293 {
294 continue;
295 }
296
297 ioapic_version_t version = ioapic_get_version(ioapic);
298 if (ioapic->globalSystemInterruptBase <= gsi && ioapic->globalSystemInterruptBase + version.maxRedirs > gsi)
299 {
300 return ioapic;
301 }
302 }
303
304 panic(NULL, "Failed to locate vector for gsi %d", gsi);
305}
306
308 ioapic_polarity_t polarity, ioapic_trigger_mode_t triggerMode, cpu_t* cpu, bool enable)
309{
310 if (!initialized)
311 {
312 panic(NULL, "ioapic used before apic initialized");
313 }
314
315 ioapic_redirect_entry_t redirect = {
316 .vector = vector,
317 .deliveryMode = deliveryMode,
318 .deliveryStatus = 0,
319 .polarity = polarity,
320 .remoteIRR = 0,
321 .triggerMode = triggerMode,
322 .mask = enable ? 0 : 1,
323 .destination = cpu->lapicId,
324 };
325
326 ioapic_t* ioapic = ioapic_from_gsi(gsi);
327 uint32_t pin = gsi - ioapic->globalSystemInterruptBase;
328
329 ioapic_write(ioapic, IOAPIC_REG_REDIRECTION(pin, 0), redirect.raw.low);
330 ioapic_write(ioapic, IOAPIC_REG_REDIRECTION(pin, 1), redirect.raw.high);
331
332 LOG_INFO("ioapic redirect set gsi=%u vector=0x%02x cpu=%u enable=%d\n", gsi, vector, cpu->id, enable);
333}
static madt_t * madt
Definition apic.c:18
static uint64_t lapic_init(void)
Definition apic.c:21
static uint64_t ioapic_all_init(void)
Definition apic.c:42
static uintptr_t lapicBase
Definition apic.c:19
static uint64_t apic_init(sdt_header_t *table)
Definition apic.c:78
static bool initialized
Definition apic.c:17
#define assert(expression)
Definition assert.h:29
#define CLOCKS_PER_SEC
Definition clock_t.h:15
#define ACPI_SDT_HANDLER_REGISTER(sig, initHandler)
Macro to register an ACPI SDT handler.
Definition tables.h:276
#define MADT_FOR_EACH(madt, ic)
Iterate over all MADT interrupt controllers.
Definition tables.h:195
#define MADT_SIGNATURE
MADT table signature.
Definition tables.h:204
#define INTERRUPT_CONTROLLER_IO_APIC
Definition tables.h:124
void interrupt_disable(void)
Disable interrupts and increment the disableDepth.
Definition interrupt.c:26
void interrupt_enable(void)
Decrement the CLI depth and enable interrupts if depth reaches zero and interrupts were previously en...
Definition interrupt.c:38
interrupt_t
CPU vector identifiers.
Definition interrupt.h:97
static cpu_t * smp_self_unsafe(void)
Returns a pointer to the cpu_t structure of the current CPU.
Definition smp.h:90
ioapic_delivery_mode_t
IO APIC Delivery Modes.
Definition apic.h:203
#define IOAPIC_REG_REDIRECTION(pin, high)
Macro to get the redirection entry register for a specific pin.
Definition apic.h:169
ioapic_register_t
IO APIC Registers.
Definition apic.h:155
#define LAPIC_REG_ICR1_ID_OFFSET
The offset at which the lapic id is stored in the LAPIC_REG_ID register.
Definition apic.h:105
void ioapic_write(ioapic_t *ioapic, ioapic_register_t reg, uint32_t value)
Write to an IOAPIC register.
Definition apic.c:258
uint64_t apic_timer_ticks_per_ns(void)
Apic timer ticks per nanosecond.
Definition apic.c:119
ioapic_polarity_t
IO APIC Polarity Modes.
Definition apic.h:237
void lapic_cpu_init(void)
Initialize the local apic for the current cpu.
Definition apic.c:147
void lapic_eoi(void)
Send an End Of Interrupt (EOI) signal to the local apic.
Definition apic.c:236
void ioapic_set_redirect(interrupt_t vector, ioapic_gsi_t gsi, ioapic_delivery_mode_t deliveryMode, ioapic_polarity_t polarity, ioapic_trigger_mode_t triggerMode, cpu_t *cpu, bool enable)
Set an IOAPIC redirection entry.
Definition apic.c:307
void apic_timer_one_shot(interrupt_t vector, uint32_t ticks)
Configure the apic timer in one-shot mode.
Definition apic.c:105
void lapic_send_init(lapic_id_t id)
Send an INIT IPI to a local apic.
Definition apic.c:201
uint32_t ioapic_gsi_t
IO APIC Global System Interrupt type.
Definition apic.h:32
void lapic_send_sipi(lapic_id_t id, void *entryPoint)
Send a Startup IPI to a local apic.
Definition apic.c:212
ioapic_version_t ioapic_get_version(ioapic_t *ioapic)
Get the IOAPIC version.
Definition apic.c:270
lapic_id_t lapic_self_id(void)
Get the lapic id of the current cpu.
Definition apic.c:171
uint32_t ioapic_read(ioapic_t *ioapic, ioapic_register_t reg)
Read from an IOAPIC register.
Definition apic.c:246
#define APIC_TIMER_TICKS_FIXED_POINT_OFFSET
APIC Timer Ticks Fixed Point Offset.
Definition apic.h:176
ioapic_trigger_mode_t
IO APIC Trigger Modes.
Definition apic.h:227
uint8_t lapic_id_t
Local APIC ID type.
Definition apic.h:24
void lapic_send_ipi(lapic_id_t id, interrupt_t vector)
Send an Inter-Processor Interrupt (IPI) to a local apic.
Definition apic.c:225
ioapic_t * ioapic_from_gsi(ioapic_gsi_t gsi)
Get the IOAPIC id responsible for a given GSI.
Definition apic.c:282
lapic_register_t
Local APIC Registers.
Definition apic.h:73
uint32_t lapic_read(lapic_register_t reg)
Read from a local apic register.
Definition apic.c:191
void lapic_write(lapic_register_t reg, uint32_t value)
Write to a local apic register.
Definition apic.c:181
@ LAPIC_LVT_MASKED
Definition apic.h:114
@ LAPIC_SPURIOUS_ENABLE
Definition apic.h:113
@ IOAPIC_REG_VERSION
Definition apic.h:156
@ APIC_TIMER_ONE_SHOT
Definition apic.h:42
@ APIC_TIMER_MASKED
Timer is masked (disabled)
Definition apic.h:40
@ LAPIC_MSR_BSP
Definition apic.h:65
@ LAPIC_MSR_ENABLE
Definition apic.h:64
@ APIC_TIMER_DIV_DEFAULT
Definition apic.h:55
@ IOAPIC_MMIO_REG_DATA
Definition apic.h:147
@ IOAPIC_MMIO_REG_SELECT
Definition apic.h:146
@ LAPIC_ICR_CLEAR_INIT_LEVEL
Definition apic.h:137
@ LAPIC_REG_TASK_PRIORITY
Definition apic.h:76
@ LAPIC_REG_TIMER_CURRENT_COUNT
Definition apic.h:98
@ LAPIC_REG_TIMER_INITIAL_COUNT
Definition apic.h:97
@ LAPIC_REG_LVT_PERFCTR
Definition apic.h:93
@ LAPIC_REG_TIMER_DIVIDER
Definition apic.h:99
@ LAPIC_REG_LVT_THERMAL
Definition apic.h:92
@ LAPIC_REG_LVT_LINT0
Definition apic.h:94
@ LAPIC_REG_ID
Definition apic.h:74
@ LAPIC_REG_LVT_ERROR
Definition apic.h:96
@ LAPIC_REG_ICR1
Definition apic.h:90
@ LAPIC_REG_EOI
Definition apic.h:79
@ LAPIC_REG_LVT_LINT1
Definition apic.h:95
@ LAPIC_REG_SPURIOUS
Definition apic.h:83
@ LAPIC_REG_ICR0
Definition apic.h:89
@ LAPIC_REG_LVT_TIMER
Definition apic.h:91
@ LAPIC_ICR_STARTUP
Definition apic.h:128
@ LAPIC_ICR_INIT
Definition apic.h:127
void hpet_wait(clock_t nanoseconds)
Wait for a specified number of nanoseconds using the HPET.
Definition hpet.c:104
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:362
#define LOG_ERR(format,...)
Definition log.h:89
#define LOG_INFO(format,...)
Definition log.h:87
#define LOG_DEBUG(format,...)
Definition log.h:81
#define PML_LOWER_TO_HIGHER(addr)
Converts an address from the lower half to the higher half.
@ PML_PRESENT
@ PML_WRITE
@ PML_GLOBAL
void * vmm_map(space_t *space, void *virtAddr, void *physAddr, uint64_t length, pml_flags_t flags, space_callback_func_t func, void *private)
Maps physical memory to virtual memory in a given address space.
Definition vmm.c:231
#define PAGE_SIZE
Memory page size.
Definition proc.h:140
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
void pic_disable(void)
Definition pic.c:7
static void msr_write(uint32_t msr, uint64_t value)
Definition regs.h:71
static uint64_t msr_read(uint32_t msr)
Definition regs.h:63
#define MSR_LAPIC
Definition regs.h:12
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
__UINTPTR_TYPE__ uintptr_t
Definition stdint.h:43
#define UINT32_MAX
Definition stdint.h:70
CPU structure.
Definition cpu.h:42
cpuid_t id
Definition cpu.h:43
lapic_id_t lapicId
Definition cpu.h:44
interrupt_controller_type_t type
Definition tables.h:132
uint32_t high
Definition apic.h:265
uint32_t low
Definition apic.h:264
IO APIC.
Definition tables.h:167
uint32_t ioApicAddress
Definition tables.h:171
uint32_t globalSystemInterruptBase
Definition tables.h:172
interrupt_controller_header_t header
Definition tables.h:168
IO APIC Version Structure.
Definition apic.h:185
uint32_t raw
Definition apic.h:187
uint8_t maxRedirs
Definition apic.h:192
Multiple APIC Description Table.
Definition tables.h:182
uint32_t localInterruptControllerAddress
Definition tables.h:184
System Description Table Header.
Definition acpi.h:90
IO APIC Redirection Entry Structure.
Definition apic.h:248
struct ioapic_redirect_entry_t::PACKED raw
#define WRITE_32(address, value)
Definition utils.h:10
#define READ_32(address)
Definition utils.h:9