From 33a1e2baad9d5a2326f2c6b8f2888d44fee7b48a Mon Sep 17 00:00:00 2001 From: fslongjin Date: Thu, 1 Sep 2022 21:08:27 +0800 Subject: [PATCH] =?UTF-8?q?bugfix:=20=E5=9C=A8=E7=89=A9=E7=90=86=E6=9C=BA?= =?UTF-8?q?=E4=B8=8A=EF=BC=8C=E7=94=B1=E4=BA=8E=E4=B8=8D=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=9A=84=E5=86=85=E5=AD=98=E8=AE=BF=E9=97=AE=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=EF=BC=8C=E5=AF=BC=E8=87=B4=E6=97=A0=E6=B3=95=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96HPET?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/common/glib.h | 66 ++++++++++++++++++++++- kernel/driver/interrupt/apic/apic.c | 2 +- kernel/driver/interrupt/apic/apic_timer.h | 14 ++--- kernel/driver/timers/HPET/HPET.c | 40 +++++++------- 4 files changed, 93 insertions(+), 29 deletions(-) diff --git a/kernel/common/glib.h b/kernel/common/glib.h index 5989745d..47ef339a 100644 --- a/kernel/common/glib.h +++ b/kernel/common/glib.h @@ -487,7 +487,69 @@ static inline uint64_t copy_to_user(void *dst, void *src, uint64_t size) /** * @brief 这个函数让蜂鸣器发声,目前仅用于真机调试。未来将移除,请勿依赖此函数。 - * + * * @param times 发声循环多少遍 */ -void __experimental_beep(uint64_t times); \ No newline at end of file +void __experimental_beep(uint64_t times); + +/** + * @brief 往指定地址写入8字节 + * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候) + * + * @param vaddr 虚拟地址 + * @param value 要写入的值 + */ +static __always_inline void __write8b(uint64_t vaddr, uint64_t value) +{ + asm volatile("movq %%rdx, 0(%%rax)" ::"a"(vaddr), "d"(value) + : "memory"); + +} + +/** + * @brief 往指定地址写入4字节 + * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候) + * + * @param vaddr 虚拟地址 + * @param value 要写入的值 + */ +static __always_inline void __write4b(uint64_t vaddr, uint32_t value) +{ + asm volatile("movl %%edx, 0(%%rax)" ::"a"(vaddr), "d"(value) + : "memory"); + +} + +/** + * @brief 从指定地址读取8字节 + * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候) + * + * @param vaddr 虚拟地址 + * @return uint64_t 读取到的值 + */ +static __always_inline uint64_t __read8b(uint64_t vaddr) +{ + uint64_t retval; + asm volatile("movq 0(%%rax), %0" + : "=r"(retval) + : "a"(vaddr) + : "memory"); + return retval; +} + +/** + * @brief 从指定地址读取4字节 + * 防止由于编译器优化导致不支持的内存访问类型(尤其是在mmio的时候) + * + * @param vaddr 虚拟地址 + * @return uint64_t 读取到的值 + */ +static __always_inline uint32_t __read4b(uint64_t vaddr) +{ + uint32_t retval; + asm volatile("movl 0(%%rax), %0" + : "=d"(retval) + : "a"(vaddr) + : "memory"); + return retval; +} \ No newline at end of file diff --git a/kernel/driver/interrupt/apic/apic.c b/kernel/driver/interrupt/apic/apic.c index bedf3db0..806fbd72 100644 --- a/kernel/driver/interrupt/apic/apic.c +++ b/kernel/driver/interrupt/apic/apic.c @@ -41,7 +41,7 @@ static __always_inline void __send_eoi() { io_mfence(); - *(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_EOI) = 0; + __write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_EOI, 0); io_mfence(); } } diff --git a/kernel/driver/interrupt/apic/apic_timer.h b/kernel/driver/interrupt/apic/apic_timer.h index b80a8a5e..a0c09b2d 100644 --- a/kernel/driver/interrupt/apic/apic_timer.h +++ b/kernel/driver/interrupt/apic/apic_timer.h @@ -23,7 +23,7 @@ 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; + __write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_CLKDIV, divider); } /** @@ -36,7 +36,7 @@ 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; + __write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG, init_cnt); } /** @@ -52,7 +52,7 @@ static __always_inline void apic_timer_set_LVT(uint32_t vector, uint32_t mask, u 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; + __write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER, val); } static __always_inline void apic_timer_write_LVT(uint32_t value) @@ -60,7 +60,7 @@ 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; + __write4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER, value); } /** @@ -72,7 +72,7 @@ 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); + return __read4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER); } /** @@ -83,8 +83,8 @@ 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); + else + return __read4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG); } /** diff --git a/kernel/driver/timers/HPET/HPET.c b/kernel/driver/timers/HPET/HPET.c index a292b783..27e7f12b 100644 --- a/kernel/driver/timers/HPET/HPET.c +++ b/kernel/driver/timers/HPET/HPET.c @@ -17,7 +17,7 @@ static struct acpi_HPET_description_table_t *hpet_table; static uint64_t HPET_REG_BASE = 0; static uint32_t HPET_COUNTER_CLK_PERIOD = 0; // 主计数器时间精度(单位:飞秒) -static double HPET_freq = 0; // 主计时器频率 +static uint64_t HPET_freq = 0; // 主计时器频率 static uint8_t HPET_NUM_TIM_CAP = 0; // 定时器数量 static char measure_apic_timer_flag; // 初始化apic时钟时所用到的标志变量 @@ -124,7 +124,7 @@ void HPET_measure_freq() // 使用I/O APIC 的IRQ2接收hpet定时器0的中断 apic_make_rte_entry(&entry, 34, IO_APIC_FIXED, DEST_PHYSICAL, IDLE, POLARITY_HIGH, IRR_RESET, EDGE_TRIGGER, MASKED, 0); - + // 计算HPET0间隔多少个时钟周期触发一次中断 uint64_t clks_to_intr = 0.001 * interval * HPET_freq; // kdebug("clks_to_intr=%#ld", clks_to_intr); @@ -134,11 +134,11 @@ void HPET_measure_freq() while (1) hlt(); } - *(uint64_t *)(HPET_REG_BASE + MAIN_CNT) = 0; + __write8b(HPET_REG_BASE + MAIN_CNT, 0); io_mfence(); - *(uint64_t *)(HPET_REG_BASE + TIM0_CONF) = 0x0044; // 设置定时器0为非周期,边沿触发,默认投递到IO APIC的2号引脚 + __write8b((HPET_REG_BASE + TIM0_CONF), 0x0044); // 设置定时器0为非周期,边沿触发,默认投递到IO APIC的2号引脚 io_mfence(); - *(uint64_t *)(HPET_REG_BASE + TIM0_COMP) = clks_to_intr; + __write8b(HPET_REG_BASE + TIM0_COMP, clks_to_intr); io_mfence(); @@ -146,6 +146,7 @@ void HPET_measure_freq() // 注册中断 irq_register(34, &entry, &HPET_measure_handler, 0, &HPET_intr_controller, "HPET0 measure"); + sti(); // 设置div16 apic_timer_stop(); @@ -156,13 +157,13 @@ void HPET_measure_freq() // 启动apic定时器 apic_timer_set_LVT(151, 0, APIC_LVT_Timer_One_Shot); - *(uint64_t *)(HPET_REG_BASE + GEN_CONF) = 3; // 置位旧设备中断路由兼容标志位、定时器组使能标志位,开始计时 + __write8b(HPET_REG_BASE + GEN_CONF, 3); // 置位旧设备中断路由兼容标志位、定时器组使能标志位,开始计时 + // 顺便测定tsc频率 test_tsc_start = rdtsc(); io_mfence(); while (measure_apic_timer_flag == false) ; - kdebug("wait done"); irq_unregister(34); @@ -195,11 +196,11 @@ void HPET_enable() hlt(); } // kdebug("[HPET0] conf register=%#018lx conf register[63:32]=%#06lx", (*(uint64_t *)(HPET_REG_BASE + TIM0_CONF)), ((*(uint64_t *)(HPET_REG_BASE + TIM0_CONF))>>32)&0xffffffff); - *(uint64_t *)(HPET_REG_BASE + MAIN_CNT) = 0; + __write8b(HPET_REG_BASE + MAIN_CNT, 0); io_mfence(); - *(uint64_t *)(HPET_REG_BASE + TIM0_CONF) = 0x004c; // 设置定时器0为周期定时,边沿触发,默认投递到IO APIC的2号引脚(看conf寄存器的高32bit,哪一位被置1,则可以投递到哪一个I/O apic引脚) + __write8b(HPET_REG_BASE + TIM0_CONF, 0x004c); // 设置定时器0为周期定时,边沿触发,默认投递到IO APIC的2号引脚(看conf寄存器的高32bit,哪一位被置1,则可以投递到哪一个I/O apic引脚) io_mfence(); - *(uint64_t *)(HPET_REG_BASE + TIM0_COMP) = clks_to_intr; + __write8b(HPET_REG_BASE + TIM0_COMP, clks_to_intr); io_mfence(); @@ -210,7 +211,7 @@ void HPET_enable() kinfo("HPET0 enabled."); - *(uint64_t *)(HPET_REG_BASE + GEN_CONF) = 3; // 置位旧设备中断路由兼容标志位、定时器组使能标志位 + __write8b(HPET_REG_BASE + GEN_CONF, 3); // 置位旧设备中断路由兼容标志位、定时器组使能标志位 io_mfence(); // 注册中断 irq_register(34, &entry, &HPET_handler, 0, &HPET_intr_controller, "HPET0"); @@ -231,11 +232,11 @@ int HPET_init() if (RCBA_vaddr != 0) { kerror("NO HPET found on this computer!"); - uint32_t *hptc = (uint32_t *)(RCBA_vaddr + 0x3404UL); + uint64_t hptc_vaddr = (RCBA_vaddr + 0x3404UL); // enable HPET io_mfence(); // 读取HPET配置寄存器地址 - switch ((*hptc) & 0x3) + switch (__read4b(hptc_vaddr) & 0x3) { case 0: HPET_REG_BASE = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + 0xfed00000; @@ -253,7 +254,7 @@ int HPET_init() break; } // enable HPET - *hptc = 0x80; + __write4b(hptc_vaddr, 0x80); io_mfence(); } else @@ -270,19 +271,20 @@ int HPET_init() // 由于这段内存与io/apic的映射在同一物理页内,因此不需要重复映射 HPET_REG_BASE = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + hpet_table->address; + kdebug("hpet_table->address=%#018lx", hpet_table->address); } + kdebug("HPET_REG_BASE=%#018lx", HPET_REG_BASE); // 读取计时精度并计算频率 uint64_t tmp; - tmp = *(uint64_t *)(HPET_REG_BASE + GCAP_ID); + tmp = __read8b(HPET_REG_BASE + GCAP_ID); HPET_COUNTER_CLK_PERIOD = (tmp >> 32) & 0xffffffff; - HPET_freq = 1.0 * 1e15 / HPET_COUNTER_CLK_PERIOD; + HPET_freq = 1e15 / HPET_COUNTER_CLK_PERIOD; HPET_NUM_TIM_CAP = (tmp >> 8) & 0x1f; // 读取计时器数量 + + kdebug("HPET_COUNTER_CLK_PERIOD=%#018lx", HPET_COUNTER_CLK_PERIOD); kinfo("Total HPET timers: %d", HPET_NUM_TIM_CAP); kinfo("HPET driver Initialized."); - // kinfo("HPET CLK_PERIOD=%#03lx Frequency=%f", HPET_COUNTER_CLK_PERIOD, (double)HPET_freq); - // kdebug("HPET_freq=%ld", (long)HPET_freq); - // kdebug("HPET_freq=%lf", HPET_freq); } #pragma GCC pop_options