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 }