-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapic.c
103 lines (76 loc) · 3.24 KB
/
apic.c
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
/*****************************************************************************/
/* File: apic.c */
/* */
/* Description: Source file for IOAPIC and Local APIC code. */
/* */
/* Author: Shoily O Rahman <[email protected]> */
/* */
/* Date: Aug 2, 2020 */
/* */
/*****************************************************************************/
#include "apic.h"
#include "page32.h"
#include "util.h"
#include "system.h"
#include "setup32.h"
#include "debug.h"
int lapic_present = 0;
int lapic_base_register;
int lapic_id;
extern addr_t _kernel_pg_dir;
int __attribute__((regparm(0))) lapic_read_register(int lapic_register) {
return *((int*)(lapic_base_register+lapic_register));
}
void lapic_write_register(int lapic_register, int value) {
*((int*)(lapic_base_register+lapic_register)) = value;
}
extern int lapic_calibration_tick;
extern bool lapic_calibration_mode;
extern bool lapic_timer_enabled;
void calibrate_lapic_timer() {
lapic_write_register(LAPIC_LVT_TIMER_REG, LAPIC_IDT_VECTOR | 0x20000); // Periodic timer on vector 32.
lapic_write_register(LAPIC_DIVIDE_CONFIGURATION_REG, LAPIC_DIVIDE_CONFIG_VALUE); // Divide by 128
lapic_calibration_mode = true;
lapic_write_register(LAPIC_INITIAL_COUNTER_REG, LAPIC_COUNTER_VALUE);
pit_wait_ms(1);
lapic_write_register(LAPIC_INITIAL_COUNTER_REG, 0);
lapic_calibration_mode = false;
lapic_timer_enabled = true;
lapic_write_register(LAPIC_INITIAL_COUNTER_REG, LAPIC_COUNTER_VALUE);
}
void init_lapic() {
int eax, edx;
int local_lapic_present = 0;
__asm__ __volatile__("movl $1, %%eax;"
"cpuid;"
"andl $0x200, %%edx;"
"shrl $9, %%edx;"
"movl %%edx, %0;"
: "=r" (local_lapic_present)
:
: "%eax", "%edx", "memory"
);
printf(KERNEL_INFO, "Local APIC present: %d ", local_lapic_present);
if (!local_lapic_present) {
return;
}
read_msr(0x1b, &eax, &edx);
lapic_base_register = eax & 0xfffff000;
map_kernel_with_pagetable(lapic_base_register, lapic_base_register, PAGE_SIZE, PTE_WRITE, 0);
printf(KERNEL_INFO, "Local APIC address: %p ", eax);
lapic_id = lapic_read_register(LAPIC_ID_REG) >> 24;
printf(KERNEL_INFO, "Local APIC id: %x\n", lapic_id);
// enable receiving interrupt
lapic_write_register(LAPIC_SPURIOUS_REG, lapic_read_register(LAPIC_SPURIOUS_REG)| 0x100);
lapic_present = local_lapic_present;
calibrate_lapic_timer();
}
void lapic_switch(bool enable) {
int value;
value = lapic_read_register(LAPIC_SPURIOUS_REG);
if (enable)
value |= 0x1ff;
else
value &= ~0x1ff;
lapic_write_register(LAPIC_SPURIOUS_REG, value);
}