🔧 改用local apic定时器进行进程时间片更新

This commit is contained in:
fslongjin
2022-07-11 21:47:28 +08:00
parent 594aeadf65
commit defb9e769c
9 changed files with 220 additions and 51 deletions

View File

@ -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)

View File

@ -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 // 边沿触发

View File

@ -1,3 +1,84 @@
#include "apic_timer.h"
#include <exception/irq.h>
#include <process/process.h>
#include <common/kprint.h>
#include <sched/sched.h>
uint64_t apic_timer_ticksIn1ms = 0;
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);
}

View File

@ -3,7 +3,12 @@
#include <common/unistd.h>
#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))
#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();

View File

@ -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);
}
/**

View File

@ -1,4 +1,5 @@
#include "irq.h"
#include <common/errno.h>
// 对进行
#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;

View File

@ -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 中断注册函数
*

View File

@ -32,6 +32,8 @@
#include <driver/uart/uart.h>
#include <driver/video/video.h>
#include <driver/interrupt/apic/apic_timer.h>
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);
}

View File

@ -123,8 +123,7 @@ void sched_cfs()
*/
void sched_update_jiffies()
{
// if (current_pcb->cpu_id == 0)
// return;
switch (current_pcb->priority)
{
case 0: