From: acevest Date: Mon, 5 Jan 2026 12:38:56 +0000 (+0800) Subject: 让AP正常触发本地时钟中断 X-Git-Url: http://repos.zhaoyanbai.com/Mou_128.png?a=commitdiff_plain;h=dbe0e46283586794db4929b15619e9f2cf2df2f5;p=kernel.git 让AP正常触发本地时钟中断 --- diff --git a/include/apic.h b/include/apic.h index 8607500..0323ccf 100644 --- a/include/apic.h +++ b/include/apic.h @@ -71,7 +71,16 @@ #define LAPIC_LVT_ERROR 0x370 #define LAPIC_TIMER_INITIAL 0x380 #define LAPIC_TIMER_COUNTER 0x390 -#define LAPIC_TIMER_DIVIDE 0x3E0 +#define LAPIC_TIMER_DIVIDER 0x3E0 + +// 屏蔽本地中断位 +#define LAPIC_LVT_MASKED (1 << 16) + +// 定时器模式 +#define LAPIC_TIMER_MODE_ONESHOT (0 << 17) +#define LAPIC_TIMER_MODE_PERIODIC (1 << 17) +#define LAPIC_TIMER_MODE_TSC_DEADLINE (2 << 17) +#define LAPIC_TIMER_MODE_RESERVED (3 << 17) typedef struct lapic { const char* name; diff --git a/kernel/ap.c b/kernel/ap.c index be45a56..0312377 100644 --- a/kernel/ap.c +++ b/kernel/ap.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include extern pde_t* ap_pre_pgd; @@ -53,7 +55,7 @@ static inline void set_ap_idt_gate(u32 vec, u32 handler, u8 type, u8 DPL) { void ap_kernel_entry() { // 虽然ap_pre_pgd只做了一下跳板页目录看起来很可惜 // 不过可以把它拿来个AP的栈用 - asm("mov %0, %%esp" : : "r"(pa2va(&ap_pre_pgd) + PAGE_SIZE)); + asm("mov %0, %%esp" : : "r"(pa2va(&ap_pre_pgd) + PAGE_SIZE - 128)); // 进入内核空间后要加载原来已经在内核空间的ap_gdt // 之前加载的被复制到1MB以下的ap_gdt需要废弃,因为它已经在内核地址空间之外了 @@ -97,11 +99,60 @@ void ap_kernel_entry() { *((unsigned long*)(ap_idtr + 2)) = (unsigned long)ap_idt; asm volatile("lidt ap_idtr"); - asm("int $0x28"); + cpuid_regs_t r; + r = cpuid(1); + if (r.edx & (1 << 9)) { + printk("local apic supported\n"); + if (r.ecx & (1 << 21)) { + printk("x2apic supported\n"); + } else { + panic("x2apic not supported\n"); + } + } else { + panic("local apic not supported\n"); + } + + // 开房时钟中断 + lapic_t* lapic = system.lapic; + uint32_t clkvec = 0x28; + + uint32_t apic_base = 0; + apic_base = read_msr32(MSR_IA32_APIC_BASE); + apic_base |= (1 << 11); + if (lapic->x2apic) { + apic_base |= (1 << 10); + write_msr(MSR_IA32_APIC_BASE, apic_base); + } + + uint32_t lapic_svr = lapic->read(LAPIC_SVR); + lapic_svr |= (1 << 8); // 启用LAPIC + lapic_svr &= ~(1 << 12); // 禁用EOI广播 + lapic->write(LAPIC_SVR, lapic_svr); + + // 先显示地屏蔽时钟中断 + lapic->write(LAPIC_LVT_TIMER, LAPIC_LVT_MASKED); + + // 设置分频频率 + // 000: divide by 2 + // 001: divide by 4 + // 010: divide by 8 + // 011: divide by 16 + // 100: divide by 32 + // 101: divide by 64 + // 110: divide by 128 + // 111: divide by 1 + lapic->write(LAPIC_TIMER_DIVIDER, 0x03); + + // 设置时钟中断周期 + lapic->write(LAPIC_TIMER_INITIAL, 10000000); + + // + lapic->write(LAPIC_LVT_TIMER, LAPIC_TIMER_MODE_PERIODIC | clkvec); + + asm("sti;"); while (1) { - asm("nop;"); - asm("int $0x28"); + asm("hlt;"); } } @@ -110,4 +161,5 @@ void do_ap_no_irq_handler() { // printk("AP no irq handler\n"); uint8_t* p = (uint8_t*)0xC00B8000; *p = *p == ' ' ? 'K' : ' '; + system.lapic->write(LAPIC_EOI, 0); } diff --git a/kernel/innerint.c b/kernel/innerint.c index e09df56..dd49d21 100644 --- a/kernel/innerint.c +++ b/kernel/innerint.c @@ -19,11 +19,11 @@ #include #include -#define DIE_MSG() \ - do { \ - printk("Unsupport Now...[%s]\n", __FUNCTION__); \ - printk("EFLAGS:%08x CS:%02x EIP:%08x ERRCODE:%x", regs.eflags, regs.cs, regs.eip, regs.errcode); \ - asm("cli;hlt;"); \ +#define DIE_MSG() \ + do { \ + printk("Unsupport Now...[%s]\n", __FUNCTION__); \ + printk("EFLAGS:%08x CS:%02x EIP:%08x ERRCODE:%x\n", regs.eflags, regs.cs, regs.eip, regs.errcode); \ + asm("cli;hlt;"); \ } while (0); void doDivideError(pt_regs_t regs) { @@ -111,11 +111,11 @@ void doCoprocError(pt_regs_t regs) { } // TODO 把printk换掉 -#define AP_DIE_MSG() \ - do { \ - printk("AP Unsupport Now...[%s]\n", __FUNCTION__); \ - printk("EFLAGS:%08x CS:%02x EIP:%08x ERRCODE:%x", regs.eflags, regs.cs, regs.eip, regs.errcode); \ - asm("cli;hlt;"); \ +#define AP_DIE_MSG() \ + do { \ + printk("AP Unsupport Now...[%s]\n", __FUNCTION__); \ + printk("EFLAGS:%08x CS:%02x EIP:%08x ERRCODE:%x\n", regs.eflags, regs.cs, regs.eip, regs.errcode); \ + asm("cli;hlt;"); \ } while (0); void doAPDivideError(pt_regs_t regs) {