#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;
#include <system.h>
#include <processor.h>
#include <linkage.h>
+#include <msr.h>
+#include <cpuid.h>
extern pde_t* ap_pre_pgd;
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需要废弃,因为它已经在内核地址空间之外了
*((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;");
}
}
// printk("AP no irq handler\n");
uint8_t* p = (uint8_t*)0xC00B8000;
*p = *p == ' ' ? 'K' : ' ';
+ system.lapic->write(LAPIC_EOI, 0);
}
#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) {
}
// 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) {