Browse Source

:new: 测定tsc频率

fslongjin 2 years ago
parent
commit
4bc64de8f9

+ 2 - 1
.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": ""

+ 3 - 1
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;
 }

+ 11 - 9
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();

+ 19 - 12
kernel/common/glib.h

@@ -10,6 +10,7 @@
 #include <stdint.h>
 #include <common/stddef.h>
 #include <arch/arch.h>
+#include <common/compiler.h>
 
 #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)
 {

+ 19 - 6
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);
 }
 
 /**

+ 2 - 2
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)

+ 1 - 1
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());