mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 07:06:47 +00:00
205 lines
5.7 KiB
C
205 lines
5.7 KiB
C
#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 |