diff --git a/.vscode/settings.json b/.vscode/settings.json index 1930ef11..c450b567 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -112,7 +112,8 @@ "time.h": "c", "ia64_msi.h": "c", "errno.h": "c", - "bug.h": "c" + "bug.h": "c", + "apic_timer.h": "c" }, "C_Cpp.errorSquiggles": "Enabled", "esbonio.sphinx.confDir": "" diff --git a/kernel/common/cpu.c b/kernel/common/cpu.c index 2b64a8f3..e6845008 100644 --- a/kernel/common/cpu.c +++ b/kernel/common/cpu.c @@ -26,6 +26,8 @@ uint Cpu_Processor_Type; uint Cpu_max_phys_addrline_size; // 处理器支持的最大线性地址可寻址地址线宽度 uint Cpu_max_linear_addrline_size; +// 处理器的tsc频率(单位:hz)(HPET定时器在测定apic频率时,顺便测定了这个值) +uint64_t Cpu_tsc_freq = 0; struct cpu_core_info_t cpu_core_info[MAX_CPU_NUM]; void cpu_init(void) @@ -115,6 +117,6 @@ uint32_t cpu_get_core_crysral_freq() : "0"(0x15), "2"(0) : "memory"); // kdebug("Cpu_cpuid_max_Basic_mop = %#03x, a=%ld, b=%ld, c=%ld, d=%ld", Cpu_cpuid_max_Basic_mop, a, b, c, d); - + return c; } \ No newline at end of file diff --git a/kernel/common/cpu.h b/kernel/common/cpu.h index c51b3fd9..f034a2c7 100644 --- a/kernel/common/cpu.h +++ b/kernel/common/cpu.h @@ -29,39 +29,41 @@ extern uint32_t Cpu_max_phys_addrline_size; // 处理器支持的最大线性地址可寻址地址线宽度 extern uint32_t Cpu_max_linear_addrline_size; +// 处理器的tsc频率(单位:hz)(HPET定时器在测定apic频率时,顺便测定了这个值) +extern uint64_t Cpu_tsc_freq; + /** * @brief 执行cpuid指令 - * + * * @param mop 主功能号 * @param sop 子功能号 * @param eax 结果的eax值 * @param ebx 结果的ebx值 * @param ecx 结果的ecx值 * @param edx 结果的edx值 - * + * * cpuid指令参考英特尔开发手册卷2A Chapter3 3.2 Instruction */ -void cpu_cpuid(uint32_t mop, uint32_t sop, uint32_t *eax, uint32_t*ebx, uint32_t*ecx, uint32_t*edx); +void cpu_cpuid(uint32_t mop, uint32_t sop, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); /** * @brief 初始化获取处理器信息模块 - * + * */ void cpu_init(void); struct cpu_core_info_t { - uint64_t stack_start; // 栈基地址 - uint64_t ist_stack_start; // IST栈基地址 - uint64_t tss_vaddr; // tss地址 + uint64_t stack_start; // 栈基地址 + uint64_t ist_stack_start; // IST栈基地址 + uint64_t tss_vaddr; // tss地址 }; extern struct cpu_core_info_t cpu_core_info[MAX_CPU_NUM]; - /** * @brief 获取当前cpu核心晶振频率 - * + * * @return uint32_t 当前cpu核心晶振频率 */ uint32_t cpu_get_core_crysral_freq(); \ No newline at end of file diff --git a/kernel/common/glib.h b/kernel/common/glib.h index 8c34ad85..10ee3f69 100644 --- a/kernel/common/glib.h +++ b/kernel/common/glib.h @@ -10,6 +10,7 @@ #include #include #include +#include #define sti() __asm__ __volatile__("sti\n\t" :: \ : "memory") //开启外部中断 @@ -27,6 +28,13 @@ #define io_lfence() __asm__ __volatile__("lfence\n\t" :: \ : "memory") // 在lfence指令前的读操作必须在lfence指令后的读操作前完成。 +#define rdtsc() ({ \ + uint64_t tmp1 = 0, tmp2 = 0; \ + asm volatile("rdtsc" \ + : "=d"(tmp1), "=a"(tmp2)::"memory"); \ + (tmp1 << 32 | tmp2); \ +}) + /** * @brief 根据结构体变量内某个成员变量member的基地址,计算出该结构体变量的基地址 * @param ptr 指向结构体变量内的成员变量member的指针 @@ -170,7 +178,7 @@ static inline struct List *list_next(struct List *entry) //计算字符串的长度(经过测试,该版本比采用repne/scasb汇编的运行速度快16.8%左右) static inline int strlen(const char *s) { - if(s == NULL) + if (s == NULL) return 0; register int __res = 0; while (s[__res] != '\0') @@ -182,10 +190,10 @@ static inline int strlen(const char *s) /** * @brief 测量字符串的长度 - * + * * @param src 字符串 * @param maxlen 最大长度 - * @return long + * @return long */ long strnlen(const char *src, unsigned long maxlen); @@ -213,14 +221,14 @@ void *memset(void *dst, unsigned char C, ul size) return dst; } -void *memset_c(void* dst, uint8_t c, size_t count) +void *memset_c(void *dst, uint8_t c, size_t count) { - uint8_t* xs = (uint8_t*)dst; - - while (count--) - *xs++ = c; - - return dst; + uint8_t *xs = (uint8_t *)dst; + + while (count--) + *xs++ = c; + + return dst; } /** @@ -233,7 +241,7 @@ void *memset_c(void* dst, uint8_t c, size_t count) */ static void *memcpy(void *dst, const void *src, long Num) { - int d0=0, d1=0, d2=0; + int d0 = 0, d1 = 0, d2 = 0; __asm__ __volatile__("cld \n\t" "rep \n\t" "movsq \n\t" @@ -283,7 +291,6 @@ int strcmp(char *FirstPart, char *SecondPart) return __res; } - // 从io口读入8个bit unsigned char io_in8(unsigned short port) { diff --git a/kernel/driver/timers/HPET/HPET.c b/kernel/driver/timers/HPET/HPET.c index a038afe2..bc347b4d 100644 --- a/kernel/driver/timers/HPET/HPET.c +++ b/kernel/driver/timers/HPET/HPET.c @@ -18,7 +18,13 @@ static uint32_t HPET_COUNTER_CLK_PERIOD = 0; // 主计数器时间精度(单 static double HPET_freq = 0; // 主计时器频率 static uint8_t HPET_NUM_TIM_CAP = 0; // 定时器数量 static char measure_apic_timer_flag; // 初始化apic时钟时所用到的标志变量 -extern struct rtc_time_t rtc_now; // 导出全局墙上时钟 + +// 测定tsc频率的临时变量 +static uint64_t test_tsc_start = 0; +static uint64_t test_tsc_end = 0; +extern uint64_t Cpu_tsc_freq; // 导出自cpu.c + +extern struct rtc_time_t rtc_now; // 导出全局墙上时钟 enum { @@ -91,11 +97,12 @@ void HPET_handler(uint64_t number, uint64_t param, struct pt_regs *regs) } /** - * @brief 测量apic定时器频率的中断回调函数 + * @brief 测定apic定时器以及tsc的频率的中断回调函数 * */ -void HPET_measure_apic_timer_handler(uint64_t number, uint64_t param, struct pt_regs *regs) +void HPET_measure_handler(uint64_t number, uint64_t param, struct pt_regs *regs) { + test_tsc_end = rdtsc(); // 停止apic定时器 // 写入每1ms的ticks apic_timer_stop(); @@ -104,10 +111,10 @@ void HPET_measure_apic_timer_handler(uint64_t number, uint64_t param, struct pt_ } /** - * @brief 测定apic定时器的频率 + * @brief 测定apic定时器以及tsc的频率 * */ -void HPET_measure_apic_timer_freq() +void HPET_measure_freq() { kinfo("Measuring local APIC timer's frequency..."); const uint64_t interval = APIC_TIMER_INTERVAL; // 测量给定时间内的计数 @@ -136,7 +143,7 @@ void HPET_measure_apic_timer_freq() measure_apic_timer_flag = false; // 注册中断 - irq_register(34, &entry, &HPET_measure_apic_timer_handler, 0, &HPET_intr_controller, "HPET0 measure"); + irq_register(34, &entry, &HPET_measure_handler, 0, &HPET_intr_controller, "HPET0 measure"); // 设置div16 apic_timer_stop(); @@ -148,6 +155,8 @@ void HPET_measure_apic_timer_freq() // 启动apic定时器 apic_timer_set_LVT(151, 0, APIC_LVT_Timer_One_Shot); *(uint64_t *)(HPET_REG_BASE + GEN_CONF) = 3; // 置位旧设备中断路由兼容标志位、定时器组使能标志位,开始计时 + // 顺便测定tsc频率 + test_tsc_start = rdtsc(); io_mfence(); while (measure_apic_timer_flag == false) @@ -158,6 +167,10 @@ void HPET_measure_apic_timer_freq() *(uint64_t *)(HPET_REG_BASE + GEN_CONF) = 0; // 停用HPET定时器 io_mfence(); kinfo("Local APIC timer's freq: %d ticks/ms.", apic_timer_ticks_result); + // 计算tsc频率 + Cpu_tsc_freq = (test_tsc_end - test_tsc_start) * (1000UL / interval); + + kinfo("TSC frequency: %ldMHz", Cpu_tsc_freq / 1000000); } /** diff --git a/kernel/driver/timers/HPET/HPET.h b/kernel/driver/timers/HPET/HPET.h index fd035689..4e1124b7 100644 --- a/kernel/driver/timers/HPET/HPET.h +++ b/kernel/driver/timers/HPET/HPET.h @@ -10,10 +10,10 @@ int HPET_init(); /** - * @brief 测定apic定时器的频率 + * @brief 测定apic定时器以及tsc的频率 * */ -void HPET_measure_apic_timer_freq(); +void HPET_measure_freq(); /** * @brief 启用HPET周期中断(5ms) diff --git a/kernel/main.c b/kernel/main.c index fcfc9b2f..f91b1d6e 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -144,7 +144,7 @@ void system_initialize() // process_init(); HPET_init(); - HPET_measure_apic_timer_freq(); + HPET_measure_freq(); // current_pcb->preempt_count = 0; // kdebug("cpu_get_core_crysral_freq()=%ld", cpu_get_core_crysral_freq());