]> Zhao Yanbai Git Server - kernel.git/commitdiff
让AP正常触发本地时钟中断
authoracevest <zhaoyanbai@126.com>
Mon, 5 Jan 2026 12:38:56 +0000 (20:38 +0800)
committeracevest <zhaoyanbai@126.com>
Mon, 5 Jan 2026 12:38:56 +0000 (20:38 +0800)
include/apic.h
kernel/ap.c
kernel/innerint.c

index 8607500c25a1c19fa77ff42af742f325a553f68e..0323ccfaebaa1d58d3c2a3cf92a80e2ea681b612 100644 (file)
 #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;
index be45a56f5cfa67c0adc13181f08813444ba382d6..0312377db81f48addf40cd42f46c629fb14c9d3e 100644 (file)
@@ -12,6 +12,8 @@
 #include <system.h>
 #include <processor.h>
 #include <linkage.h>
+#include <msr.h>
+#include <cpuid.h>
 
 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);
 }
index e09df5689a1e52081722d8a21604dd2564e52235..dd49d2118479e18582b1a006cb859505c95a741e 100644 (file)
 #include <sched.h>
 #include <system.h>
 
-#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) {