LoGin f2022a8a1c
使用rust编写中断/异常的入口 (#509)
* 使用rust编写中断/异常的入口
2024-02-07 13:29:47 +08:00

205 lines
5.7 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "apic.h"
#include "apic_timer.h"
#include <common/cpu.h>
#include <common/glib.h>
#include <common/kprint.h>
#include <common/printk.h>
#include <driver/acpi/acpi.h>
#include <exception/softirq.h>
#include <process/process.h>
#include <sched/sched.h>
#pragma GCC push_options
#pragma GCC optimize("O0")
// 导出定义在irq.c中的中段门表
extern void (*interrupt_table[26])(void);
extern uint32_t rs_current_pcb_preempt_count();
extern uint32_t rs_current_pcb_pid();
extern uint32_t rs_current_pcb_flags();
extern void rs_apic_init_bsp();
extern void rs_apic_local_apic_edge_ack(uint8_t irq_num);
extern int rs_ioapic_install(uint8_t vector, uint8_t dest, bool level_triggered, bool active_high, bool dest_logical);
extern void rs_ioapic_uninstall(uint8_t irq_num);
extern void rs_ioapic_enable(uint8_t irq_num);
extern void rs_ioapic_disable(uint8_t irq_num);
/**
* @brief 中断服务程序
*
* @param rsp 中断栈指针
* @param number 中断向量号
*/
void do_IRQ(struct pt_regs *rsp, ul number)
{
if ((rsp->cs & 0x3) == 3)
{
asm volatile("swapgs" ::: "memory");
}
if (number < 0x80 && number >= 32) // 以0x80为界限低于0x80的是外部中断控制器高于0x80的是Local APIC
{
// ==========外部中断控制器========
irq_desc_t *irq = &interrupt_desc[number - 32];
// 执行中断上半部处理程序
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
// rs_apic_local_apic_edge_ack(number);
rs_apic_local_apic_edge_ack(number);
}
else if (number >= 200)
{
rs_apic_local_apic_edge_ack(number);
{
irq_desc_t *irq = &SMP_IPI_desc[number - 200];
if (irq->handler != NULL)
irq->handler(number, irq->parameter, rsp);
}
}
else if (number >= 150 && number < 200)
{
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
// rs_apic_local_apic_edge_ack(number);
rs_apic_local_apic_edge_ack(number);
}
else
{
kwarn("do IRQ receive: %d", number);
// 忽略未知中断
return;
}
// kdebug("before softirq");
// 进入软中断处理程序
rs_do_softirq();
// kdebug("after softirq");
// 检测当前进程是否持有自旋锁,若持有自旋锁,则不进行抢占式的进程调度
if (rs_current_pcb_preempt_count() > 0)
{
return;
}
else if ((int32_t)rs_current_pcb_preempt_count() < 0)
kBUG("current_pcb->preempt_count<0! pid=%d", rs_current_pcb_pid()); // should not be here
// 检测当前进程是否可被调度
if ((rs_current_pcb_flags() & PF_NEED_SCHED) && number == APIC_TIMER_IRQ_NUM)
{
io_mfence();
sched();
}
}
// =========== 中断控制操作接口 ============
void apic_ioapic_enable(ul irq_num)
{
rs_ioapic_enable(irq_num);
}
void apic_ioapic_disable(ul irq_num)
{
rs_ioapic_disable(irq_num);
}
ul apic_ioapic_install(ul irq_num, void *arg)
{
struct apic_IO_APIC_RTE_entry *entry = (struct apic_IO_APIC_RTE_entry *)arg;
uint8_t dest = 0;
if (entry->dest_mode)
{
dest = entry->destination.logical.logical_dest;
}
else
{
dest = entry->destination.physical.phy_dest;
}
return rs_ioapic_install(entry->vector, dest, entry->trigger_mode, entry->polarity, entry->dest_mode);
}
void apic_ioapic_uninstall(ul irq_num)
{
rs_ioapic_uninstall(irq_num);
}
void apic_ioapic_edge_ack(ul irq_num) // 边沿触发
{
rs_apic_local_apic_edge_ack(irq_num);
}
/**
* @brief local apic 边沿触发应答
*
* @param irq_num
*/
void apic_local_apic_edge_ack(ul irq_num)
{
rs_apic_local_apic_edge_ack(irq_num);
}
/**
* @brief 构造RTE Entry结构体
*
* @param entry 返回的结构体
* @param vector 中断向量
* @param deliver_mode 投递模式
* @param dest_mode 目标模式
* @param deliver_status 投递状态
* @param polarity 电平触发极性
* @param irr 远程IRR标志位只读
* @param trigger 触发模式
* @param mask 屏蔽标志位0为未屏蔽 1为已屏蔽
* @param dest_apicID 目标apicID
*/
void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, uint8_t deliver_mode, uint8_t dest_mode,
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask,
uint8_t dest_apicID)
{
entry->vector = vector;
entry->deliver_mode = deliver_mode;
entry->dest_mode = dest_mode;
entry->deliver_status = deliver_status;
entry->polarity = polarity;
entry->remote_IRR = irr;
entry->trigger_mode = trigger;
entry->mask = mask;
entry->reserved = 0;
if (dest_mode == DEST_PHYSICAL)
{
entry->destination.physical.phy_dest = dest_apicID;
entry->destination.physical.reserved1 = 0;
entry->destination.physical.reserved2 = 0;
}
else
{
entry->destination.logical.logical_dest = dest_apicID;
entry->destination.logical.reserved1 = 0;
}
}
#pragma GCC pop_options