1/* @title: LAPIC */
2#pragma once
3#include <asm.h>
4#include <console/printf.h>
5#include <drivers/mmio.h>
6#include <smp/core.h>
7#include <stdbool.h>
8#include <stdint.h>
9
10#define LAPIC_ICR_LOW 0x300
11#define LAPIC_ICR_HIGH 0x310
12
13#define LAPIC_DELIVERY_FIXED (0x0 << 8)
14#define LAPIC_DELIVERY_LOWEST (0x1 << 8)
15#define LAPIC_DELIVERY_SMI (0x2 << 8)
16#define LAPIC_DELIVERY_NMI (0x4 << 8)
17#define LAPIC_DELIVERY_INIT (0x5 << 8)
18#define LAPIC_DELIVERY_STARTUP (0x6 << 8)
19
20#define LAPIC_LEVEL_ASSERT (1 << 14)
21#define LAPIC_TRIGGER_EDGE (0 << 15)
22#define LAPIC_TRIGGER_LEVEL (1 << 15)
23#define LAPIC_IPI_IN_FLIGHT (1u << 12)
24#define LAPIC_DEST_PHYSICAL (0 << 11)
25#define LAPIC_DEST_LOGICAL (1 << 11)
26
27#define LAPIC_DEST_SHIFT 24
28
29#define LAPIC_REG_ID 0x020
30#define LAPIC_REG_EOI 0x0B0
31#define LAPIC_REG_SVR 0x0F0
32
33#define LAPIC_REG_LVT_TIMER 0x320
34#define LAPIC_REG_TIMER_INIT 0x380
35#define LAPIC_REG_TIMER_CUR 0x390
36#define LAPIC_REG_TIMER_DIV 0x3E0
37#define LAPIC_LVT_MASK (1 << 16)
38#define LAPIC_ENABLE 0x100
39#define LAPIC_SPURIOUS_REGISTER 0xF0
40
41#define IA32_X2APIC_BASE 0x800
42#define IA32_X2APIC_ID (IA32_X2APIC_BASE + 0x02)
43#define IA32_X2APIC_EOI (IA32_X2APIC_BASE + 0x0B)
44#define IA32_X2APIC_SVR (IA32_X2APIC_BASE + 0x0F)
45#define IA32_X2APIC_LVT_TIMER (IA32_X2APIC_BASE + 0x32)
46
47#define IA32_X2APIC_TIMER_INIT (IA32_X2APIC_BASE + 0x38)
48#define IA32_X2APIC_TIMER_CUR (IA32_X2APIC_BASE + 0x39)
49#define IA32_X2APIC_TIMER_DIV (IA32_X2APIC_BASE + 0x3E)
50
51extern uint32_t *lapic;
52extern bool x2apic_enabled;
53static inline uint32_t lapic_reg_to_x2apic_msr(uint32_t reg) {
54 switch (reg) {
55 case LAPIC_REG_ID: return IA32_X2APIC_ID;
56 case LAPIC_REG_EOI: return IA32_X2APIC_EOI;
57 case LAPIC_REG_SVR: return IA32_X2APIC_SVR;
58 case LAPIC_REG_LVT_TIMER: return IA32_X2APIC_LVT_TIMER;
59 case LAPIC_REG_TIMER_INIT: return IA32_X2APIC_TIMER_INIT;
60 case LAPIC_REG_TIMER_CUR: return IA32_X2APIC_TIMER_CUR;
61 case LAPIC_REG_TIMER_DIV: return IA32_X2APIC_TIMER_DIV;
62 default: return 0;
63 }
64}
65
66static inline void lapic_write(uint32_t reg, uint32_t val) {
67 if (x2apic_enabled) {
68 uint32_t msr = lapic_reg_to_x2apic_msr(reg);
69 if (!msr)
70 return;
71 wrmsr(msr, value: val);
72 } else {
73 mmio_write_32(address: (uint32_t *) ((uintptr_t) lapic + reg), value: val);
74 }
75}
76
77static inline uint32_t lapic_read(uint32_t reg) {
78 if (x2apic_enabled) {
79 uint32_t msr = lapic_reg_to_x2apic_msr(reg);
80 if (!msr)
81 return 0;
82 return (uint32_t) rdmsr(msr);
83 } else {
84 return mmio_read_32(address: (uint32_t *) ((uintptr_t) lapic + reg));
85 }
86}
87
88#define TIMER_VECTOR 0x20
89#define TIMER_MODE_PERIODIC (1 << 17)
90#define IA32_APIC_BASE 0x1B
91#define APIC_X2APIC_ENABLE (1 << 10)
92
93#define IA32_X2APIC_ICR 0x830
94#define LAPIC_LEVEL_ASSERT (1 << 14)
95
96void lapic_init();
97void lapic_timer_init(cpu_id_t core_id);
98uint64_t lapic_get_id(void);
99uint32_t cpu_get_this_id(void);
100void lapic_timer_disable();
101bool lapic_timer_is_enabled();
102void lapic_timer_enable();
103void lapic_timer_set_ms(uint32_t ms);
104void panic_broadcast(size_t exclude_core);
105void x2apic_init();
106
107void ipi_send(uint32_t apic_id, uint8_t vector);
108void nmi_send(uint32_t apic_id);
109struct irq_chip *lapic_get_chip();
110#define IA32_APIC_BASE_MSR 0x1B
111#define IA32_APIC_BASE_MASK 0xFFFFF000UL
112#define IA32_APIC_BASE_ENABLE (1 << 11)
113