1 #pragma once
2 
3 #include <common/unistd.h>
4 #include "apic.h"
5 
6 extern uint64_t apic_timer_ticks_result;
7 // 5ms产生一次中断
8 #define APIC_TIMER_INTERVAL 5
9 #define APIC_TIMER_DIVISOR 3
10 
11 #define APIC_TIMER_IRQ_NUM 151
12 
13 #pragma GCC push_options
14 #pragma GCC optimize("O0")
15 
16 /**
17  * @brief 设置apic定时器的分频计数
18  *
19  * @param divider 分频除数
20  */
apic_timer_set_div(uint64_t divider)21 static __always_inline void apic_timer_set_div(uint64_t divider)
22 {
23     if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
24         wrmsr(0x83e, divider);
25     else
26         __write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_CLKDIV, divider);
27 }
28 
29 /**
30  * @brief 设置apic定时器的初始计数值
31  *
32  * @param init_cnt 初始计数值
33  */
apic_timer_set_init_cnt(uint32_t init_cnt)34 static __always_inline void apic_timer_set_init_cnt(uint32_t init_cnt)
35 {
36     if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
37         wrmsr(0x838, init_cnt);
38     else
39         __write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG, init_cnt);
40 }
41 
42 /**
43  * @brief 设置apic定时器的lvt,并启动定时器
44  *
45  * @param vector 中断向量号
46  * @param mask 是否屏蔽(1:屏蔽, 0:不屏蔽)
47  * @param mode 计时模式
48  */
apic_timer_set_LVT(uint32_t vector,uint32_t mask,uint32_t mode)49 static __always_inline void apic_timer_set_LVT(uint32_t vector, uint32_t mask, uint32_t mode)
50 {
51     register uint32_t val = (mode << 17) | vector | (mask ? (APIC_LVT_INT_MASKED) : 0);
52     if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
53         wrmsr(0x832, val);
54     else
55         __write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER, val);
56 }
57 
apic_timer_write_LVT(uint32_t value)58 static __always_inline void apic_timer_write_LVT(uint32_t value)
59 {
60     if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
61         wrmsr(0x832, value);
62     else
63         __write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER, value);
64 }
65 
66 /**
67  * @brief 获取apic定时器的LVT的值
68  *
69  */
apic_timer_get_LVT()70 static __always_inline uint32_t apic_timer_get_LVT()
71 {
72     if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
73         return rdmsr(0x832);
74     else
75         return __read4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER);
76 }
77 
78 /**
79  * @brief 获取apic定时器当前计数值
80  *
81  */
apic_timer_get_current()82 static __always_inline uint32_t apic_timer_get_current()
83 {
84     if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
85         return (uint32_t)rdmsr(0x839);
86     else
87         return __read4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG);
88 }
89 
90 /**
91  * @brief 停止apic定时器
92  *
93  */
94 #define apic_timer_stop()                    \
95     do                                       \
96     {                                        \
97         uint32_t val = apic_timer_get_LVT(); \
98         val |= APIC_LVT_INT_MASKED;          \
99         apic_timer_write_LVT(val);           \
100     } while (0)
101 
102 /**
103  * @brief 初始化local APIC定时器
104  *
105  */
106 void apic_timer_init();
107 
108 #pragma GCC pop_options