mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-10 16:26:48 +00:00
108 lines
2.9 KiB
C
108 lines
2.9 KiB
C
#pragma once
|
||
|
||
#include <common/unistd.h>
|
||
#include "apic.h"
|
||
|
||
extern uint64_t apic_timer_ticks_result;
|
||
// 5ms产生一次中断
|
||
#define APIC_TIMER_INTERVAL 5
|
||
#define APIC_TIMER_DIVISOR 3
|
||
|
||
#define APIC_TIMER_IRQ_NUM 151
|
||
|
||
#pragma GCC push_options
|
||
#pragma GCC optimize("O0")
|
||
|
||
/**
|
||
* @brief 设置apic定时器的分频计数
|
||
*
|
||
* @param divider 分频除数
|
||
*/
|
||
static __always_inline void apic_timer_set_div(uint64_t divider)
|
||
{
|
||
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
|
||
wrmsr(0x83e, divider);
|
||
else
|
||
*(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_CLKDIV) = (uint32_t)divider;
|
||
}
|
||
|
||
/**
|
||
* @brief 设置apic定时器的初始计数值
|
||
*
|
||
* @param init_cnt 初始计数值
|
||
*/
|
||
static __always_inline void apic_timer_set_init_cnt(uint32_t init_cnt)
|
||
{
|
||
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
|
||
wrmsr(0x838, init_cnt);
|
||
else
|
||
*(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG) = (uint32_t)init_cnt;
|
||
}
|
||
|
||
/**
|
||
* @brief 设置apic定时器的lvt,并启动定时器
|
||
*
|
||
* @param vector 中断向量号
|
||
* @param mask 是否屏蔽(1:屏蔽, 0:不屏蔽)
|
||
* @param mode 计时模式
|
||
*/
|
||
static __always_inline void apic_timer_set_LVT(uint32_t vector, uint32_t mask, uint32_t mode)
|
||
{
|
||
register uint32_t val = (mode << 17) | vector | (mask ? (APIC_LVT_INT_MASKED) : 0);
|
||
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
|
||
wrmsr(0x832, val);
|
||
else
|
||
*(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER) = (uint32_t)val;
|
||
}
|
||
|
||
static __always_inline void apic_timer_write_LVT(uint32_t value)
|
||
{
|
||
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
|
||
wrmsr(0x832, value);
|
||
else
|
||
*(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER) = (uint32_t)value;
|
||
}
|
||
|
||
/**
|
||
* @brief 获取apic定时器的LVT的值
|
||
*
|
||
*/
|
||
static __always_inline uint32_t apic_timer_get_LVT()
|
||
{
|
||
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
|
||
return rdmsr(0x832);
|
||
else
|
||
return *(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER);
|
||
}
|
||
|
||
/**
|
||
* @brief 获取apic定时器当前计数值
|
||
*
|
||
*/
|
||
static __always_inline uint32_t apic_timer_get_current()
|
||
{
|
||
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
|
||
return (uint32_t)rdmsr(0x839);
|
||
else
|
||
return *(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG);
|
||
}
|
||
|
||
/**
|
||
* @brief 停止apic定时器
|
||
*
|
||
*/
|
||
#define apic_timer_stop() \
|
||
do \
|
||
{ \
|
||
uint32_t val = apic_timer_get_LVT(); \
|
||
val |= APIC_LVT_INT_MASKED; \
|
||
apic_timer_write_LVT(val); \
|
||
} while (0)
|
||
|
||
/**
|
||
* @brief 初始化local APIC定时器
|
||
*
|
||
*/
|
||
void apic_timer_init();
|
||
|
||
#pragma GCC pop_options |