blob: 3a14e36e710e3d0e46ebabcd61bb02a23ba35b4c (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
/** @file apic.c
* @brief Code for manipulating the local apic
*
* @author Ryan Pearl (rpearl)
*/
#include <assert.h>
#include <smp/smp.h>
#include <smp/mptable.h>
#include <smp/apic.h>
extern int cpu2apic[MAX_CPUS];
extern int apic2cpu[MAX_CPUS];
/** @brief Read from a local APIC register
*
* @param reg The register offset to read from.
* @return The value of the register.
*/
uint32_t lapic_read(int reg) {
return *(volatile uint32_t *)(LAPIC_VIRT_BASE + reg);
}
/** @brief Write to a local APIC register
*
* @param reg The register offset to write to.
* @param data The data to write
* @return unit
*/
void lapic_write(int reg, uint32_t data) {
*(volatile uint32_t *)(LAPIC_VIRT_BASE + reg) = data;
}
/** @brief Read from the local APIC before it is mapped into virtual memory.
* (It is almost certainly not necessary to call this function)
*
* @param reg The register offset to write to.
* @return The data at that register.
*/
uint32_t lapic_phys_read(int reg) {
return *(volatile uint32_t *)(smp_lapic_base() + reg);
}
/** @brief Write to the local APIC before it is mapped into virtual memory.
* (It is almost certainly not necessary to call this function)
*
* @param reg The register offset to write to.
* @param data The data to write
* @return unit
*/
void lapic_phys_write(int reg, uint32_t data) {
*(volatile uint32_t *)(smp_lapic_base() + reg) = data;
}
/** @brief Initialize the APIC.
*
* @return unit
*/
void apic_init(void) {
lapic_write(LAPIC_SVR, lapic_read(LAPIC_SVR) | LAPIC_ENABLE);
}
/** @brief Return this core's APIC ID.
*
* @return The APIC's ID.
*/
int get_apic_id(void) {
return lapic_read(LAPIC_ID) >> LAPIC_ID_SHIFT;
}
/** @brief Sends an APIC end-of-interrupt command.
*
* @return unit
*/
void apic_eoi(void) {
lapic_write(LAPIC_EOI, 0);
}
/** @brief Send an interprocessor interrupt to a particular target CPU.
*
* @param cpuno The CPU to target
* @param vector The interrupt to send.
*
* @return unit
*/
void apic_ipi_cpu(int cpuno, uint8_t vector) {
assert(cpuno >= 0 && cpuno < MAX_CPUS);
int apic_id = cpu2apic[cpuno];
lapic_write(LAPIC_ICRHI, apic_id << LAPIC_ID_SHIFT);
lapic_write(LAPIC_ICRLO, vector | LAPIC_ASSERT | LAPIC_FIELD);
}
/** @brief Send an interprocessor interrupt to all other CPUs
*
* @param vector The interrupt to send.
*
* @return unit
*/
void apic_ipi_others(uint8_t vector) {
uint32_t val = vector | LAPIC_FIXED | LAPIC_ALLEXC | LAPIC_ASSERT;
lapic_write(LAPIC_ICRLO, val);
}
|