bugfix: 在物理机上,由于不支持的内存访问类型,导致无法初始化HPET

This commit is contained in:
fslongjin 2022-09-01 21:08:27 +08:00
parent dffa51b1ef
commit 33a1e2baad
4 changed files with 93 additions and 29 deletions

View File

@ -491,3 +491,65 @@ static inline uint64_t copy_to_user(void *dst, void *src, uint64_t size)
* @param times * @param times
*/ */
void __experimental_beep(uint64_t times); 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;
}

View File

@ -41,7 +41,7 @@ static __always_inline void __send_eoi()
{ {
io_mfence(); 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(); io_mfence();
} }
} }

View File

@ -23,7 +23,7 @@ static __always_inline void apic_timer_set_div(uint64_t divider)
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED) if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
wrmsr(0x83e, divider); wrmsr(0x83e, divider);
else 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) if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
wrmsr(0x838, init_cnt); wrmsr(0x838, init_cnt);
else 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) if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
wrmsr(0x832, val); wrmsr(0x832, val);
else 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) 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) if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
wrmsr(0x832, value); wrmsr(0x832, value);
else 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) if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
return rdmsr(0x832); return rdmsr(0x832);
else 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);
} }
/** /**
@ -84,7 +84,7 @@ static __always_inline uint32_t apic_timer_get_current()
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED) if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED)
return (uint32_t)rdmsr(0x839); return (uint32_t)rdmsr(0x839);
else else
return *(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG); return __read4b(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG);
} }
/** /**

View File

@ -17,7 +17,7 @@
static struct acpi_HPET_description_table_t *hpet_table; static struct acpi_HPET_description_table_t *hpet_table;
static uint64_t HPET_REG_BASE = 0; static uint64_t HPET_REG_BASE = 0;
static uint32_t HPET_COUNTER_CLK_PERIOD = 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 uint8_t HPET_NUM_TIM_CAP = 0; // 定时器数量
static char measure_apic_timer_flag; // 初始化apic时钟时所用到的标志变量 static char measure_apic_timer_flag; // 初始化apic时钟时所用到的标志变量
@ -134,11 +134,11 @@ void HPET_measure_freq()
while (1) while (1)
hlt(); hlt();
} }
*(uint64_t *)(HPET_REG_BASE + MAIN_CNT) = 0; __write8b(HPET_REG_BASE + MAIN_CNT, 0);
io_mfence(); 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(); io_mfence();
*(uint64_t *)(HPET_REG_BASE + TIM0_COMP) = clks_to_intr; __write8b(HPET_REG_BASE + TIM0_COMP, clks_to_intr);
io_mfence(); io_mfence();
@ -146,6 +146,7 @@ void HPET_measure_freq()
// 注册中断 // 注册中断
irq_register(34, &entry, &HPET_measure_handler, 0, &HPET_intr_controller, "HPET0 measure"); irq_register(34, &entry, &HPET_measure_handler, 0, &HPET_intr_controller, "HPET0 measure");
sti();
// 设置div16 // 设置div16
apic_timer_stop(); apic_timer_stop();
@ -156,13 +157,13 @@ void HPET_measure_freq()
// 启动apic定时器 // 启动apic定时器
apic_timer_set_LVT(151, 0, APIC_LVT_Timer_One_Shot); 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频率 // 顺便测定tsc频率
test_tsc_start = rdtsc(); test_tsc_start = rdtsc();
io_mfence(); io_mfence();
while (measure_apic_timer_flag == false) while (measure_apic_timer_flag == false)
; ;
kdebug("wait done");
irq_unregister(34); irq_unregister(34);
@ -195,11 +196,11 @@ void HPET_enable()
hlt(); 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); // 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(); 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(); io_mfence();
*(uint64_t *)(HPET_REG_BASE + TIM0_COMP) = clks_to_intr; __write8b(HPET_REG_BASE + TIM0_COMP, clks_to_intr);
io_mfence(); io_mfence();
@ -210,7 +211,7 @@ void HPET_enable()
kinfo("HPET0 enabled."); kinfo("HPET0 enabled.");
*(uint64_t *)(HPET_REG_BASE + GEN_CONF) = 3; // 置位旧设备中断路由兼容标志位、定时器组使能标志位 __write8b(HPET_REG_BASE + GEN_CONF, 3); // 置位旧设备中断路由兼容标志位、定时器组使能标志位
io_mfence(); io_mfence();
// 注册中断 // 注册中断
irq_register(34, &entry, &HPET_handler, 0, &HPET_intr_controller, "HPET0"); irq_register(34, &entry, &HPET_handler, 0, &HPET_intr_controller, "HPET0");
@ -231,11 +232,11 @@ int HPET_init()
if (RCBA_vaddr != 0) if (RCBA_vaddr != 0)
{ {
kerror("NO HPET found on this computer!"); kerror("NO HPET found on this computer!");
uint32_t *hptc = (uint32_t *)(RCBA_vaddr + 0x3404UL); uint64_t hptc_vaddr = (RCBA_vaddr + 0x3404UL);
// enable HPET // enable HPET
io_mfence(); io_mfence();
// 读取HPET配置寄存器地址 // 读取HPET配置寄存器地址
switch ((*hptc) & 0x3) switch (__read4b(hptc_vaddr) & 0x3)
{ {
case 0: case 0:
HPET_REG_BASE = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + 0xfed00000; HPET_REG_BASE = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + 0xfed00000;
@ -253,7 +254,7 @@ int HPET_init()
break; break;
} }
// enable HPET // enable HPET
*hptc = 0x80; __write4b(hptc_vaddr, 0x80);
io_mfence(); io_mfence();
} }
else else
@ -270,19 +271,20 @@ int HPET_init()
// 由于这段内存与io/apic的映射在同一物理页内因此不需要重复映射 // 由于这段内存与io/apic的映射在同一物理页内因此不需要重复映射
HPET_REG_BASE = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + hpet_table->address; 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; 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_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; // 读取计时器数量 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("Total HPET timers: %d", HPET_NUM_TIM_CAP);
kinfo("HPET driver Initialized."); 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 #pragma GCC pop_options