1 #include "apic_timer.h"
2 #include <common/kprint.h>
3 #include <exception/irq.h>
4 #include <process/process.h>
5 #include <sched/sched.h>
6
7 // #pragma GCC push_options
8 // #pragma GCC optimize("O0")
9 uint64_t apic_timer_ticks_result = 0;
10 static spinlock_t apic_timer_init_lock = {1};
11 // bsp 是否已经完成apic时钟初始化
12 static bool bsp_initialized = false;
13
14 /**
15 * @brief 初始化AP核的apic时钟
16 *
17 */
apic_timer_ap_core_init()18 void apic_timer_ap_core_init()
19 {
20 while (!bsp_initialized)
21 {
22 pause();
23 }
24
25 apic_timer_init();
26 }
27
apic_timer_enable(uint64_t irq_num)28 void apic_timer_enable(uint64_t irq_num)
29 {
30 // 启动apic定时器
31 io_mfence();
32 uint64_t val = apic_timer_get_LVT();
33 io_mfence();
34 val &= (~APIC_LVT_INT_MASKED);
35 io_mfence();
36 apic_timer_write_LVT(val);
37 io_mfence();
38 }
39
apic_timer_disable(uint64_t irq_num)40 void apic_timer_disable(uint64_t irq_num)
41 {
42 apic_timer_stop();
43 }
44
45 /**
46 * @brief 安装local apic定时器中断
47 *
48 * @param irq_num 中断向量号
49 * @param arg 初始计数值
50 * @return uint64_t
51 */
apic_timer_install(ul irq_num,void * arg)52 uint64_t apic_timer_install(ul irq_num, void *arg)
53 {
54 // 设置div16
55 io_mfence();
56 apic_timer_stop();
57 io_mfence();
58 apic_timer_set_div(APIC_TIMER_DIVISOR);
59 io_mfence();
60
61 // 设置初始计数
62 apic_timer_set_init_cnt(*(uint64_t *)arg);
63 io_mfence();
64 // 填写LVT
65 apic_timer_set_LVT(APIC_TIMER_IRQ_NUM, 1, APIC_LVT_Timer_Periodic);
66 io_mfence();
67 }
68
apic_timer_uninstall(ul irq_num)69 void apic_timer_uninstall(ul irq_num)
70 {
71 apic_timer_write_LVT(APIC_LVT_INT_MASKED);
72 io_mfence();
73 }
74
75 hardware_intr_controller apic_timer_intr_controller = {
76 .enable = apic_timer_enable,
77 .disable = apic_timer_disable,
78 .install = apic_timer_install,
79 .uninstall = apic_timer_uninstall,
80 .ack = apic_local_apic_edge_ack,
81 };
82
83 /**
84 * @brief local apic定时器的中断处理函数
85 *
86 * @param number 中断向量号
87 * @param param 参数
88 * @param regs 寄存器值
89 */
apic_timer_handler(uint64_t number,uint64_t param,struct pt_regs * regs)90 void apic_timer_handler(uint64_t number, uint64_t param, struct pt_regs *regs)
91 {
92 io_mfence();
93 sched_update_jiffies();
94 io_mfence();
95 }
96
97 /**
98 * @brief 初始化local APIC定时器
99 *
100 */
apic_timer_init()101 void apic_timer_init()
102 {
103
104 if (apic_timer_ticks_result == 0)
105 {
106 kBUG("APIC timer ticks in 5ms is equal to ZERO!");
107 while (1)
108 hlt();
109 }
110 spin_lock(&apic_timer_init_lock);
111 kinfo("Initializing apic timer for cpu %d", proc_current_cpu_id);
112 io_mfence();
113 irq_register(APIC_TIMER_IRQ_NUM, &apic_timer_ticks_result, &apic_timer_handler, 0, &apic_timer_intr_controller,
114 "apic timer");
115 io_mfence();
116 if (proc_current_cpu_id == 0)
117 {
118 bsp_initialized = true;
119 }
120 spin_unlock(&apic_timer_init_lock);
121 // kinfo("Successfully initialized apic timer for cpu %d", proc_current_cpu_id);
122 }