diff --git a/kernel/driver/interrupt/apic/apic.c b/kernel/driver/interrupt/apic/apic.c index 3d50e0c9..ae8f987e 100644 --- a/kernel/driver/interrupt/apic/apic.c +++ b/kernel/driver/interrupt/apic/apic.c @@ -20,6 +20,17 @@ uint local_apic_max_LVT_entries; static struct acpi_Multiple_APIC_Description_Table_t *madt; static struct acpi_IO_APIC_Structure_t *io_apic_ICS; + +#define send_EOI() \ + do \ + { \ + __asm__ __volatile__("movq $0x00, %%rdx \n\t" \ + "movq $0x00, %%rax \n\t" \ + "movq $0x80b, %%rcx \n\t" \ + "wrmsr \n\t" :: \ + : "memory"); \ + } while (0) + /** * @brief 初始化io_apic * @@ -235,7 +246,7 @@ void apic_local_apic_init() // 检测是否成功启用xAPIC和x2APIC if (eax & 0xc00) kinfo("xAPIC & x2APIC enabled!"); - + /* io_mfence(); uint *svr = (uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_SVR); @@ -378,6 +389,10 @@ void apic_init() for (int i = 32; i <= 55; ++i) set_intr_gate(i, 0, interrupt_table[i - 32]); + // 设置local apic中断门 + for (int i = 150; i < 160; ++i) + set_intr_gate(i, 0, local_apic_interrupt_table[i - 150]); + /* // 初始化主芯片 io_out8(0x20, 0x11); // 初始化主芯片的icw1 @@ -461,7 +476,7 @@ void do_IRQ(struct pt_regs *rsp, ul number) // ps: 当前已经将系统调用直接使用系统调用门实现,不走这里。。 do_syscall_int(rsp, 0); } - else if (number > 0x80) + else if (number >= 200) { // printk_color(RED, BLACK, "SMP IPI [ %d ]\n", number); @@ -473,6 +488,25 @@ void do_IRQ(struct pt_regs *rsp, ul number) irq->handler(number, irq->parameter, rsp); } } + else if (number >= 150 && number < 160) + { + irq_desc_t *irq = &local_apic_interrupt_desc[number - 150]; + + // 执行中断上半部处理程序 + if (irq != NULL && irq->handler != NULL) + irq->handler(number, irq->parameter, rsp); + else + kwarn("Intr vector [%d] does not have a handler!"); + // 向中断控制器发送应答消息 + if (irq->controller != NULL && irq->controller->ack != NULL) + irq->controller->ack(number); + else + { + + // 向EOI寄存器写入0x00表示结束中断 + send_EOI(); + } + } else { @@ -482,7 +516,7 @@ void do_IRQ(struct pt_regs *rsp, ul number) // kdebug("before softirq"); // 进入软中断处理程序 do_softirq(); - + // kdebug("after softirq"); // 检测当前进程是否持有自旋锁,若持有自旋锁,则不进行抢占式的进程调度 if (current_pcb->preempt_count > 0) diff --git a/kernel/driver/interrupt/apic/apic.h b/kernel/driver/interrupt/apic/apic.h index 1e20b712..35b1199f 100644 --- a/kernel/driver/interrupt/apic/apic.h +++ b/kernel/driver/interrupt/apic/apic.h @@ -202,7 +202,7 @@ struct apic_IO_APIC_RTE_entry // 屏蔽 #define UNMASKED 0 #define MASKED 1 -#define APIC_LVT_INT_MASKED 0x10000 +#define APIC_LVT_INT_MASKED 0x10000UL // 触发模式 #define EDGE_TRIGGER 0 // 边沿触发 diff --git a/kernel/driver/interrupt/apic/apic_timer.c b/kernel/driver/interrupt/apic/apic_timer.c index 04e18ee9..9842e099 100644 --- a/kernel/driver/interrupt/apic/apic_timer.c +++ b/kernel/driver/interrupt/apic/apic_timer.c @@ -1,3 +1,84 @@ #include "apic_timer.h" +#include +#include +#include +#include -uint64_t apic_timer_ticksIn1ms = 0; \ No newline at end of file +uint64_t apic_timer_ticks_result = 0; + +void apic_timer_enable(uint64_t irq_num) +{ + // 启动apic定时器 + uint64_t val = apic_timer_get_LVT(); + val &= (~APIC_LVT_INT_MASKED); + apic_timer_write_LVT(val); +} + +void apic_timer_disable(uint64_t irq_num) +{ + apic_timer_stop(); +} + +/** + * @brief 安装local apic定时器中断 + * + * @param irq_num 中断向量号 + * @param arg 初始计数值 + * @return uint64_t + */ +uint64_t apic_timer_install(ul irq_num, void *arg) +{ + // 设置div16 + apic_timer_stop(); + apic_timer_set_div(APIC_TIMER_DIVISOR); + + // 设置初始计数 + apic_timer_set_init_cnt(*(uint64_t *)arg); + // 填写LVT + apic_timer_set_LVT(APIC_TIMER_IRQ_NUM, 1, APIC_LVT_Timer_Periodic); +} + +void apic_timer_uninstall(ul irq_num) +{ + apic_timer_write_LVT(APIC_LVT_INT_MASKED); +} + +hardware_intr_controller apic_timer_intr_controller = + { + .enable = apic_timer_enable, + .disable = apic_timer_disable, + .install = apic_timer_install, + .uninstall = apic_timer_uninstall, + .ack = apic_local_apic_edge_ack, +}; + +/** + * @brief local apic定时器的中断处理函数 + * + * @param number 中断向量号 + * @param param 参数 + * @param regs 寄存器值 + */ +void apic_timer_handler(uint64_t number, uint64_t param, struct pt_regs *regs) +{ + + sched_update_jiffies(); +} + +/** + * @brief 初始化local APIC定时器 + * + */ +void apic_timer_init() +{ + if (apic_timer_ticks_result == 0) + { + kBUG("APIC timer ticks in 5ms is equal to ZERO!"); + while (1) + hlt(); + } + kinfo("Initializing apic timer for cpu %d", proc_current_cpu_id); + + irq_register(APIC_TIMER_IRQ_NUM, &apic_timer_ticks_result, &apic_timer_handler, 0, &apic_timer_intr_controller, "apic timer"); + kinfo("Successfully initialized apic timer for cpu %d", proc_current_cpu_id); +} \ No newline at end of file diff --git a/kernel/driver/interrupt/apic/apic_timer.h b/kernel/driver/interrupt/apic/apic_timer.h index 2c064020..1472b920 100644 --- a/kernel/driver/interrupt/apic/apic_timer.h +++ b/kernel/driver/interrupt/apic/apic_timer.h @@ -3,7 +3,12 @@ #include #include "apic.h" -extern uint64_t apic_timer_ticksIn1ms; +extern uint64_t apic_timer_ticks_result; +// 5ms产生一次中断 +#define APIC_TIMER_INTERVAL 5 +#define APIC_TIMER_DIVISOR 3 + +#define APIC_TIMER_IRQ_NUM 151 /** * @brief 设置apic定时器的分频计数 @@ -27,34 +32,50 @@ extern uint64_t apic_timer_ticksIn1ms; wrmsr(0x838, init_cnt); \ } while (0) -/** - * @brief 停止apic定时器 - * - */ -#define apic_timer_stop() \ - do \ - { \ - wrmsr(0x832, APIC_LVT_INT_MASKED); \ - } while (0) - /** * @brief 设置apic定时器的lvt,并启动定时器 * + * @param vector 中断向量号 + * @param mask 是否屏蔽(1:屏蔽, 0:不屏蔽) + * @param mode 计时模式 */ -#define apic_timer_set_LVT(vector, mode) \ - do \ - { \ - wrmsr(0x832, (mode << 17) | vector); \ - io_mfence(); \ +#define apic_timer_set_LVT(vector, mask, mode) \ + do \ + { \ + wrmsr(0x832, (mode << 17) | vector | (mask ? (APIC_LVT_INT_MASKED) : 0)); \ + } while (0) + +#define apic_timer_write_LVT(value) \ + do \ + { \ + wrmsr(0x832, value); \ } while (0) /** * @brief 获取apic定时器的LVT的值 - * + * */ #define apic_timer_get_LVT() (rdmsr(0x832)) /** * @brief 获取apic定时器当前计数值 * */ -#define apic_timer_get_current() (rdmsr(0x839)) \ No newline at end of file +#define apic_timer_get_current() (rdmsr(0x839)) + +/** + * @brief 停止apic定时器 + * + */ +#define apic_timer_stop() \ + do \ + { \ + uint64_t val = apic_timer_get_LVT(); \ + val |= APIC_LVT_INT_MASKED; \ + apic_timer_write_LVT(val); \ + } while (0) + +/** + * @brief 初始化local APIC定时器 + * + */ +void apic_timer_init(); \ No newline at end of file diff --git a/kernel/driver/timers/HPET/HPET.c b/kernel/driver/timers/HPET/HPET.c index 35a0a361..6641946d 100644 --- a/kernel/driver/timers/HPET/HPET.c +++ b/kernel/driver/timers/HPET/HPET.c @@ -70,16 +70,11 @@ void HPET_handler(uint64_t number, uint64_t param, struct pt_regs *regs) if (container_of(list_next(&timer_func_head.list), struct timer_func_list_t, list)->expire_jiffies <= timer_jiffies) raise_softirq((1 << TIMER_SIRQ)); - // if (current_pcb->pid == 2) - // kwarn("timer_jiffies = %ld video_refresh_expire_jiffies=%ld", timer_jiffies, video_refresh_expire_jiffies); // 当时间到了,或进程发生切换时,刷新帧缓冲区 if (timer_jiffies >= video_refresh_expire_jiffies || (video_last_refresh_pid != current_pcb->pid)) { raise_softirq(VIDEO_REFRESH_SIRQ); } - - sched_update_jiffies(); - break; default: @@ -92,12 +87,12 @@ void HPET_handler(uint64_t number, uint64_t param, struct pt_regs *regs) * @brief 测量apic定时器频率的中断回调函数 * */ -void HPET_measure_apic_timer_handler() +void HPET_measure_apic_timer_handler(uint64_t number, uint64_t param, struct pt_regs *regs) { // 停止apic定时器 // 写入每1ms的ticks apic_timer_stop(); - apic_timer_ticksIn1ms = 0xFFFFFFFF - apic_timer_get_current(); + apic_timer_ticks_result = 0xFFFFFFFF - apic_timer_get_current(); measure_apic_timer_flag = true; } @@ -108,7 +103,7 @@ void HPET_measure_apic_timer_handler() void HPET_measure_apic_timer_freq() { kinfo("Measuring local APIC timer's frequency..."); - const uint64_t interval = 1; // 测量1毫秒内的计数 + const uint64_t interval = APIC_TIMER_INTERVAL; // 测量给定时间内的计数 struct apic_IO_APIC_RTE_entry entry; // 使用I/O APIC 的IRQ2接收hpet定时器0的中断 @@ -137,15 +132,14 @@ void HPET_measure_apic_timer_freq() irq_register(34, &entry, &HPET_measure_apic_timer_handler, 0, &HPET_intr_controller, "HPET0 measure"); // 设置div16 - apic_timer_set_div(0x3); apic_timer_stop(); - // 设置初始计数 + apic_timer_set_div(APIC_TIMER_DIVISOR); - + // 设置初始计数 apic_timer_set_init_cnt(0xFFFFFFFF); // 启动apic定时器 - apic_timer_set_LVT(151, APIC_LVT_Timer_One_Shot); + apic_timer_set_LVT(151, 0, APIC_LVT_Timer_One_Shot); *(uint64_t *)(HPET_REG_BASE + GEN_CONF) = 3; // 置位旧设备中断路由兼容标志位、定时器组使能标志位,开始计时 io_mfence(); @@ -156,7 +150,7 @@ void HPET_measure_apic_timer_freq() *(uint64_t *)(HPET_REG_BASE + GEN_CONF) = 0; // 停用HPET定时器 io_mfence(); - kinfo("Local APIC timer's freq: %d ticks/ms.", apic_timer_ticksIn1ms); + kinfo("Local APIC timer's freq: %d ticks/ms.", apic_timer_ticks_result); } /** diff --git a/kernel/exception/irq.c b/kernel/exception/irq.c index 468145c3..9eef557d 100644 --- a/kernel/exception/irq.c +++ b/kernel/exception/irq.c @@ -1,4 +1,5 @@ #include "irq.h" +#include // 对进行 #if _INTR_8259A_ @@ -148,6 +149,31 @@ void (*SMP_interrupt_table[SMP_IRQ_NUM])(void) = IRQ0xd1interrupt, }; +// 初始化local apic中断服务程序数组 +Build_IRQ(0x96); +Build_IRQ(0x97); +Build_IRQ(0x98); +Build_IRQ(0x99); +Build_IRQ(0x9a); +Build_IRQ(0x9b); +Build_IRQ(0x9c); +Build_IRQ(0x9d); +Build_IRQ(0x9e); +Build_IRQ(0x9f); +void (*local_apic_interrupt_table[LOCAL_APIC_IRQ_NUM])(void) = + { + IRQ0x96interrupt, + IRQ0x97interrupt, + IRQ0x98interrupt, + IRQ0x99interrupt, + IRQ0x9ainterrupt, + IRQ0x9binterrupt, + IRQ0x9cinterrupt, + IRQ0x9dinterrupt, + IRQ0x9einterrupt, + IRQ0x9finterrupt, +}; + /** * @brief 中断注册函数 * @@ -162,14 +188,24 @@ void (*SMP_interrupt_table[SMP_IRQ_NUM])(void) = int irq_register(ul irq_num, void *arg, void (*handler)(ul irq_num, ul parameter, struct pt_regs *regs), ul paramater, hardware_intr_controller *controller, char *irq_name) { // 由于为I/O APIC分配的中断向量号是从32开始的,因此要减去32才是对应的interrupt_desc的元素 - irq_desc_t *p = &interrupt_desc[irq_num - 32]; - + irq_desc_t *p = NULL; + if (irq_num >= 32 && irq_num < 0x80) + p = &interrupt_desc[irq_num - 32]; + else if (irq_num >= 150 && irq_num < 160) + p = &local_apic_interrupt_desc[irq_num - 150]; + else + { + kerror("irq_register(): invalid irq num: %ld.", irq_num); + return -EINVAL; + } p->controller = controller; - - int namelen = sizeof(strlen(irq_name)+1); - p->irq_name = (char *)kmalloc(namelen,0); - memset(p->irq_name, 0, namelen); - strncpy(p->irq_name, irq_name, namelen); + if (p->irq_name == NULL) + { + int namelen = sizeof(strlen(irq_name) + 1); + p->irq_name = (char *)kmalloc(namelen, 0); + memset(p->irq_name, 0, namelen); + strncpy(p->irq_name, irq_name, namelen); + } p->parameter = paramater; p->flags = 0; diff --git a/kernel/exception/irq.h b/kernel/exception/irq.h index 30fc9ffc..5b9769ce 100644 --- a/kernel/exception/irq.h +++ b/kernel/exception/irq.h @@ -16,6 +16,7 @@ #include "../process/ptrace.h" #define SMP_IRQ_NUM 10 +#define LOCAL_APIC_IRQ_NUM 10 extern void (*interrupt_table[24])(void); extern void do_IRQ(struct pt_regs *regs, ul number); @@ -23,6 +24,7 @@ extern void do_IRQ(struct pt_regs *regs, ul number); extern void (*SMP_interrupt_table[SMP_IRQ_NUM])(void); extern void (*syscall_intr_table[1])(void); +extern void (*local_apic_interrupt_table[LOCAL_APIC_IRQ_NUM])(void); /* ========= 中断向量分配表 ========== @@ -128,9 +130,10 @@ typedef struct #define IRQ_NUM 24 // 这两个表一定要放在这里,否则在HPET初始化后收到中断,会产生page fault irq_desc_t interrupt_desc[IRQ_NUM] = {0}; - +irq_desc_t local_apic_interrupt_desc[20] = {0}; irq_desc_t SMP_IPI_desc[SMP_IRQ_NUM] = {0}; + /** * @brief 中断注册函数 * diff --git a/kernel/main.c b/kernel/main.c index 787a64bd..e5e776c5 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -32,6 +32,8 @@ #include #include +#include + unsigned int *FR_address = (unsigned int *)0xb8000; //帧缓存区的地址 ul bsp_idt_size, bsp_gdt_size; @@ -39,7 +41,6 @@ struct memory_desc memory_management_struct = {{0}, 0}; // struct Global_Memory_Descriptor memory_management_struct = {{0}, 0}; void test_slab(); - struct gdtr gdtp; struct idtr idtp; void reload_gdt() @@ -144,14 +145,15 @@ void system_initialize() HPET_measure_apic_timer_freq(); // current_pcb->preempt_count = 0; // kdebug("cpu_get_core_crysral_freq()=%ld", cpu_get_core_crysral_freq()); - // while(1); + process_init(); // 对显示模块进行高级初始化,启用double buffer video_init(true); // fat32_init(); - // 系统初始化到此结束,剩下的初始化功能应当放在初始内核线程中执行 HPET_enable(); + // 系统初始化到此结束,剩下的初始化功能应当放在初始内核线程中执行 + apic_timer_init(); } //操作系统内核从这里开始执行 @@ -178,7 +180,6 @@ void Start_Kernel(void) system_initialize(); - while (1) hlt(); } @@ -186,5 +187,5 @@ void Start_Kernel(void) void ignore_int() { kwarn("Unknown interrupt or fault at RIP.\n"); - return; + while(1); } \ No newline at end of file diff --git a/kernel/sched/sched.c b/kernel/sched/sched.c index 8ca1ce80..565c378f 100644 --- a/kernel/sched/sched.c +++ b/kernel/sched/sched.c @@ -123,8 +123,7 @@ void sched_cfs() */ void sched_update_jiffies() { - // if (current_pcb->cpu_id == 0) - // return; + switch (current_pcb->priority) { case 0: