mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-19 00:46:31 +00:00
使用rust重写了apic的驱动 (#425)
* 使用rust重写了apic的驱动。 * 修正signal和调度器的部分加锁逻辑,增加回退策略。 * 把pcb的flags字段替换为无锁的 * 使用cargo管理apic的编译 * 删除makefile中指定PIC的变量 --------- Co-authored-by: Gou Ngai <ymd7823@outlook.com> Co-authored-by: 櫻井桃華 <89176634+TihayaKousaka@users.noreply.github.com>
This commit is contained in:
@ -9,7 +9,7 @@ all:
|
||||
@list='$(kernel_arch_subdirs)'; for subdir in $$list; do \
|
||||
echo "make all in $$subdir";\
|
||||
cd $$subdir;\
|
||||
$(MAKE) all CFLAGS="$(CFLAGS)" PIC="$(PIC)";\
|
||||
$(MAKE) all CFLAGS="$(CFLAGS)" ;\
|
||||
cd ..;\
|
||||
done
|
||||
|
||||
|
@ -13,7 +13,7 @@ $(kernel_arch_x86_64_objs): ECHO
|
||||
$(CC) $(CFLAGS) -c $@ -o $@.o
|
||||
|
||||
$(kernel_arch_x86_64_subdirs): ECHO
|
||||
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
|
||||
$(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)"
|
||||
|
||||
all: $(kernel_arch_x86_64_objs) $(kernel_arch_x86_64_subdirs)
|
||||
|
||||
|
@ -13,7 +13,7 @@ $(kernel_arch_x86_64_asm_objs): ECHO
|
||||
$(CC) $(CFLAGS) -c $@ -o $@.o
|
||||
|
||||
# $(kernel_arch_x86_64_asm_subdirs): ECHO
|
||||
# $(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)" PIC="$(PIC)"
|
||||
# $(MAKE) -C $@ all CFLAGS="$(CFLAGS)" ASFLAGS="$(ASFLAGS)"
|
||||
|
||||
all: $(kernel_arch_x86_64_asm_objs)
|
||||
|
||||
|
228
kernel/src/arch/x86_64/driver/apic/apic.c
Normal file
228
kernel/src/arch/x86_64/driver/apic/apic.c
Normal file
@ -0,0 +1,228 @@
|
||||
#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/gate.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 初始化apic控制器
|
||||
*
|
||||
*/
|
||||
int apic_init()
|
||||
{
|
||||
cli();
|
||||
kinfo("Initializing APIC...");
|
||||
// 初始化中断门, 中断使用rsp0防止在软中断时发生嵌套,然后处理器重新加载导致数据被抹掉
|
||||
for (int i = 32; i <= 57; ++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]);
|
||||
|
||||
// 初始化BSP的APIC
|
||||
rs_apic_init_bsp();
|
||||
|
||||
kinfo("APIC initialized.");
|
||||
// sti();
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @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
|
252
kernel/src/arch/x86_64/driver/apic/apic.h
Normal file
252
kernel/src/arch/x86_64/driver/apic/apic.h
Normal file
@ -0,0 +1,252 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/asm.h>
|
||||
#include <process/ptrace.h>
|
||||
#include <exception/irq.h>
|
||||
#include <mm/mm.h>
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize("O0")
|
||||
|
||||
// 当前apic启用状态标志
|
||||
extern uint8_t __apic_enable_state;
|
||||
#define APIC_XAPIC_ENABLED 0
|
||||
#define APIC_X2APIC_ENABLED 1
|
||||
#define CURRENT_APIC_STATE (__apic_enable_state)
|
||||
|
||||
// ======== local apic 寄存器虚拟地址偏移量表 =======
|
||||
// 0x00~0x10 Reserved.
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_ID 0x20
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_Version 0x30
|
||||
// 0x40~0x70 Reserved.
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_TPR 0x80
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_APR 0x90
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_PPR 0xa0
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_EOI 0xb0
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_RRD 0xc0
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_LDR 0xd0
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_DFR 0xe0
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_SVR 0xf0
|
||||
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_31_0 0x100
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_63_32 0x110
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_95_64 0x120
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_127_96 0x130
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_159_128 0x140
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_191_160 0x150
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_223_192 0x160
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_ISR_255_224 0x170
|
||||
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_31_0 0x180
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_63_32 0x190
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_95_64 0x1a0
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_127_96 0x1b0
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_159_128 0x1c0
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_191_160 0x1d0
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_223_192 0x1e0
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_TMR_255_224 0x1f0
|
||||
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_31_0 0x200
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_63_32 0x210
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_95_64 0x220
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_127_96 0x230
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_159_128 0x240
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_191_160 0x250
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_223_192 0x260
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_IRR_255_224 0x270
|
||||
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_ESR 0x280
|
||||
|
||||
// 0x290~0x2e0 Reserved.
|
||||
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI 0x2f0
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0 0x300
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32 0x310
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER 0x320
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL 0x330
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR 0x340
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0 0x350
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1 0x360
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR 0x370
|
||||
// 初始计数寄存器(定时器专用)
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG 0x380
|
||||
// 当前计数寄存器(定时器专用)
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG 0x390
|
||||
// 0x3A0~0x3D0 Reserved.
|
||||
// 分频配置寄存器(定时器专用)
|
||||
#define LOCAL_APIC_OFFSET_Local_APIC_CLKDIV 0x3e0
|
||||
|
||||
uint32_t RCBA_vaddr = 0; // RCBA寄存器的虚拟地址
|
||||
|
||||
/*
|
||||
|
||||
1: LVT CMCI
|
||||
2: LVT Timer
|
||||
3: LVT Thermal Monitor
|
||||
4: LVT Performace Counter
|
||||
5: LVT LINT0
|
||||
6: LVT LINT1
|
||||
7: LVT Error
|
||||
|
||||
*/
|
||||
/**
|
||||
* LVT表项
|
||||
* */
|
||||
struct apic_LVT
|
||||
{
|
||||
uint vector : 8, // 0-7位全部置为1
|
||||
delivery_mode : 3, // 第[10:8]位置为100, 表示NMI
|
||||
reserved_1 : 1, // 第11位保留
|
||||
delivery_status : 1, // 第12位,投递状态 -> 发送挂起
|
||||
polarity : 1, // 第13位,电平触发极性 存在于LINT0,LINT1
|
||||
remote_IRR : 1, // 第14位,远程IRR标志位(只读) 存在于LINT0,LINT1
|
||||
trigger_mode : 1, // 第15位,触发模式(0位边沿触发,1为电平触发) 存在于LINT0,LINT1
|
||||
mask : 1, // 第16位,屏蔽标志位,(0为未屏蔽, 1为已屏蔽)
|
||||
timer_mode : 2, // 第[18:17]位,定时模式。(00:一次性定时, 01:周期性定时, 10:指定TSC值计数), 存在于定时器寄存器
|
||||
reserved_2 : 13; // [31:19]位保留
|
||||
|
||||
} __attribute((packed)); // 取消结构体的align
|
||||
|
||||
/**
|
||||
* @brief I/O APIC 的中断定向寄存器的结构体
|
||||
*
|
||||
*/
|
||||
struct apic_IO_APIC_RTE_entry
|
||||
{
|
||||
unsigned int vector : 8, // 0~7
|
||||
deliver_mode : 3, // [10:8] 投递模式默认为NMI
|
||||
dest_mode : 1, // 11 目标模式(0位物理模式,1为逻辑模式)
|
||||
deliver_status : 1, // 12 投递状态
|
||||
polarity : 1, // 13 电平触发极性
|
||||
remote_IRR : 1, // 14 远程IRR标志位(只读)
|
||||
trigger_mode : 1, // 15 触发模式(0位边沿触发,1为电平触发)
|
||||
mask : 1, // 16 屏蔽标志位,(0为未屏蔽, 1为已屏蔽)
|
||||
reserved : 15; // [31:17]位保留
|
||||
|
||||
union
|
||||
{
|
||||
// 物理模式
|
||||
struct
|
||||
{
|
||||
unsigned int reserved1 : 24, // [55:32] 保留
|
||||
phy_dest : 4, // [59:56] APIC ID
|
||||
reserved2 : 4; // [63:60] 保留
|
||||
} physical;
|
||||
|
||||
// 逻辑模式
|
||||
struct
|
||||
{
|
||||
unsigned int reserved1 : 24, // [55:32] 保留
|
||||
logical_dest : 8; // [63:56] 自定义APIC ID
|
||||
} logical;
|
||||
} destination;
|
||||
} __attribute__((packed));
|
||||
|
||||
// ========== APIC的寄存器的参数定义 ==============
|
||||
// 投递模式
|
||||
#define LOCAL_APIC_FIXED 0
|
||||
#define IO_APIC_FIXED 0
|
||||
#define ICR_APIC_FIXED 0
|
||||
|
||||
#define IO_APIC_Lowest_Priority 1
|
||||
#define ICR_Lowest_Priority 1
|
||||
|
||||
#define LOCAL_APIC_SMI 2
|
||||
#define APIC_SMI 2
|
||||
#define ICR_SMI 2
|
||||
|
||||
#define LOCAL_APIC_NMI 4
|
||||
#define APIC_NMI 4
|
||||
#define ICR_NMI 4
|
||||
|
||||
#define LOCAL_APIC_INIT 5
|
||||
#define APIC_INIT 5
|
||||
#define ICR_INIT 5
|
||||
|
||||
#define ICR_Start_up 6
|
||||
|
||||
#define IO_APIC_ExtINT 7
|
||||
|
||||
// 时钟模式
|
||||
#define APIC_LVT_Timer_One_Shot 0
|
||||
#define APIC_LVT_Timer_Periodic 1
|
||||
#define APIC_LVT_Timer_TSC_Deadline 2
|
||||
|
||||
// 屏蔽
|
||||
#define UNMASKED 0
|
||||
#define MASKED 1
|
||||
#define APIC_LVT_INT_MASKED 0x10000UL
|
||||
|
||||
// 触发模式
|
||||
#define EDGE_TRIGGER 0 // 边沿触发
|
||||
#define Level_TRIGGER 1 // 电平触发
|
||||
|
||||
// 投递模式
|
||||
#define IDLE 0 // 挂起
|
||||
#define SEND_PENDING 1 // 发送等待
|
||||
|
||||
// destination shorthand
|
||||
#define ICR_No_Shorthand 0
|
||||
#define ICR_Self 1
|
||||
#define ICR_ALL_INCLUDE_Self 2
|
||||
#define ICR_ALL_EXCLUDE_Self 3
|
||||
|
||||
// 投递目标模式
|
||||
#define DEST_PHYSICAL 0 // 物理模式
|
||||
#define DEST_LOGIC 1 // 逻辑模式
|
||||
|
||||
// level
|
||||
#define ICR_LEVEL_DE_ASSERT 0
|
||||
#define ICR_LEVEL_ASSERT 1
|
||||
|
||||
// 远程IRR标志位, 在处理Local APIC标志位时置位,在收到处理器发来的EOI命令时复位
|
||||
#define IRR_RESET 0
|
||||
#define IRR_ACCEPT 1
|
||||
|
||||
// 电平触发极性
|
||||
#define POLARITY_HIGH 0
|
||||
#define POLARITY_LOW 1
|
||||
|
||||
/**
|
||||
* @brief 中断服务程序
|
||||
*
|
||||
* @param rsp 中断栈指针
|
||||
* @param number 中断向量号
|
||||
*/
|
||||
void do_IRQ(struct pt_regs *rsp, ul number);
|
||||
void rs_apic_init_ap();
|
||||
|
||||
/**
|
||||
* @brief 初始化apic控制器
|
||||
*
|
||||
*/
|
||||
int apic_init();
|
||||
|
||||
// =========== 中断控制操作接口 ============
|
||||
void apic_ioapic_enable(ul irq_num);
|
||||
void apic_ioapic_disable(ul irq_num);
|
||||
ul apic_ioapic_install(ul irq_num, void *arg);
|
||||
void apic_ioapic_uninstall(ul irq_num);
|
||||
void apic_ioapic_edge_ack(ul irq_num); // ioapic边沿触发 应答
|
||||
|
||||
// void apic_local_apic_level_ack(ul irq_num);// local apic电平触发 应答
|
||||
void apic_local_apic_edge_ack(ul irq_num); // local apic边沿触发 应答
|
||||
|
||||
/**
|
||||
* @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);
|
||||
|
||||
#pragma GCC pop_options
|
96
kernel/src/arch/x86_64/driver/apic/apic_timer.c
Normal file
96
kernel/src/arch/x86_64/driver/apic/apic_timer.c
Normal file
@ -0,0 +1,96 @@
|
||||
#include "apic_timer.h"
|
||||
#include <common/kprint.h>
|
||||
#include <exception/irq.h>
|
||||
#include <process/process.h>
|
||||
#include <sched/sched.h>
|
||||
|
||||
|
||||
// bsp 是否已经完成apic时钟初始化
|
||||
static bool bsp_initialized = false;
|
||||
|
||||
extern void rs_apic_timer_install(int irq_num);
|
||||
extern void rs_apic_timer_uninstall(int irq_num);
|
||||
extern void rs_apic_timer_enable(int irq_num);
|
||||
extern void rs_apic_timer_disable(int irq_num);
|
||||
extern int rs_apic_timer_handle_irq();
|
||||
|
||||
/**
|
||||
* @brief 初始化AP核的apic时钟
|
||||
*
|
||||
*/
|
||||
void apic_timer_ap_core_init()
|
||||
{
|
||||
while (!bsp_initialized)
|
||||
{
|
||||
pause();
|
||||
}
|
||||
|
||||
apic_timer_init();
|
||||
}
|
||||
|
||||
void apic_timer_enable(uint64_t irq_num)
|
||||
{
|
||||
rs_apic_timer_enable(irq_num);
|
||||
}
|
||||
|
||||
void apic_timer_disable(uint64_t irq_num)
|
||||
{
|
||||
rs_apic_timer_disable(irq_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 安装local apic定时器中断
|
||||
*
|
||||
* @param irq_num 中断向量号
|
||||
* @param arg 初始计数值
|
||||
* @return uint64_t
|
||||
*/
|
||||
uint64_t apic_timer_install(ul irq_num, void *arg)
|
||||
{
|
||||
|
||||
rs_apic_timer_install(irq_num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void apic_timer_uninstall(ul irq_num)
|
||||
{
|
||||
rs_apic_timer_uninstall(irq_num);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
rs_apic_timer_handle_irq();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化local APIC定时器
|
||||
*
|
||||
*/
|
||||
void apic_timer_init()
|
||||
{
|
||||
kinfo("Initializing apic timer for cpu %d", rs_current_pcb_cpuid());
|
||||
io_mfence();
|
||||
irq_register(APIC_TIMER_IRQ_NUM, NULL, &apic_timer_handler, 0, &apic_timer_intr_controller,
|
||||
"apic timer");
|
||||
io_mfence();
|
||||
if (rs_current_pcb_cpuid() == 0)
|
||||
{
|
||||
bsp_initialized = true;
|
||||
}
|
||||
kdebug("apic timer init done for cpu %d", rs_current_pcb_cpuid());
|
||||
}
|
14
kernel/src/arch/x86_64/driver/apic/apic_timer.h
Normal file
14
kernel/src/arch/x86_64/driver/apic/apic_timer.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/unistd.h>
|
||||
#include "apic.h"
|
||||
|
||||
#define APIC_TIMER_IRQ_NUM 151
|
||||
|
||||
/**
|
||||
* @brief 初始化local APIC定时器
|
||||
*
|
||||
*/
|
||||
void apic_timer_init();
|
||||
|
||||
void apic_timer_ap_core_init();
|
257
kernel/src/arch/x86_64/driver/apic/apic_timer.rs
Normal file
257
kernel/src/arch/x86_64/driver/apic/apic_timer.rs
Normal file
@ -0,0 +1,257 @@
|
||||
use core::cell::RefCell;
|
||||
|
||||
use crate::arch::driver::tsc::TSCManager;
|
||||
use crate::include::bindings::bindings::APIC_TIMER_IRQ_NUM;
|
||||
|
||||
use crate::kdebug;
|
||||
use crate::mm::percpu::PerCpu;
|
||||
use crate::sched::core::sched_update_jiffies;
|
||||
use crate::smp::core::smp_get_processor_id;
|
||||
use crate::syscall::SystemError;
|
||||
pub use drop;
|
||||
use x86::cpuid::cpuid;
|
||||
use x86::msr::{wrmsr, IA32_X2APIC_DIV_CONF, IA32_X2APIC_INIT_COUNT};
|
||||
|
||||
use super::xapic::XApicOffset;
|
||||
use super::{CurrentApic, LVTRegister, LocalAPIC, LVT};
|
||||
|
||||
static mut LOCAL_APIC_TIMERS: [RefCell<LocalApicTimer>; PerCpu::MAX_CPU_NUM] =
|
||||
[const { RefCell::new(LocalApicTimer::new()) }; PerCpu::MAX_CPU_NUM];
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) fn local_apic_timer_instance(cpu_id: u32) -> core::cell::Ref<'static, LocalApicTimer> {
|
||||
unsafe { LOCAL_APIC_TIMERS[cpu_id as usize].borrow() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) fn local_apic_timer_instance_mut(
|
||||
cpu_id: u32,
|
||||
) -> core::cell::RefMut<'static, LocalApicTimer> {
|
||||
unsafe { LOCAL_APIC_TIMERS[cpu_id as usize].borrow_mut() }
|
||||
}
|
||||
|
||||
/// 初始化BSP的APIC定时器
|
||||
///
|
||||
fn init_bsp_apic_timer() {
|
||||
kdebug!("init_bsp_apic_timer");
|
||||
assert!(smp_get_processor_id() == 0);
|
||||
let mut local_apic_timer = local_apic_timer_instance_mut(0);
|
||||
local_apic_timer.init(
|
||||
LocalApicTimerMode::Periodic,
|
||||
LocalApicTimer::periodic_default_initial_count(),
|
||||
LocalApicTimer::DIVISOR as u32,
|
||||
);
|
||||
kdebug!("init_bsp_apic_timer done");
|
||||
}
|
||||
|
||||
fn init_ap_apic_timer() {
|
||||
kdebug!("init_ap_apic_timer");
|
||||
let cpu_id = smp_get_processor_id();
|
||||
assert!(cpu_id != 0);
|
||||
|
||||
let mut local_apic_timer = local_apic_timer_instance_mut(cpu_id);
|
||||
local_apic_timer.init(
|
||||
LocalApicTimerMode::Periodic,
|
||||
LocalApicTimer::periodic_default_initial_count(),
|
||||
LocalApicTimer::DIVISOR as u32,
|
||||
);
|
||||
kdebug!("init_ap_apic_timer done");
|
||||
}
|
||||
|
||||
pub(super) struct LocalApicTimerIntrController;
|
||||
|
||||
impl LocalApicTimerIntrController {
|
||||
pub(super) fn install(&self, _irq_num: u8) {
|
||||
kdebug!("LocalApicTimerIntrController::install");
|
||||
if smp_get_processor_id() == 0 {
|
||||
init_bsp_apic_timer();
|
||||
} else {
|
||||
init_ap_apic_timer();
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn uninstall(&self) {
|
||||
let cpu_id = smp_get_processor_id();
|
||||
let local_apic_timer = local_apic_timer_instance(cpu_id);
|
||||
local_apic_timer.stop_current();
|
||||
}
|
||||
|
||||
pub(super) fn enable(&self) {
|
||||
kdebug!("LocalApicTimerIntrController::enable");
|
||||
let cpu_id = smp_get_processor_id();
|
||||
let mut local_apic_timer = local_apic_timer_instance_mut(cpu_id);
|
||||
local_apic_timer.start_current();
|
||||
}
|
||||
|
||||
pub(super) fn disable(&self) {
|
||||
let cpu_id = smp_get_processor_id();
|
||||
let local_apic_timer = local_apic_timer_instance_mut(cpu_id);
|
||||
local_apic_timer.stop_current();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct LocalApicTimer {
|
||||
mode: LocalApicTimerMode,
|
||||
/// IntialCount
|
||||
initial_count: u64,
|
||||
divisor: u32,
|
||||
/// 是否已经触发(oneshot模式)
|
||||
triggered: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(u32)]
|
||||
pub enum LocalApicTimerMode {
|
||||
Oneshot = 0,
|
||||
Periodic = 1,
|
||||
Deadline = 2,
|
||||
}
|
||||
|
||||
impl LocalApicTimer {
|
||||
/// 定时器中断的间隔
|
||||
pub const INTERVAL_MS: u64 = 5;
|
||||
pub const DIVISOR: u64 = 3;
|
||||
|
||||
/// IoApicManager 初值为0或false
|
||||
pub const fn new() -> Self {
|
||||
LocalApicTimer {
|
||||
mode: LocalApicTimerMode::Periodic,
|
||||
initial_count: 0,
|
||||
divisor: 0,
|
||||
triggered: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// 周期模式下的默认初始值
|
||||
pub fn periodic_default_initial_count() -> u64 {
|
||||
let cpu_khz = TSCManager::cpu_khz();
|
||||
|
||||
// 疑惑:这里使用khz吗?
|
||||
// 我觉得应该是hz,但是由于旧的代码是测量出initcnt的,而不是计算的
|
||||
// 然后我发现使用hz会导致计算出来的initcnt太大,导致系统卡顿,而khz的却能跑
|
||||
let count = cpu_khz * Self::INTERVAL_MS / (1000 * Self::DIVISOR);
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Init this manager.
|
||||
///
|
||||
/// At this time, it does nothing.
|
||||
fn init(&mut self, mode: LocalApicTimerMode, initial_count: u64, divisor: u32) {
|
||||
self.stop_current();
|
||||
self.triggered = false;
|
||||
match mode {
|
||||
LocalApicTimerMode::Periodic => self.install_periodic_mode(initial_count, divisor),
|
||||
LocalApicTimerMode::Oneshot => todo!(),
|
||||
LocalApicTimerMode::Deadline => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn install_periodic_mode(&mut self, initial_count: u64, divisor: u32) {
|
||||
kdebug!(
|
||||
"install_periodic_mode: initial_count = {}, divisor = {}",
|
||||
initial_count,
|
||||
divisor
|
||||
);
|
||||
self.mode = LocalApicTimerMode::Periodic;
|
||||
self.set_divisor(divisor);
|
||||
self.set_initial_cnt(initial_count);
|
||||
self.setup_lvt(APIC_TIMER_IRQ_NUM as u8, true, LocalApicTimerMode::Periodic);
|
||||
}
|
||||
|
||||
fn setup_lvt(&mut self, vector: u8, mask: bool, mode: LocalApicTimerMode) {
|
||||
let mode: u32 = mode as u32;
|
||||
let data = (mode << 17) | (vector as u32) | (if mask { 1 << 16 } else { 0 });
|
||||
let lvt = LVT::new(LVTRegister::Timer, data).unwrap();
|
||||
|
||||
CurrentApic.set_lvt(lvt);
|
||||
}
|
||||
|
||||
fn set_divisor(&mut self, divisor: u32) {
|
||||
self.divisor = divisor;
|
||||
CurrentApic.set_timer_divisor(divisor as u32);
|
||||
}
|
||||
|
||||
fn set_initial_cnt(&mut self, initial_count: u64) {
|
||||
self.initial_count = initial_count;
|
||||
CurrentApic.set_timer_initial_count(initial_count);
|
||||
}
|
||||
|
||||
fn start_current(&mut self) {
|
||||
let mut lvt = CurrentApic.read_lvt(LVTRegister::Timer);
|
||||
lvt.set_mask(false);
|
||||
CurrentApic.set_lvt(lvt);
|
||||
}
|
||||
|
||||
fn stop_current(&self) {
|
||||
let mut lvt = CurrentApic.read_lvt(LVTRegister::Timer);
|
||||
lvt.set_mask(true);
|
||||
CurrentApic.set_lvt(lvt);
|
||||
}
|
||||
|
||||
/// 检查是否支持TSC-Deadline
|
||||
///
|
||||
/// 此函数调用cpuid,请避免多次调用此函数。
|
||||
/// 如果支持TSC-Deadline模式,则除非TSC为常数,否则不会启用该模式。
|
||||
#[allow(dead_code)]
|
||||
pub fn is_deadline_mode_supported(&self) -> bool {
|
||||
let res = cpuid!(1);
|
||||
return (res.ecx & (1 << 24)) != 0;
|
||||
}
|
||||
|
||||
pub(super) fn handle_irq() -> Result<(), SystemError> {
|
||||
sched_update_jiffies();
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for LocalApicTimerMode {
|
||||
type Error = SystemError;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0b00 => {
|
||||
return Ok(LocalApicTimerMode::Oneshot);
|
||||
}
|
||||
0b01 => {
|
||||
return Ok(LocalApicTimerMode::Periodic);
|
||||
}
|
||||
0b10 => {
|
||||
return Ok(LocalApicTimerMode::Deadline);
|
||||
}
|
||||
_ => {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CurrentApic {
|
||||
fn set_timer_divisor(&self, divisor: u32) {
|
||||
if self.x2apic_enabled() {
|
||||
unsafe { wrmsr(IA32_X2APIC_DIV_CONF, divisor.into()) };
|
||||
} else {
|
||||
unsafe {
|
||||
self.write_xapic_register(
|
||||
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_CLKDIV,
|
||||
divisor.into(),
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn set_timer_initial_count(&self, initial_count: u64) {
|
||||
if self.x2apic_enabled() {
|
||||
unsafe {
|
||||
wrmsr(IA32_X2APIC_INIT_COUNT.into(), initial_count);
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
self.write_xapic_register(
|
||||
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG,
|
||||
initial_count as u32,
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
84
kernel/src/arch/x86_64/driver/apic/c_adapter.rs
Normal file
84
kernel/src/arch/x86_64/driver/apic/c_adapter.rs
Normal file
@ -0,0 +1,84 @@
|
||||
use super::{
|
||||
apic_timer::{LocalApicTimer, LocalApicTimerIntrController},
|
||||
ioapic::{ioapic_disable, ioapic_enable, ioapic_install, ioapic_uninstall},
|
||||
CurrentApic, LocalAPIC,
|
||||
};
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_apic_timer_install(irq_num: u8) {
|
||||
LocalApicTimerIntrController.install(irq_num);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_apic_timer_uninstall(_irq_num: u8) {
|
||||
LocalApicTimerIntrController.uninstall();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_apic_timer_enable(_irq_num: u8) {
|
||||
LocalApicTimerIntrController.enable();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_apic_timer_disable(_irq_num: u8) {
|
||||
LocalApicTimerIntrController.disable();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_apic_local_apic_edge_ack(_irq_num: u8) {
|
||||
CurrentApic.send_eoi();
|
||||
}
|
||||
|
||||
/// 初始化bsp处理器的apic
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_apic_init_bsp() -> i32 {
|
||||
if CurrentApic.init_current_cpu() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_apic_init_ap() -> i32 {
|
||||
if CurrentApic.init_current_cpu() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_ioapic_install(
|
||||
vector: u8,
|
||||
dest: u8,
|
||||
level_triggered: bool,
|
||||
active_high: bool,
|
||||
dest_logic: bool,
|
||||
) -> i32 {
|
||||
return ioapic_install(vector, dest, level_triggered, active_high, dest_logic)
|
||||
.map(|_| 0)
|
||||
.unwrap_or_else(|e| e.to_posix_errno());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_ioapic_uninstall(vector: u8) {
|
||||
ioapic_uninstall(vector);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_ioapic_enable(vector: u8) {
|
||||
ioapic_enable(vector);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_ioapic_disable(vector: u8) {
|
||||
ioapic_disable(vector);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_apic_timer_handle_irq(_irq_num: u8) -> i32 {
|
||||
return LocalApicTimer::handle_irq()
|
||||
.map(|_| 0)
|
||||
.unwrap_or_else(|e| e.to_posix_errno());
|
||||
}
|
364
kernel/src/arch/x86_64/driver/apic/ioapic.rs
Normal file
364
kernel/src/arch/x86_64/driver/apic/ioapic.rs
Normal file
@ -0,0 +1,364 @@
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use acpi::madt::Madt;
|
||||
use bit_field::BitField;
|
||||
use bitflags::bitflags;
|
||||
|
||||
use crate::{
|
||||
driver::acpi::acpi_manager,
|
||||
kdebug, kinfo,
|
||||
libs::{
|
||||
once::Once,
|
||||
spinlock::SpinLock,
|
||||
volatile::{volwrite, Volatile},
|
||||
},
|
||||
mm::{
|
||||
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
|
||||
PhysAddr,
|
||||
},
|
||||
syscall::SystemError,
|
||||
};
|
||||
|
||||
use super::{CurrentApic, LocalAPIC};
|
||||
|
||||
static mut __IOAPIC: Option<SpinLock<IoApic>> = None;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn IOAPIC() -> &'static SpinLock<IoApic> {
|
||||
unsafe { __IOAPIC.as_ref().unwrap() }
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct IoApic {
|
||||
reg: *mut u32,
|
||||
data: *mut u32,
|
||||
virt_eoi: *mut u32,
|
||||
phys_base: PhysAddr,
|
||||
mmio_guard: MMIOSpaceGuard,
|
||||
}
|
||||
|
||||
impl IoApic {
|
||||
/// IO APIC的中断向量号从32开始
|
||||
pub const VECTOR_BASE: u8 = 32;
|
||||
|
||||
/// Create a new IOAPIC.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// You must provide a valid address.
|
||||
pub unsafe fn new() -> Self {
|
||||
static INIT_STATE: Once = Once::new();
|
||||
assert!(!INIT_STATE.is_completed());
|
||||
|
||||
let mut result: Option<IoApic> = None;
|
||||
INIT_STATE.call_once(|| {
|
||||
kinfo!("Initializing ioapic...");
|
||||
|
||||
// get ioapic base from acpi
|
||||
|
||||
let madt = acpi_manager()
|
||||
.tables()
|
||||
.unwrap()
|
||||
.find_table::<Madt>()
|
||||
.expect("IoApic::new(): failed to find MADT");
|
||||
|
||||
let io_apic_paddr = madt
|
||||
.entries()
|
||||
.find(|x| {
|
||||
if let acpi::madt::MadtEntry::IoApic(_x) = x {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
.map(|x| {
|
||||
if let acpi::madt::MadtEntry::IoApic(x) = x {
|
||||
Some(x.io_apic_address)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.flatten()
|
||||
.unwrap();
|
||||
|
||||
let phys_base = PhysAddr::new(io_apic_paddr as usize);
|
||||
|
||||
let mmio_guard = mmio_pool()
|
||||
.create_mmio(0x1000)
|
||||
.expect("IoApic::new(): failed to create mmio");
|
||||
assert!(
|
||||
mmio_guard.map_phys(phys_base, 0x1000).is_ok(),
|
||||
"IoApic::new(): failed to map phys"
|
||||
);
|
||||
kdebug!("Ioapic map ok");
|
||||
let reg = mmio_guard.vaddr();
|
||||
|
||||
result = Some(IoApic {
|
||||
reg: reg.data() as *mut u32,
|
||||
data: (reg + 0x10).data() as *mut u32,
|
||||
virt_eoi: (reg + 0x40).data() as *mut u32,
|
||||
phys_base,
|
||||
mmio_guard,
|
||||
});
|
||||
kdebug!("IOAPIC: to mask all RTE");
|
||||
// 屏蔽所有的RTE
|
||||
let res_mut = result.as_mut().unwrap();
|
||||
for i in 0..res_mut.supported_interrupts() {
|
||||
res_mut.write_rte(i, 0x20 + i, RedirectionEntry::DISABLED, 0);
|
||||
}
|
||||
kdebug!("Ioapic init done");
|
||||
});
|
||||
|
||||
assert!(
|
||||
result.is_some(),
|
||||
"Failed to init ioapic, maybe this is a double initialization bug?"
|
||||
);
|
||||
return result.unwrap();
|
||||
}
|
||||
|
||||
/// Disable all interrupts.
|
||||
#[allow(dead_code)]
|
||||
pub fn disable_all(&mut self) {
|
||||
// Mark all interrupts edge-triggered, active high, disabled,
|
||||
// and not routed to any CPUs.
|
||||
for i in 0..self.supported_interrupts() {
|
||||
self.disable(i);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn read(&mut self, reg: u8) -> u32 {
|
||||
assert!(!(0x3..REG_TABLE).contains(®));
|
||||
self.reg.write_volatile(reg as u32);
|
||||
self.data.read_volatile()
|
||||
}
|
||||
|
||||
/// 直接写入REG_TABLE内的寄存器
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// * `reg` - 寄存器下标
|
||||
/// * `data` - 寄存器数据
|
||||
unsafe fn write(&mut self, reg: u8, data: u32) {
|
||||
// 0x1 & 0x2 are read-only regs
|
||||
assert!(!(0x1..REG_TABLE).contains(®));
|
||||
self.reg.write_volatile(reg as u32);
|
||||
self.data.write_volatile(data);
|
||||
}
|
||||
|
||||
fn write_rte(&mut self, rte_index: u8, vector: u8, flags: RedirectionEntry, dest: u8) {
|
||||
unsafe {
|
||||
self.write(REG_TABLE + 2 * rte_index, vector as u32 | flags.bits());
|
||||
self.write(REG_TABLE + 2 * rte_index + 1, (dest as u32) << 24);
|
||||
}
|
||||
}
|
||||
|
||||
/// 标记中断边沿触发、高电平有效、
|
||||
/// 启用并路由到给定的 cpunum,即是是该 cpu 的 APIC ID(不是cpuid)
|
||||
pub fn enable(&mut self, rte_index: u8) {
|
||||
let mut val = unsafe { self.read(REG_TABLE + 2 * rte_index) };
|
||||
val &= !RedirectionEntry::DISABLED.bits();
|
||||
unsafe { self.write(REG_TABLE + 2 * rte_index, val) };
|
||||
}
|
||||
|
||||
pub fn disable(&mut self, rte_index: u8) {
|
||||
let reg = REG_TABLE + 2 * rte_index;
|
||||
let mut val = unsafe { self.read(reg) };
|
||||
val |= RedirectionEntry::DISABLED.bits();
|
||||
unsafe { self.write(reg, val) };
|
||||
}
|
||||
|
||||
/// 安装中断
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// * `rte_index` - RTE下标
|
||||
/// * `vector` - 中断向量号
|
||||
/// * `dest` - 目标CPU的APIC ID
|
||||
/// * `level_triggered` - 是否为电平触发
|
||||
/// * `active_high` - 是否为高电平有效
|
||||
/// * `dest_logic` - 是否为逻辑模式
|
||||
/// * `mask` - 是否屏蔽
|
||||
pub fn install(
|
||||
&mut self,
|
||||
rte_index: u8,
|
||||
vector: u8,
|
||||
dest: u8,
|
||||
level_triggered: bool,
|
||||
active_high: bool,
|
||||
dest_logic: bool,
|
||||
mut mask: bool,
|
||||
) -> Result<(), SystemError> {
|
||||
// 重定向表从 REG_TABLE 开始,使用两个寄存器来配置每个中断。
|
||||
// 一对中的第一个(低位)寄存器包含配置位。32bit
|
||||
// 第二个(高)寄存器包含一个位掩码,告诉哪些 CPU 可以服务该中断。
|
||||
// level_triggered:如果为真,表示中断触发方式为电平触发(level-triggered),则将RedirectionEntry::LEVEL标志位设置在flags中。
|
||||
// active_high:如果为假,表示中断的极性为低电平有效(active-low),则将RedirectionEntry::ACTIVELOW标志位设置在flags中。
|
||||
// dest_logic:如果为真,表示中断目标为逻辑模式(logical mode),则将RedirectionEntry::LOGICAL标志位设置在flags中。
|
||||
// !(0x20..=0xef).contains(&vector):判断中断向量号(vector)是否在范围0x20到0xef之外,如果是,则表示中断无效,将mask标志位设置为真。
|
||||
// mask:如果为真,表示中断被屏蔽(masked),将RedirectionEntry::DISABLED标志位设置在flags中。
|
||||
let mut flags = RedirectionEntry::NONE;
|
||||
if level_triggered {
|
||||
flags |= RedirectionEntry::LEVEL;
|
||||
}
|
||||
if !active_high {
|
||||
flags |= RedirectionEntry::ACTIVELOW;
|
||||
}
|
||||
if dest_logic {
|
||||
flags |= RedirectionEntry::LOGICAL;
|
||||
}
|
||||
if !(0x20..=0xef).contains(&vector) {
|
||||
mask = true;
|
||||
}
|
||||
if mask {
|
||||
flags |= RedirectionEntry::DISABLED;
|
||||
}
|
||||
self.write_rte(rte_index, vector, flags, dest);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// Get the vector number for the given IRQ.
|
||||
#[allow(dead_code)]
|
||||
pub fn irq_vector(&mut self, irq: u8) -> u8 {
|
||||
unsafe { self.read(REG_TABLE + 2 * irq).get_bits(0..8) as u8 }
|
||||
}
|
||||
|
||||
/// Set the vector number for the given IRQ.
|
||||
#[allow(dead_code)]
|
||||
pub fn set_irq_vector(&mut self, irq: u8, vector: u8) {
|
||||
let mut old = unsafe { self.read(REG_TABLE + 2 * irq) };
|
||||
let old_vector = old.get_bits(0..8);
|
||||
if !(0x20..=0xfe).contains(&old_vector) {
|
||||
old |= RedirectionEntry::DISABLED.bits();
|
||||
}
|
||||
unsafe {
|
||||
self.write(REG_TABLE + 2 * irq, *old.set_bits(0..8, vector as u32));
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn id(&mut self) -> u8 {
|
||||
unsafe { self.read(REG_ID).get_bits(24..28) as u8 }
|
||||
}
|
||||
|
||||
/// IO APIC Version
|
||||
#[allow(dead_code)]
|
||||
pub fn version(&mut self) -> u8 {
|
||||
unsafe { self.read(REG_VER).get_bits(0..8) as u8 }
|
||||
}
|
||||
|
||||
/// Number of supported interrupts by this IO APIC.
|
||||
///
|
||||
/// Max Redirection Entry = "how many IRQs can this I/O APIC handle - 1"
|
||||
/// The -1 is silly so we add one back to it.
|
||||
pub fn supported_interrupts(&mut self) -> u8 {
|
||||
unsafe { (self.read(REG_VER).get_bits(16..24) + 1) as u8 }
|
||||
}
|
||||
|
||||
fn vector_rte_index(irq_num: u8) -> u8 {
|
||||
assert!(irq_num >= Self::VECTOR_BASE);
|
||||
irq_num - Self::VECTOR_BASE
|
||||
}
|
||||
|
||||
/// 电平响应
|
||||
#[allow(dead_code)]
|
||||
fn level_ack(&mut self, irq_num: u8) {
|
||||
#[repr(C)]
|
||||
struct LevelAck {
|
||||
virt_eoi: Volatile<u32>,
|
||||
}
|
||||
|
||||
let p = NonNull::new(self.virt_eoi as *mut LevelAck).unwrap();
|
||||
|
||||
unsafe {
|
||||
volwrite!(p, virt_eoi, irq_num as u32);
|
||||
}
|
||||
}
|
||||
|
||||
/// 边沿响应
|
||||
#[allow(dead_code)]
|
||||
fn edge_ack(&mut self, _irq_num: u8) {
|
||||
CurrentApic.send_eoi();
|
||||
}
|
||||
}
|
||||
|
||||
/// Register index: ID
|
||||
const REG_ID: u8 = 0x00;
|
||||
/// 获取IO APIC Version
|
||||
const REG_VER: u8 = 0x01;
|
||||
/// Redirection table base
|
||||
const REG_TABLE: u8 = 0x10;
|
||||
|
||||
bitflags! {
|
||||
/// The redirection table starts at REG_TABLE and uses
|
||||
/// two registers to configure each interrupt.
|
||||
/// The first (low) register in a pair contains configuration bits.
|
||||
/// The second (high) register contains a bitmask telling which
|
||||
/// CPUs can serve that interrupt.
|
||||
struct RedirectionEntry: u32 {
|
||||
/// Interrupt disabled
|
||||
const DISABLED = 0x00010000;
|
||||
/// Level-triggered (vs edge-)
|
||||
const LEVEL = 0x00008000;
|
||||
/// Active low (vs high)
|
||||
const ACTIVELOW = 0x00002000;
|
||||
/// Destination is CPU id (vs APIC ID)
|
||||
const LOGICAL = 0x00000800;
|
||||
/// None
|
||||
const NONE = 0x00000000;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ioapic_init() {
|
||||
kinfo!("Initializing ioapic...");
|
||||
let ioapic = unsafe { IoApic::new() };
|
||||
unsafe {
|
||||
__IOAPIC = Some(SpinLock::new(ioapic));
|
||||
}
|
||||
kinfo!("IO Apic initialized.");
|
||||
}
|
||||
|
||||
/// 安装中断
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// * `vector` - 中断向量号
|
||||
/// * `dest` - 目标CPU的APIC ID
|
||||
/// * `level_triggered` - 是否为电平触发
|
||||
/// * `active_high` - 是否为高电平有效
|
||||
/// * `dest_logic` - 是否为逻辑模式
|
||||
/// * `mask` - 是否屏蔽
|
||||
pub(super) fn ioapic_install(
|
||||
vector: u8,
|
||||
dest: u8,
|
||||
level_triggered: bool,
|
||||
active_high: bool,
|
||||
dest_logic: bool,
|
||||
) -> Result<(), SystemError> {
|
||||
let rte_index = IoApic::vector_rte_index(vector);
|
||||
return IOAPIC().lock_irqsave().install(
|
||||
rte_index,
|
||||
vector,
|
||||
dest,
|
||||
level_triggered,
|
||||
active_high,
|
||||
dest_logic,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
/// 卸载中断
|
||||
pub(super) fn ioapic_uninstall(vector: u8) {
|
||||
let rte_index = IoApic::vector_rte_index(vector);
|
||||
IOAPIC().lock_irqsave().disable(rte_index);
|
||||
}
|
||||
|
||||
/// 使能中断
|
||||
pub(super) fn ioapic_enable(vector: u8) {
|
||||
let rte_index = IoApic::vector_rte_index(vector);
|
||||
IOAPIC().lock_irqsave().enable(rte_index);
|
||||
}
|
||||
|
||||
/// 禁用中断
|
||||
pub(super) fn ioapic_disable(vector: u8) {
|
||||
let rte_index = IoApic::vector_rte_index(vector);
|
||||
IOAPIC().lock_irqsave().disable(rte_index);
|
||||
}
|
623
kernel/src/arch/x86_64/driver/apic/mod.rs
Normal file
623
kernel/src/arch/x86_64/driver/apic/mod.rs
Normal file
@ -0,0 +1,623 @@
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use atomic_enum::atomic_enum;
|
||||
use x86::{apic::Icr, msr::IA32_APIC_BASE};
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
driver::apic::{ioapic::ioapic_init, x2apic::X2Apic, xapic::XApic},
|
||||
io::PortIOArch,
|
||||
CurrentPortIOArch,
|
||||
},
|
||||
kdebug, kinfo,
|
||||
mm::PhysAddr,
|
||||
smp::core::smp_get_processor_id,
|
||||
syscall::SystemError,
|
||||
};
|
||||
|
||||
use self::{
|
||||
apic_timer::LocalApicTimerMode,
|
||||
xapic::{current_xapic_instance, XApicOffset},
|
||||
};
|
||||
|
||||
pub mod apic_timer;
|
||||
mod c_adapter;
|
||||
pub mod ioapic;
|
||||
pub mod x2apic;
|
||||
pub mod xapic;
|
||||
|
||||
/// 当前启用的APIC类型
|
||||
#[atomic_enum]
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum LocalApicEnableType {
|
||||
XApic,
|
||||
X2Apic,
|
||||
}
|
||||
|
||||
static LOCAL_APIC_ENABLE_TYPE: AtomicLocalApicEnableType =
|
||||
AtomicLocalApicEnableType::new(LocalApicEnableType::XApic);
|
||||
|
||||
pub trait LocalAPIC {
|
||||
/// @brief 判断当前处理器是否支持这个类型的apic
|
||||
///
|
||||
/// @return true 当前处理器支持这个类型的apic
|
||||
/// @return false 当前处理器不支持这个类型的apic
|
||||
fn support() -> bool;
|
||||
|
||||
/// @brief 为当前处理器初始化local apic
|
||||
///
|
||||
/// @return true 初始化成功
|
||||
/// @return false 初始化失败
|
||||
fn init_current_cpu(&mut self) -> bool;
|
||||
|
||||
/// @brief 发送EOI信号(End of interrupt)
|
||||
fn send_eoi(&self);
|
||||
|
||||
/// @brief 获取APIC版本号
|
||||
fn version(&self) -> u8;
|
||||
|
||||
/// @brief 判断当前处理器是否支持EOI广播抑制
|
||||
fn support_eoi_broadcast_suppression(&self) -> bool;
|
||||
|
||||
/// 获取最多支持的LVT寄存器数量
|
||||
fn max_lvt_entry(&self) -> u8;
|
||||
|
||||
/// @brief 获取当前处理器的APIC ID
|
||||
fn id(&self) -> u32;
|
||||
|
||||
/// @brief 设置LVT寄存器
|
||||
///
|
||||
/// @param register 寄存器
|
||||
/// @param lvt 要被设置成的值
|
||||
fn set_lvt(&mut self, lvt: LVT);
|
||||
|
||||
/// 读取LVT寄存器
|
||||
fn read_lvt(&self, reg: LVTRegister) -> LVT;
|
||||
|
||||
fn mask_all_lvt(&mut self);
|
||||
|
||||
/// 写入ICR寄存器
|
||||
fn write_icr(&self, icr: Icr);
|
||||
}
|
||||
|
||||
/// @brief 所有LVT寄存器的枚举类型
|
||||
#[allow(dead_code)]
|
||||
#[repr(u32)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum LVTRegister {
|
||||
/// CMCI寄存器
|
||||
///
|
||||
/// 如果支持CMCI功能,那么,当修正的机器错误超过阈值时,Local APIC通过CMCI寄存器的配置,
|
||||
/// 向处理器核心投递中断消息
|
||||
CMCI = 0x82f,
|
||||
/// 定时器寄存器
|
||||
///
|
||||
/// 当APIC定时器产生中断信号时,Local APIC通过定时器寄存器的设置,向处理器投递中断消息
|
||||
Timer = 0x832,
|
||||
/// 温度传感器寄存器
|
||||
///
|
||||
/// 当处理器内部的温度传感器产生中断请求信号时,Local APIC会通过温度传感器寄存器的设置,
|
||||
/// 向处理器投递中断消息。
|
||||
Thermal = 0x833,
|
||||
/// 性能监控计数器寄存器
|
||||
///
|
||||
/// 当性能检测计数器寄存器溢出,产生中断请求时,Local APIC将会根据这个寄存器的配置,
|
||||
/// 向处理器投递中断消息
|
||||
PerformanceMonitor = 0x834,
|
||||
/// 当处理器的LINT0引脚接收到中断请求信号时,Local APIC会根据这个寄存器的配置,
|
||||
/// 向处理器投递中断消息
|
||||
LINT0 = 0x835,
|
||||
/// 当处理器的LINT0引脚接收到中断请求信号时,Local APIC会根据这个寄存器的配置,
|
||||
/// 向处理器投递中断消息
|
||||
LINT1 = 0x836,
|
||||
/// 错误寄存器
|
||||
///
|
||||
/// 当APIC检测到内部错误而产生中断请求信号时,它将会通过错误寄存器的设置,向处理器投递中断消息
|
||||
ErrorReg = 0x837,
|
||||
}
|
||||
|
||||
impl Into<u32> for LVTRegister {
|
||||
fn into(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LVT {
|
||||
register: LVTRegister,
|
||||
data: u32,
|
||||
}
|
||||
|
||||
impl LVT {
|
||||
/// 当第16位为1时,表示屏蔽中断
|
||||
pub const MASKED: u32 = 1 << 16;
|
||||
|
||||
pub fn new(register: LVTRegister, data: u32) -> Option<Self> {
|
||||
// vector: u8, mode: DeliveryMode, status: DeliveryStatus
|
||||
let mut result = Self { register, data: 0 };
|
||||
result.set_vector((data & 0xFF) as u8);
|
||||
match result.register {
|
||||
LVTRegister::Timer | LVTRegister::ErrorReg => {}
|
||||
_ => {
|
||||
result
|
||||
.set_delivery_mode(DeliveryMode::try_from(((data >> 8) & 0b111) as u8).ok()?)
|
||||
.ok()?;
|
||||
}
|
||||
}
|
||||
|
||||
if let LVTRegister::LINT0 | LVTRegister::LINT1 = result.register {
|
||||
result.set_interrupt_input_pin_polarity((data & (1 << 13)) == 0);
|
||||
|
||||
if data & (1 << 15) != 0 {
|
||||
result.set_trigger_mode(TriggerMode::Level).ok()?;
|
||||
} else {
|
||||
result.set_trigger_mode(TriggerMode::Edge).ok()?;
|
||||
}
|
||||
}
|
||||
result.set_mask((data & (1 << 16)) != 0);
|
||||
|
||||
if let LVTRegister::Timer = result.register {
|
||||
result
|
||||
.set_timer_mode(LocalApicTimerMode::try_from(((data >> 17) & 0b11) as u8).ok()?)
|
||||
.ok()?;
|
||||
}
|
||||
|
||||
return Some(result);
|
||||
}
|
||||
|
||||
/// 获取LVT寄存器的原始值
|
||||
#[allow(dead_code)]
|
||||
pub fn data(&self) -> u32 {
|
||||
return self.data;
|
||||
}
|
||||
|
||||
pub fn register(&self) -> LVTRegister {
|
||||
return self.register;
|
||||
}
|
||||
|
||||
pub fn set_vector(&mut self, vector: u8) {
|
||||
self.data &= !((1 << 8) - 1);
|
||||
self.data |= vector as u32;
|
||||
}
|
||||
|
||||
/// 获取中断向量号
|
||||
#[allow(dead_code)]
|
||||
pub fn vector(&self) -> u8 {
|
||||
return (self.data & 0xFF) as u8;
|
||||
}
|
||||
|
||||
/// 设置中断投递模式
|
||||
///
|
||||
/// Timer、ErrorReg寄存器不支持这个功能
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `mode`:投递模式
|
||||
pub fn set_delivery_mode(&mut self, mode: DeliveryMode) -> Result<(), SystemError> {
|
||||
match self.register {
|
||||
LVTRegister::Timer | LVTRegister::ErrorReg => {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.data &= 0xFFFF_F8FF;
|
||||
self.data |= ((mode as u32) & 0x7) << 8;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 获取中断投递模式
|
||||
/// Timer、ErrorReg寄存器不支持这个功能
|
||||
#[allow(dead_code)]
|
||||
pub fn delivery_mode(&self) -> Option<DeliveryMode> {
|
||||
if let LVTRegister::Timer | LVTRegister::ErrorReg = self.register {
|
||||
return None;
|
||||
}
|
||||
return DeliveryMode::try_from(((self.data >> 8) & 0b111) as u8).ok();
|
||||
}
|
||||
|
||||
/// Get the delivery status of the interrupt
|
||||
#[allow(dead_code)]
|
||||
pub fn delivery_status(&self) -> DeliveryStatus {
|
||||
return DeliveryStatus::from(self.data);
|
||||
}
|
||||
|
||||
/// 设置中断输入引脚的极性
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `high`:true表示高电平有效,false表示低电平有效
|
||||
pub fn set_interrupt_input_pin_polarity(&mut self, high: bool) {
|
||||
self.data &= 0xFFFF_DFFF;
|
||||
// 0表示高电平有效,1表示低电平有效
|
||||
if !high {
|
||||
self.data |= 1 << 13;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取中断输入引脚的极性
|
||||
///
|
||||
/// true表示高电平有效,false表示低电平有效
|
||||
#[allow(dead_code)]
|
||||
pub fn interrupt_input_pin_polarity(&self) -> bool {
|
||||
return (self.data & (1 << 13)) == 0;
|
||||
}
|
||||
|
||||
/// 设置中断输入引脚的触发模式
|
||||
///
|
||||
/// 只有LINT0和LINT1寄存器支持这个功能
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `trigger_mode`:触发模式
|
||||
pub fn set_trigger_mode(&mut self, trigger_mode: TriggerMode) -> Result<(), SystemError> {
|
||||
match self.register {
|
||||
LVTRegister::LINT0 | LVTRegister::LINT1 => {
|
||||
self.data &= 0xFFFF_7FFF;
|
||||
if trigger_mode == TriggerMode::Level {
|
||||
self.data |= 1 << 15;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取中断输入引脚的触发模式
|
||||
///
|
||||
/// 只有LINT0和LINT1寄存器支持这个功能
|
||||
#[allow(dead_code)]
|
||||
pub fn trigger_mode(&self) -> Option<TriggerMode> {
|
||||
match self.register {
|
||||
LVTRegister::LINT0 | LVTRegister::LINT1 => {
|
||||
if self.data & (1 << 15) != 0 {
|
||||
return Some(TriggerMode::Level);
|
||||
} else {
|
||||
return Some(TriggerMode::Edge);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置是否屏蔽中断
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `mask`:true表示屏蔽中断,false表示不屏蔽中断
|
||||
pub fn set_mask(&mut self, mask: bool) {
|
||||
self.data &= 0xFFFE_FFFF;
|
||||
if mask {
|
||||
self.data |= 1 << 16;
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if the interrupt is masked
|
||||
///
|
||||
/// true表示屏蔽中断,false表示不屏蔽中断
|
||||
#[allow(dead_code)]
|
||||
pub fn mask(&self) -> bool {
|
||||
return (self.data & (1 << 16)) != 0;
|
||||
}
|
||||
|
||||
/// 设置定时器模式
|
||||
pub fn set_timer_mode(&mut self, mode: LocalApicTimerMode) -> Result<(), SystemError> {
|
||||
match self.register {
|
||||
LVTRegister::Timer => {
|
||||
self.data &= 0xFFF9_FFFF;
|
||||
match mode {
|
||||
LocalApicTimerMode::Oneshot => {
|
||||
self.data |= 0b00 << 17;
|
||||
}
|
||||
LocalApicTimerMode::Periodic => {
|
||||
self.data |= 0b01 << 17;
|
||||
}
|
||||
LocalApicTimerMode::Deadline => {
|
||||
self.data |= 0b10 << 17;
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取定时器模式
|
||||
#[allow(dead_code)]
|
||||
pub fn timer_mode(&self) -> Option<LocalApicTimerMode> {
|
||||
if let LVTRegister::Timer = self.register {
|
||||
let mode = (self.data >> 17) & 0b11;
|
||||
match mode {
|
||||
0b00 => {
|
||||
return Some(LocalApicTimerMode::Oneshot);
|
||||
}
|
||||
0b01 => {
|
||||
return Some(LocalApicTimerMode::Periodic);
|
||||
}
|
||||
0b10 => {
|
||||
return Some(LocalApicTimerMode::Deadline);
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum DeliveryMode {
|
||||
/// 由LVT寄存器的向量号区域指定中断向量号
|
||||
Fixed = 0b000,
|
||||
/// 通过处理器的SMI信号线,向处理器投递SMI中断请求。
|
||||
/// 由于兼容性的原因,使用此投递模式时,LVT的中断向量号区域必须设置为0。
|
||||
SMI = 0b010,
|
||||
/// 向处理器投递不可屏蔽中断,并忽略向量号区域
|
||||
NMI = 0b100,
|
||||
/// 向处理器投递INIT中断请求,处理器会执行初始化的过程。
|
||||
/// 由于兼容性的原因,使用此投递模式时,LVT的中断向量号区域必须设置为0。
|
||||
/// CMCI、温度传感器、性能监控计数器等寄存器均不支持INIT投递模式
|
||||
INIT = 0b101,
|
||||
|
||||
/// 向目标处理器投递Start-Up IPI。
|
||||
///
|
||||
/// 这个向量通常由多核引导模块调用(请参阅Intel开发手册Volume3 Section 8.4,
|
||||
/// Multiple-Processor (MP) Initialization)。
|
||||
/// 如果源APIC无法投递这个IPI,它不会自动重发。如果Start-Up IPI未成功投递,
|
||||
/// 则交由软件决定是否在必要时重新投递SIPI
|
||||
StartUp = 0b110,
|
||||
|
||||
/// ExtINT模式可以将类8259A中断控制器产生的中断请求投递到处理器,并接收类
|
||||
/// 8259A中断控制器提供的中断向量号。
|
||||
/// CMCI、温度传感器、性能监控计数器等寄存器均不支持ExtINT投递模式
|
||||
ExtINT = 0b111,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for DeliveryMode {
|
||||
type Error = SystemError;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
0b000 => {
|
||||
return Ok(DeliveryMode::Fixed);
|
||||
}
|
||||
0b010 => {
|
||||
return Ok(DeliveryMode::SMI);
|
||||
}
|
||||
0b100 => {
|
||||
return Ok(DeliveryMode::NMI);
|
||||
}
|
||||
0b101 => {
|
||||
return Ok(DeliveryMode::INIT);
|
||||
}
|
||||
0b110 => {
|
||||
return Ok(DeliveryMode::StartUp);
|
||||
}
|
||||
0b111 => {
|
||||
return Ok(DeliveryMode::ExtINT);
|
||||
}
|
||||
_ => {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 投递状态
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum DeliveryStatus {
|
||||
/// 空闲态。
|
||||
/// 此状态表明,当前中断源未产生中断,或者产生的中断已经投递到处理器,并被处理器处理。
|
||||
Idle = 0,
|
||||
/// 发送挂起状态。
|
||||
/// 此状态表明,中断源产生的请求已经投递至处理器,但尚未被处理器处理。
|
||||
SendPending = 1,
|
||||
}
|
||||
|
||||
impl DeliveryStatus {
|
||||
pub fn from(data: u32) -> Self {
|
||||
if data & (1 << 12) == 0 {
|
||||
return DeliveryStatus::Idle;
|
||||
} else {
|
||||
return DeliveryStatus::SendPending;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// IPI Trigger Mode
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
#[repr(u64)]
|
||||
pub enum TriggerMode {
|
||||
Edge = 0,
|
||||
Level = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CurrentApic;
|
||||
|
||||
impl CurrentApic {
|
||||
/// x2apic是否启用
|
||||
pub fn x2apic_enabled(&self) -> bool {
|
||||
return LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic;
|
||||
}
|
||||
|
||||
pub(self) unsafe fn write_xapic_register(&self, reg: XApicOffset, value: u32) {
|
||||
current_xapic_instance().borrow_mut().as_mut().map(|xapic| {
|
||||
xapic.write(reg, value);
|
||||
});
|
||||
}
|
||||
|
||||
/// 屏蔽类8259A芯片
|
||||
unsafe fn mask8259a(&self) {
|
||||
CurrentPortIOArch::out8(0x21, 0xff);
|
||||
CurrentPortIOArch::out8(0xa1, 0xff);
|
||||
|
||||
// 写入8259A pic的EOI位
|
||||
CurrentPortIOArch::out8(0x20, 0x20);
|
||||
CurrentPortIOArch::out8(0xa0, 0x20);
|
||||
|
||||
kdebug!("8259A Masked.");
|
||||
|
||||
// enable IMCR
|
||||
CurrentPortIOArch::out8(0x22, 0x70);
|
||||
CurrentPortIOArch::out8(0x23, 0x01);
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalAPIC for CurrentApic {
|
||||
fn support() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn init_current_cpu(&mut self) -> bool {
|
||||
let cpu_id = smp_get_processor_id();
|
||||
if cpu_id == 0 {
|
||||
unsafe {
|
||||
self.mask8259a();
|
||||
}
|
||||
}
|
||||
kinfo!("Initializing apic for cpu {}", cpu_id);
|
||||
if X2Apic::support() && X2Apic.init_current_cpu() {
|
||||
if cpu_id == 0 {
|
||||
LOCAL_APIC_ENABLE_TYPE.store(LocalApicEnableType::X2Apic, Ordering::SeqCst);
|
||||
}
|
||||
kinfo!("x2APIC initialized for cpu {}", cpu_id);
|
||||
} else {
|
||||
kinfo!("x2APIC not supported or failed to initialize, fallback to xAPIC.");
|
||||
if cpu_id == 0 {
|
||||
LOCAL_APIC_ENABLE_TYPE.store(LocalApicEnableType::XApic, Ordering::SeqCst);
|
||||
}
|
||||
let apic_base =
|
||||
PhysAddr::new(unsafe { x86::msr::rdmsr(IA32_APIC_BASE) as usize & 0xFFFF_0000 });
|
||||
let xapic_instance = unsafe { XApic::new(apic_base) };
|
||||
|
||||
let mut cur = current_xapic_instance().borrow_mut();
|
||||
if cur.is_none() {
|
||||
*cur = Some(xapic_instance);
|
||||
} else {
|
||||
panic!("xapic instance already initialized.");
|
||||
}
|
||||
|
||||
if let Some(xapic) = cur.as_mut() {
|
||||
xapic.init_current_cpu();
|
||||
}
|
||||
|
||||
kinfo!("xAPIC initialized for cpu {}", cpu_id);
|
||||
}
|
||||
if cpu_id == 0 {
|
||||
ioapic_init();
|
||||
}
|
||||
kinfo!("Apic initialized.");
|
||||
return true;
|
||||
}
|
||||
|
||||
fn send_eoi(&self) {
|
||||
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
|
||||
X2Apic.send_eoi();
|
||||
} else {
|
||||
current_xapic_instance().borrow().as_ref().map(|xapic| {
|
||||
xapic.send_eoi();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn version(&self) -> u8 {
|
||||
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
|
||||
return X2Apic.version();
|
||||
} else {
|
||||
return current_xapic_instance()
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.map(|xapic| xapic.version())
|
||||
.unwrap_or(0);
|
||||
}
|
||||
}
|
||||
|
||||
fn support_eoi_broadcast_suppression(&self) -> bool {
|
||||
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
|
||||
return X2Apic.support_eoi_broadcast_suppression();
|
||||
} else {
|
||||
return current_xapic_instance()
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.map(|xapic| xapic.support_eoi_broadcast_suppression())
|
||||
.unwrap_or(false);
|
||||
}
|
||||
}
|
||||
|
||||
fn max_lvt_entry(&self) -> u8 {
|
||||
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
|
||||
return X2Apic.max_lvt_entry();
|
||||
} else {
|
||||
return current_xapic_instance()
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.map(|xapic| xapic.max_lvt_entry())
|
||||
.unwrap_or(0);
|
||||
}
|
||||
}
|
||||
|
||||
fn id(&self) -> u32 {
|
||||
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
|
||||
return X2Apic.id();
|
||||
} else {
|
||||
return current_xapic_instance()
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.map(|xapic| xapic.id())
|
||||
.unwrap_or(0);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_lvt(&mut self, lvt: LVT) {
|
||||
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
|
||||
X2Apic.set_lvt(lvt);
|
||||
} else {
|
||||
current_xapic_instance().borrow_mut().as_mut().map(|xapic| {
|
||||
xapic.set_lvt(lvt);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn read_lvt(&self, reg: LVTRegister) -> LVT {
|
||||
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
|
||||
return X2Apic.read_lvt(reg);
|
||||
} else {
|
||||
return current_xapic_instance()
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.map(|xapic| xapic.read_lvt(reg))
|
||||
.expect("xapic instance not initialized.");
|
||||
}
|
||||
}
|
||||
|
||||
fn mask_all_lvt(&mut self) {
|
||||
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
|
||||
X2Apic.mask_all_lvt();
|
||||
} else {
|
||||
current_xapic_instance().borrow_mut().as_mut().map(|xapic| {
|
||||
xapic.mask_all_lvt();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn write_icr(&self, icr: Icr) {
|
||||
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
|
||||
X2Apic.write_icr(icr);
|
||||
} else {
|
||||
current_xapic_instance().borrow().as_ref().map(|xapic| {
|
||||
xapic.write_icr(icr);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
125
kernel/src/arch/x86_64/driver/apic/x2apic.rs
Normal file
125
kernel/src/arch/x86_64/driver/apic/x2apic.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use x86::msr::{
|
||||
rdmsr, wrmsr, IA32_APIC_BASE, IA32_X2APIC_APICID, IA32_X2APIC_EOI, IA32_X2APIC_SIVR,
|
||||
IA32_X2APIC_VERSION,
|
||||
};
|
||||
|
||||
use crate::{kdebug, kinfo};
|
||||
|
||||
use super::{LVTRegister, LocalAPIC, LVT};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct X2Apic;
|
||||
|
||||
impl LocalAPIC for X2Apic {
|
||||
/// @brief 判断处理器是否支持x2APIC
|
||||
fn support() -> bool {
|
||||
return x86::cpuid::CpuId::new()
|
||||
.get_feature_info()
|
||||
.expect("Get cpu feature info failed.")
|
||||
.has_x2apic();
|
||||
}
|
||||
/// @return true -> the function works
|
||||
fn init_current_cpu(&mut self) -> bool {
|
||||
unsafe {
|
||||
// 设置 x2APIC 使能位
|
||||
wrmsr(
|
||||
IA32_APIC_BASE.into(),
|
||||
rdmsr(IA32_APIC_BASE.into()) | 1 << 10,
|
||||
);
|
||||
|
||||
assert!(
|
||||
(rdmsr(IA32_APIC_BASE.into()) & 0xc00) == 0xc00,
|
||||
"x2APIC enable failed."
|
||||
);
|
||||
|
||||
// 设置Spurious-Interrupt Vector Register
|
||||
{
|
||||
let val = if self.support_eoi_broadcast_suppression() {
|
||||
(1 << 12) | (1 << 8)
|
||||
} else {
|
||||
1 << 8
|
||||
};
|
||||
|
||||
wrmsr(IA32_X2APIC_SIVR.into(), val);
|
||||
|
||||
assert!(
|
||||
(rdmsr(IA32_X2APIC_SIVR.into()) & 0x100) == 0x100,
|
||||
"x2APIC software enable failed."
|
||||
);
|
||||
kinfo!("x2APIC software enabled.");
|
||||
|
||||
if self.support_eoi_broadcast_suppression() {
|
||||
assert!(
|
||||
(rdmsr(IA32_X2APIC_SIVR.into()) & 0x1000) == 0x1000,
|
||||
"x2APIC EOI broadcast suppression enable failed."
|
||||
);
|
||||
kinfo!("x2APIC EOI broadcast suppression enabled.");
|
||||
}
|
||||
}
|
||||
kdebug!("x2apic: to mask all lvt");
|
||||
self.mask_all_lvt();
|
||||
kdebug!("x2apic: all lvt masked");
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// 发送 EOI (End Of Interrupt)
|
||||
fn send_eoi(&self) {
|
||||
unsafe {
|
||||
wrmsr(IA32_X2APIC_EOI.into(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取 x2APIC 版本
|
||||
fn version(&self) -> u8 {
|
||||
unsafe { (rdmsr(IA32_X2APIC_VERSION.into()) & 0xff) as u8 }
|
||||
}
|
||||
|
||||
fn support_eoi_broadcast_suppression(&self) -> bool {
|
||||
unsafe { ((rdmsr(IA32_X2APIC_VERSION.into()) >> 24) & 1) == 1 }
|
||||
}
|
||||
|
||||
fn max_lvt_entry(&self) -> u8 {
|
||||
unsafe { ((rdmsr(IA32_X2APIC_VERSION.into()) >> 16) & 0xff) as u8 + 1 }
|
||||
}
|
||||
|
||||
/// 获取 x2APIC 的 APIC ID
|
||||
fn id(&self) -> u32 {
|
||||
unsafe { rdmsr(IA32_X2APIC_APICID.into()) as u32 }
|
||||
}
|
||||
|
||||
/// 设置 Local Vector Table (LVT) 寄存器
|
||||
fn set_lvt(&mut self, lvt: LVT) {
|
||||
unsafe {
|
||||
wrmsr(lvt.register().into(), lvt.data as u64);
|
||||
}
|
||||
}
|
||||
|
||||
fn read_lvt(&self, reg: LVTRegister) -> LVT {
|
||||
unsafe { LVT::new(reg, (rdmsr(reg.into()) & 0xffff_ffff) as u32).unwrap() }
|
||||
}
|
||||
|
||||
fn mask_all_lvt(&mut self) {
|
||||
// self.set_lvt(LVT::new(LVTRegister::CMCI, LVT::MASKED).unwrap());
|
||||
let cpuid = raw_cpuid::CpuId::new();
|
||||
// cpuid.get_performance_monitoring_info();
|
||||
self.set_lvt(LVT::new(LVTRegister::Timer, LVT::MASKED).unwrap());
|
||||
|
||||
if cpuid.get_thermal_power_info().is_some() {
|
||||
self.set_lvt(LVT::new(LVTRegister::Thermal, LVT::MASKED).unwrap());
|
||||
}
|
||||
|
||||
if cpuid.get_performance_monitoring_info().is_some() {
|
||||
self.set_lvt(LVT::new(LVTRegister::PerformanceMonitor, LVT::MASKED).unwrap());
|
||||
}
|
||||
|
||||
self.set_lvt(LVT::new(LVTRegister::LINT0, LVT::MASKED).unwrap());
|
||||
self.set_lvt(LVT::new(LVTRegister::LINT1, LVT::MASKED).unwrap());
|
||||
|
||||
self.set_lvt(LVT::new(LVTRegister::ErrorReg, LVT::MASKED).unwrap());
|
||||
}
|
||||
|
||||
fn write_icr(&self, icr: x86::apic::Icr) {
|
||||
unsafe { wrmsr(0x830, ((icr.upper() as u64) << 32) | icr.lower() as u64) };
|
||||
}
|
||||
}
|
358
kernel/src/arch/x86_64/driver/apic/xapic.rs
Normal file
358
kernel/src/arch/x86_64/driver/apic/xapic.rs
Normal file
@ -0,0 +1,358 @@
|
||||
use core::{
|
||||
cell::RefCell,
|
||||
hint::spin_loop,
|
||||
ptr::{read_volatile, write_volatile},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
kdebug, kerror, kinfo,
|
||||
mm::{
|
||||
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
|
||||
percpu::PerCpu,
|
||||
PhysAddr, VirtAddr,
|
||||
},
|
||||
smp::core::smp_get_processor_id,
|
||||
};
|
||||
|
||||
use super::{LVTRegister, LocalAPIC, LVT};
|
||||
|
||||
/// per-cpu的xAPIC的MMIO空间起始地址
|
||||
static mut XAPIC_INSTANCES: [RefCell<Option<XApic>>; PerCpu::MAX_CPU_NUM] =
|
||||
[const { RefCell::new(None) }; PerCpu::MAX_CPU_NUM];
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) fn current_xapic_instance() -> &'static RefCell<Option<XApic>> {
|
||||
unsafe { &XAPIC_INSTANCES.as_ref()[smp_get_processor_id() as usize] }
|
||||
}
|
||||
|
||||
/// TODO:统一变量
|
||||
/// @brief local APIC 寄存器地址偏移量
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(u32)]
|
||||
pub enum XApicOffset {
|
||||
// 定义各个寄存器的地址偏移量
|
||||
LOCAL_APIC_OFFSET_Local_APIC_ID = 0x20,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_Version = 0x30,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_TPR = 0x80,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_APR = 0x90,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_PPR = 0xa0,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_EOI = 0xb0,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_RRD = 0xc0,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_LDR = 0xd0,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_DFR = 0xe0,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_SVR = 0xf0,
|
||||
|
||||
LOCAL_APIC_OFFSET_Local_APIC_ISR_31_0 = 0x100, // In-Service Register
|
||||
LOCAL_APIC_OFFSET_Local_APIC_ISR_63_32 = 0x110,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_ISR_95_64 = 0x120,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_ISR_127_96 = 0x130,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_ISR_159_128 = 0x140,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_ISR_191_160 = 0x150,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_ISR_223_192 = 0x160,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_ISR_255_224 = 0x170,
|
||||
|
||||
LOCAL_APIC_OFFSET_Local_APIC_TMR_31_0 = 0x180, // Trigger Mode Register
|
||||
LOCAL_APIC_OFFSET_Local_APIC_TMR_63_32 = 0x190,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_TMR_95_64 = 0x1a0,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_TMR_127_96 = 0x1b0,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_TMR_159_128 = 0x1c0,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_TMR_191_160 = 0x1d0,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_TMR_223_192 = 0x1e0,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_TMR_255_224 = 0x1f0,
|
||||
|
||||
LOCAL_APIC_OFFSET_Local_APIC_IRR_31_0 = 0x200, // Interrupt Request Register
|
||||
LOCAL_APIC_OFFSET_Local_APIC_IRR_63_32 = 0x210,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_IRR_95_64 = 0x220,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_IRR_127_96 = 0x230,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_IRR_159_128 = 0x240,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_IRR_191_160 = 0x250,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_IRR_223_192 = 0x260,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_IRR_255_224 = 0x270,
|
||||
|
||||
LOCAL_APIC_OFFSET_Local_APIC_ESR = 0x280, // Error Status Register
|
||||
|
||||
LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI = 0x2f0, // Corrected Machine Check Interrupt Register
|
||||
|
||||
LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0 = 0x300, // Interrupt Command Register
|
||||
LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32 = 0x310,
|
||||
|
||||
LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER = 0x320,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL = 0x330,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR = 0x340,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0 = 0x350,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1 = 0x360,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR = 0x370,
|
||||
// 初始计数寄存器(定时器专用)
|
||||
LOCAL_APIC_OFFSET_Local_APIC_INITIAL_COUNT_REG = 0x380,
|
||||
// 当前计数寄存器(定时器专用)
|
||||
LOCAL_APIC_OFFSET_Local_APIC_CURRENT_COUNT_REG = 0x390,
|
||||
LOCAL_APIC_OFFSET_Local_APIC_CLKDIV = 0x3e0,
|
||||
}
|
||||
|
||||
impl Into<u32> for XApicOffset {
|
||||
fn into(self) -> u32 {
|
||||
self as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl From<LVTRegister> for XApicOffset {
|
||||
fn from(lvt: LVTRegister) -> Self {
|
||||
match lvt {
|
||||
LVTRegister::Timer => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER,
|
||||
LVTRegister::Thermal => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_THERMAL,
|
||||
LVTRegister::PerformanceMonitor => {
|
||||
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_PERFORMANCE_MONITOR
|
||||
}
|
||||
LVTRegister::LINT0 => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT0,
|
||||
LVTRegister::LINT1 => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_LINT1,
|
||||
LVTRegister::ErrorReg => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_ERROR,
|
||||
LVTRegister::CMCI => XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_CMCI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct XApic {
|
||||
/// 当前xAPIC的寄存器映射的虚拟地址。注意,每个CPU都有自己的xAPIC,所以这个地址是每个CPU都不一样的。
|
||||
apic_vaddr: VirtAddr,
|
||||
/// `apic_vaddr`与映射的空间起始位置之间的偏移量
|
||||
offset: usize,
|
||||
map_guard: MMIOSpaceGuard,
|
||||
xapic_base: PhysAddr,
|
||||
}
|
||||
|
||||
impl XApic {
|
||||
/// 读取指定寄存器的值
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn read(&self, reg: XApicOffset) -> u32 {
|
||||
read_volatile((self.apic_vaddr.data() + reg as usize) as *const u32)
|
||||
}
|
||||
|
||||
/// 将指定的值写入寄存器
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn write(&self, reg: XApicOffset, value: u32) {
|
||||
write_volatile(
|
||||
(self.apic_vaddr.data() + (reg as u32) as usize) as *mut u32,
|
||||
value,
|
||||
);
|
||||
self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ID); // 等待写操作完成,通过读取进行同步
|
||||
}
|
||||
}
|
||||
|
||||
impl XApic {
|
||||
/// 创建新的XAPIC实例
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `xapic_base` - 当前核心的xAPIC的寄存器的物理地址
|
||||
pub unsafe fn new(xapic_base: PhysAddr) -> Self {
|
||||
let offset = xapic_base.data() & 0xffff;
|
||||
let paddr = PhysAddr::new(xapic_base.data() & !0xffff);
|
||||
let g = mmio_pool()
|
||||
.create_mmio(4096)
|
||||
.expect("Fail to create MMIO for XAPIC");
|
||||
g.map_phys(paddr, 4096).expect("Fail to map MMIO for XAPIC");
|
||||
let addr = g.vaddr() + offset;
|
||||
|
||||
kdebug!(
|
||||
"XAPIC: {:#x} -> {:#x}, offset={offset}",
|
||||
xapic_base.data(),
|
||||
addr.data()
|
||||
);
|
||||
|
||||
let r = Self {
|
||||
apic_vaddr: addr,
|
||||
offset,
|
||||
map_guard: g,
|
||||
xapic_base,
|
||||
};
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
const X1: u32 = 0x0000000B; // 将除数设置为1,即不除频率
|
||||
#[allow(dead_code)]
|
||||
const PERIODIC: u32 = 0x00020000; // 周期性模式
|
||||
#[allow(dead_code)]
|
||||
const ENABLE: u32 = 0x00000100; // 单元使能
|
||||
#[allow(dead_code)]
|
||||
const MASKED: u32 = 0x00010000; // 中断屏蔽
|
||||
const LEVEL: u32 = 0x00008000; // 电平触发
|
||||
const BCAST: u32 = 0x00080000; // 发送到所有APIC,包括自己
|
||||
const DELIVS: u32 = 0x00001000; // 传递状态
|
||||
const INIT: u32 = 0x00000500; // INIT/RESET
|
||||
|
||||
//中断请求
|
||||
#[allow(dead_code)]
|
||||
const T_IRQ0: u32 = 32; // IRQ 0 对应于 T_IRQ 中断
|
||||
#[allow(dead_code)]
|
||||
const IRQ_TIMER: u32 = 0;
|
||||
#[allow(dead_code)]
|
||||
const IRQ_KBD: u32 = 1;
|
||||
#[allow(dead_code)]
|
||||
const IRQ_COM1: u32 = 4;
|
||||
#[allow(dead_code)]
|
||||
const IRQ_IDE: u32 = 14;
|
||||
#[allow(dead_code)]
|
||||
const IRQ_ERROR: u32 = 19;
|
||||
#[allow(dead_code)]
|
||||
const IRQ_SPURIOUS: u32 = 31;
|
||||
|
||||
impl LocalAPIC for XApic {
|
||||
/// @brief 判断处理器是否支持apic
|
||||
fn support() -> bool {
|
||||
return x86::cpuid::CpuId::new()
|
||||
.get_feature_info()
|
||||
.expect("Fail to get CPU feature.")
|
||||
.has_apic();
|
||||
}
|
||||
|
||||
/// @return true -> 函数运行成功
|
||||
fn init_current_cpu(&mut self) -> bool {
|
||||
unsafe {
|
||||
// enable xapic
|
||||
x86::msr::wrmsr(x86::msr::APIC_BASE, (self.xapic_base.data() | 0x800) as u64);
|
||||
let val = x86::msr::rdmsr(x86::msr::APIC_BASE);
|
||||
if val & 0x800 != 0x800 {
|
||||
kerror!("xAPIC enable failed: APIC_BASE & 0x800 != 0x800");
|
||||
return false;
|
||||
}
|
||||
// 设置 Spurious Interrupt Vector Register
|
||||
let val = self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR.into());
|
||||
|
||||
self.write(
|
||||
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR.into(),
|
||||
val | ENABLE,
|
||||
);
|
||||
|
||||
let val = self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_SVR.into());
|
||||
if val & ENABLE == 0 {
|
||||
kerror!("xAPIC software enable failed.");
|
||||
|
||||
return false;
|
||||
} else {
|
||||
kinfo!("xAPIC software enabled.");
|
||||
}
|
||||
|
||||
if val & 0x1000 != 0 {
|
||||
kinfo!("xAPIC EOI broadcast suppression enabled.");
|
||||
}
|
||||
|
||||
self.mask_all_lvt();
|
||||
|
||||
// 清除错误状态寄存器(需要连续写入两次)
|
||||
self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ESR.into(), 0);
|
||||
self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ESR.into(), 0);
|
||||
|
||||
// 确认任何未完成的中断
|
||||
self.write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_EOI.into(), 0);
|
||||
|
||||
// 发送 Init Level De-Assert 信号以同步仲裁ID
|
||||
self.write(
|
||||
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32.into(),
|
||||
0,
|
||||
);
|
||||
self.write(
|
||||
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into(),
|
||||
BCAST | INIT | LEVEL,
|
||||
);
|
||||
while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into()) & DELIVS != 0
|
||||
{
|
||||
spin_loop();
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// 发送 EOI(End Of Interrupt)
|
||||
fn send_eoi(&self) {
|
||||
unsafe {
|
||||
let s = self as *const Self as *mut Self;
|
||||
(*s).write(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_EOI.into(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取版本号
|
||||
fn version(&self) -> u8 {
|
||||
unsafe {
|
||||
(self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version.into()) & 0xff) as u8
|
||||
}
|
||||
}
|
||||
|
||||
fn support_eoi_broadcast_suppression(&self) -> bool {
|
||||
unsafe {
|
||||
((self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version.into()) >> 24) & 1) == 1
|
||||
}
|
||||
}
|
||||
|
||||
fn max_lvt_entry(&self) -> u8 {
|
||||
unsafe {
|
||||
((self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_Version.into()) >> 16) & 0xff)
|
||||
as u8
|
||||
+ 1
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取ID
|
||||
fn id(&self) -> u32 {
|
||||
unsafe { self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ID.into()) >> 24 }
|
||||
}
|
||||
|
||||
/// 设置LVT寄存器的值
|
||||
fn set_lvt(&mut self, lvt: LVT) {
|
||||
unsafe {
|
||||
self.write(lvt.register().into(), lvt.data);
|
||||
}
|
||||
}
|
||||
|
||||
fn read_lvt(&self, reg: LVTRegister) -> LVT {
|
||||
unsafe {
|
||||
LVT::new(
|
||||
reg,
|
||||
self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_LVT_TIMER.into()),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn mask_all_lvt(&mut self) {
|
||||
// self.set_lvt(LVT::new(LVTRegister::CMCI, LVT::MASKED).unwrap());
|
||||
self.set_lvt(LVT::new(LVTRegister::Timer, LVT::MASKED).unwrap());
|
||||
self.set_lvt(LVT::new(LVTRegister::Thermal, LVT::MASKED).unwrap());
|
||||
self.set_lvt(LVT::new(LVTRegister::PerformanceMonitor, LVT::MASKED).unwrap());
|
||||
self.set_lvt(LVT::new(LVTRegister::LINT0, LVT::MASKED).unwrap());
|
||||
self.set_lvt(LVT::new(LVTRegister::LINT1, LVT::MASKED).unwrap());
|
||||
self.set_lvt(LVT::new(LVTRegister::ErrorReg, LVT::MASKED).unwrap());
|
||||
}
|
||||
|
||||
fn write_icr(&self, icr: x86::apic::Icr) {
|
||||
unsafe {
|
||||
// Wait for any previous send to finish
|
||||
while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into()) & DELIVS != 0
|
||||
{
|
||||
spin_loop();
|
||||
}
|
||||
|
||||
self.write(
|
||||
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_63_32.into(),
|
||||
icr.upper(),
|
||||
);
|
||||
self.write(
|
||||
XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into(),
|
||||
icr.lower(),
|
||||
);
|
||||
|
||||
// Wait for send to finish
|
||||
while self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ICR_31_0.into()) & DELIVS != 0
|
||||
{
|
||||
spin_loop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#include <common/glib.h>
|
||||
#include <common/kprint.h>
|
||||
#include <driver/interrupt/apic/apic.h>
|
||||
#include <arch/x86_64/driver/apic/apic.h>
|
||||
|
||||
extern void rs_handle_hpet_irq(uint32_t timer_num);
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod apic;
|
||||
mod c_adapter;
|
||||
pub mod hpet;
|
||||
pub mod tsc;
|
||||
|
15
kernel/src/arch/x86_64/interrupt/c_adapter.rs
Normal file
15
kernel/src/arch/x86_64/interrupt/c_adapter.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use super::ipi::{ipi_send_smp_init, ipi_send_smp_startup};
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_ipi_send_smp_init() -> i32 {
|
||||
return ipi_send_smp_init()
|
||||
.map(|_| 0)
|
||||
.unwrap_or_else(|e| e.to_posix_errno());
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_ipi_send_smp_startup(target_cpu: u32) -> i32 {
|
||||
return ipi_send_smp_startup(target_cpu)
|
||||
.map(|_| 0)
|
||||
.unwrap_or_else(|e| e.to_posix_errno());
|
||||
}
|
@ -1,9 +1,13 @@
|
||||
use crate::exception::ipi::{IpiKind, IpiTarget};
|
||||
use x86::apic::ApicId;
|
||||
|
||||
extern "C" {
|
||||
pub fn apic_write_icr(value: u64);
|
||||
pub fn apic_x2apic_enabled() -> bool;
|
||||
}
|
||||
use crate::{
|
||||
arch::{
|
||||
driver::apic::{CurrentApic, LocalAPIC},
|
||||
smp::SMP_BOOT_DATA,
|
||||
},
|
||||
exception::ipi::{IpiKind, IpiTarget},
|
||||
syscall::SystemError,
|
||||
};
|
||||
|
||||
/// IPI的种类(架构相关,指定了向量号)
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
@ -32,7 +36,7 @@ pub enum ArchIpiTarget {
|
||||
/// 除了当前CPU以外的所有CPU
|
||||
Other,
|
||||
/// 指定的CPU
|
||||
Specified(usize),
|
||||
Specified(x86::apic::ApicId),
|
||||
}
|
||||
|
||||
impl From<IpiTarget> for ArchIpiTarget {
|
||||
@ -41,7 +45,23 @@ impl From<IpiTarget> for ArchIpiTarget {
|
||||
IpiTarget::Current => ArchIpiTarget::Current,
|
||||
IpiTarget::All => ArchIpiTarget::All,
|
||||
IpiTarget::Other => ArchIpiTarget::Other,
|
||||
IpiTarget::Specified(cpu_id) => ArchIpiTarget::Specified(cpu_id),
|
||||
IpiTarget::Specified(cpu_id) => {
|
||||
ArchIpiTarget::Specified(Self::cpu_id_to_apic_id(cpu_id as u32))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<ApicId> for ArchIpiTarget {
|
||||
fn into(self) -> ApicId {
|
||||
if let ArchIpiTarget::Specified(id) = self {
|
||||
return id;
|
||||
} else {
|
||||
if CurrentApic.x2apic_enabled() {
|
||||
return x86::apic::ApicId::X2Apic(0);
|
||||
} else {
|
||||
return x86::apic::ApicId::XApic(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -55,6 +75,15 @@ impl ArchIpiTarget {
|
||||
ArchIpiTarget::Other => 3,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn cpu_id_to_apic_id(cpu_id: u32) -> x86::apic::ApicId {
|
||||
if CurrentApic.x2apic_enabled() {
|
||||
x86::apic::ApicId::X2Apic(cpu_id as u32)
|
||||
} else {
|
||||
x86::apic::ApicId::XApic(cpu_id as u8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget {
|
||||
@ -68,21 +97,6 @@ impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget {
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<x86::apic::ApicId> for ArchIpiTarget {
|
||||
fn into(self) -> x86::apic::ApicId {
|
||||
let id = match self {
|
||||
ArchIpiTarget::Specified(cpu_id) => cpu_id,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
if unsafe { apic_x2apic_enabled() } {
|
||||
return x86::apic::ApicId::X2Apic(id as u32);
|
||||
} else {
|
||||
return x86::apic::ApicId::XApic(id as u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
|
||||
// kdebug!("send_ipi: {:?} {:?}", kind, target);
|
||||
@ -91,9 +105,9 @@ pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
|
||||
let target = ArchIpiTarget::from(target);
|
||||
let shorthand: x86::apic::DestinationShorthand = target.into();
|
||||
let destination: x86::apic::ApicId = target.into();
|
||||
if unsafe { apic_x2apic_enabled() } {
|
||||
let icr = if CurrentApic.x2apic_enabled() {
|
||||
// kdebug!("send_ipi: x2apic");
|
||||
let icr = x86::apic::Icr::for_x2apic(
|
||||
x86::apic::Icr::for_x2apic(
|
||||
ipi_vec,
|
||||
destination,
|
||||
shorthand,
|
||||
@ -102,14 +116,10 @@ pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
|
||||
x86::apic::DeliveryStatus::Idle,
|
||||
x86::apic::Level::Assert,
|
||||
x86::apic::TriggerMode::Edge,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
apic_write_icr(((icr.upper() as u64) << 32) | icr.lower() as u64);
|
||||
}
|
||||
)
|
||||
} else {
|
||||
// kdebug!("send_ipi: xapic");
|
||||
let icr = x86::apic::Icr::for_xapic(
|
||||
x86::apic::Icr::for_xapic(
|
||||
ipi_vec,
|
||||
destination,
|
||||
shorthand,
|
||||
@ -118,10 +128,77 @@ pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
|
||||
x86::apic::DeliveryStatus::Idle,
|
||||
x86::apic::Level::Assert,
|
||||
x86::apic::TriggerMode::Edge,
|
||||
);
|
||||
)
|
||||
};
|
||||
|
||||
unsafe {
|
||||
apic_write_icr(((icr.upper() as u64) << 32) | icr.lower() as u64);
|
||||
}
|
||||
}
|
||||
CurrentApic.write_icr(icr);
|
||||
}
|
||||
|
||||
/// 发送smp初始化IPI
|
||||
pub fn ipi_send_smp_init() -> Result<(), SystemError> {
|
||||
let target = ArchIpiTarget::Other;
|
||||
let icr = if CurrentApic.x2apic_enabled() {
|
||||
x86::apic::Icr::for_x2apic(
|
||||
0,
|
||||
target.into(),
|
||||
x86::apic::DestinationShorthand::AllExcludingSelf,
|
||||
x86::apic::DeliveryMode::Init,
|
||||
x86::apic::DestinationMode::Physical,
|
||||
x86::apic::DeliveryStatus::Idle,
|
||||
x86::apic::Level::Deassert,
|
||||
x86::apic::TriggerMode::Edge,
|
||||
)
|
||||
} else {
|
||||
x86::apic::Icr::for_xapic(
|
||||
0,
|
||||
target.into(),
|
||||
x86::apic::DestinationShorthand::AllExcludingSelf,
|
||||
x86::apic::DeliveryMode::Init,
|
||||
x86::apic::DestinationMode::Physical,
|
||||
x86::apic::DeliveryStatus::Idle,
|
||||
x86::apic::Level::Deassert,
|
||||
x86::apic::TriggerMode::Edge,
|
||||
)
|
||||
};
|
||||
CurrentApic.write_icr(icr);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 发送smp启动IPI
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// * `target_cpu` - 目标CPU
|
||||
pub fn ipi_send_smp_startup(target_cpu: u32) -> Result<(), SystemError> {
|
||||
if target_cpu as usize >= SMP_BOOT_DATA.cpu_count() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
let target: ArchIpiTarget = IpiTarget::Specified(target_cpu as usize).into();
|
||||
|
||||
let icr = if CurrentApic.x2apic_enabled() {
|
||||
x86::apic::Icr::for_x2apic(
|
||||
0x20,
|
||||
target.into(),
|
||||
x86::apic::DestinationShorthand::NoShorthand,
|
||||
x86::apic::DeliveryMode::StartUp,
|
||||
x86::apic::DestinationMode::Physical,
|
||||
x86::apic::DeliveryStatus::Idle,
|
||||
x86::apic::Level::Deassert,
|
||||
x86::apic::TriggerMode::Edge,
|
||||
)
|
||||
} else {
|
||||
x86::apic::Icr::for_xapic(
|
||||
0x20,
|
||||
target.into(),
|
||||
x86::apic::DestinationShorthand::NoShorthand,
|
||||
x86::apic::DeliveryMode::StartUp,
|
||||
x86::apic::DestinationMode::Physical,
|
||||
x86::apic::DeliveryStatus::Idle,
|
||||
x86::apic::Level::Deassert,
|
||||
x86::apic::TriggerMode::Edge,
|
||||
)
|
||||
};
|
||||
|
||||
CurrentApic.write_icr(icr);
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
mod c_adapter;
|
||||
pub mod ipi;
|
||||
|
||||
use core::{
|
||||
|
@ -1,4 +1,4 @@
|
||||
use core::{ffi::c_void, mem::size_of};
|
||||
use core::{ffi::c_void, intrinsics::unlikely, mem::size_of};
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
@ -322,7 +322,7 @@ impl SigContext {
|
||||
//TODO 引入线程后补上
|
||||
// let current_thread = ProcessManager::current_pcb().thread;
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let mut archinfo_guard = pcb.arch_info();
|
||||
let mut archinfo_guard = pcb.arch_info_irqsave();
|
||||
self.oldmask = *mask;
|
||||
self.frame = frame.clone();
|
||||
// context.trap_num = unsafe { (*current_thread).trap_num };
|
||||
@ -368,6 +368,7 @@ pub struct SigStack {
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn do_signal(frame: &mut TrapFrame) {
|
||||
X86_64SignalArch::do_signal(frame);
|
||||
return;
|
||||
}
|
||||
|
||||
pub struct X86_64SignalArch;
|
||||
@ -377,35 +378,46 @@ impl SignalArch for X86_64SignalArch {
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let siginfo = pcb.try_siginfo(5);
|
||||
|
||||
// 检查sigpending是否为0
|
||||
if siginfo
|
||||
.map(|s| s.sig_pending().signal().bits() == 0)
|
||||
.unwrap_or(true)
|
||||
|| !frame.from_user()
|
||||
{
|
||||
// 若没有正在等待处理的信号,或者将要返回到的是内核态,则启用中断,然后返回
|
||||
CurrentIrqArch::interrupt_enable();
|
||||
if unlikely(siginfo.is_none()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let siginfo_read_guard = siginfo.unwrap();
|
||||
|
||||
// 检查sigpending是否为0
|
||||
if siginfo_read_guard.sig_pending().signal().bits() == 0 || !frame.from_user() {
|
||||
// 若没有正在等待处理的信号,或者将要返回到的是内核态,则返回
|
||||
return;
|
||||
}
|
||||
|
||||
// 做完上面的检查后,开中断
|
||||
CurrentIrqArch::interrupt_enable();
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let sig_guard = pcb.sig_struct();
|
||||
|
||||
let mut sig_number: Signal;
|
||||
let mut info: Option<SigInfo>;
|
||||
let mut sigaction: Sigaction;
|
||||
let reader = pcb.sig_info();
|
||||
let sig_block: SigSet = reader.sig_block().clone();
|
||||
drop(reader);
|
||||
let sig_block: SigSet = siginfo_read_guard.sig_block().clone();
|
||||
drop(siginfo_read_guard);
|
||||
|
||||
let sig_guard = pcb.try_sig_struct_irq(5);
|
||||
if unlikely(sig_guard.is_none()) {
|
||||
return;
|
||||
}
|
||||
let siginfo_mut = pcb.try_siginfo_mut(5);
|
||||
if unlikely(siginfo_mut.is_none()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let sig_guard = sig_guard.unwrap();
|
||||
let mut siginfo_mut_guard = siginfo_mut.unwrap();
|
||||
loop {
|
||||
(sig_number, info) = pcb.sig_info_mut().dequeue_signal(&sig_block);
|
||||
(sig_number, info) = siginfo_mut_guard.dequeue_signal(&sig_block);
|
||||
// 如果信号非法,则直接返回
|
||||
if sig_number == Signal::INVALID {
|
||||
return;
|
||||
}
|
||||
|
||||
sigaction = sig_guard.handlers[sig_number as usize - 1];
|
||||
|
||||
match sigaction.action() {
|
||||
SigactionType::SaHandler(action_type) => match action_type {
|
||||
SaHandlerType::SigError => {
|
||||
@ -425,12 +437,14 @@ impl SignalArch for X86_64SignalArch {
|
||||
}
|
||||
// 如果当前动作是忽略这个信号,就继续循环。
|
||||
}
|
||||
// 所有的信号都处理完了
|
||||
let reader = pcb.sig_info();
|
||||
let oldset = reader.sig_block().clone();
|
||||
|
||||
let oldset = siginfo_mut_guard.sig_block().clone();
|
||||
//避免死锁
|
||||
drop(reader);
|
||||
drop(siginfo_mut_guard);
|
||||
drop(sig_guard);
|
||||
|
||||
// 做完上面的检查后,开中断
|
||||
CurrentIrqArch::interrupt_enable();
|
||||
let res: Result<i32, SystemError> =
|
||||
handle_signal(sig_number, &mut sigaction, &info.unwrap(), &oldset, frame);
|
||||
if res.is_err() {
|
||||
@ -564,7 +578,8 @@ fn setup_frame(
|
||||
let frame: *mut SigFrame = get_stack(&trap_frame, size_of::<SigFrame>());
|
||||
// kdebug!("frame=0x{:016x}", frame as usize);
|
||||
// 要求这个frame的地址位于用户空间,因此进行校验
|
||||
let r = UserBufferWriter::new(frame, size_of::<SigFrame>(), true);
|
||||
let r: Result<UserBufferWriter<'_>, SystemError> =
|
||||
UserBufferWriter::new(frame, size_of::<SigFrame>(), true);
|
||||
if r.is_err() {
|
||||
// 如果地址区域位于内核空间,则直接报错
|
||||
// todo: 生成一个sigsegv
|
||||
|
@ -1,39 +1,5 @@
|
||||
#include "x86_64_ipi.h"
|
||||
#include <driver/interrupt/apic/apic.h>
|
||||
|
||||
void ipi_send_IPI(uint32_t dest_mode, uint32_t deliver_status, uint32_t level, uint32_t trigger,
|
||||
uint32_t vector, uint32_t deliver_mode, uint32_t dest_shorthand, uint32_t destination)
|
||||
{
|
||||
struct INT_CMD_REG icr_entry;
|
||||
icr_entry.dest_mode = dest_mode;
|
||||
icr_entry.deliver_status = deliver_status;
|
||||
icr_entry.res_1 = 0;
|
||||
icr_entry.level = level;
|
||||
icr_entry.trigger = trigger;
|
||||
icr_entry.res_2 = 0;
|
||||
icr_entry.res_3 = 0;
|
||||
|
||||
icr_entry.vector = vector;
|
||||
icr_entry.deliver_mode = deliver_mode;
|
||||
icr_entry.dest_shorthand = dest_shorthand;
|
||||
|
||||
// x2APIC下,ICR寄存器地址为0x830
|
||||
// xAPIC下则为0xfee00300(31-0) 0xfee00310 (63-32)
|
||||
if (CURRENT_APIC_STATE == APIC_X2APIC_ENABLED) // x2APIC
|
||||
{
|
||||
icr_entry.destination.x2apic_destination = destination;
|
||||
wrmsr(0x830, *(unsigned long *)&icr_entry); // 发送ipi
|
||||
}
|
||||
else // xAPIC
|
||||
{
|
||||
|
||||
icr_entry.destination.apic_destination.dest_field = destination & 0xff;
|
||||
icr_entry.destination.apic_destination.res_4 = 0;
|
||||
// 先向高32bit写数据,然后再向低32bit写数据,不能调转
|
||||
*(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + 0x310) = (uint32_t)(((*(ul *)&icr_entry) >> 32) & 0xffffffff);
|
||||
*(uint32_t *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + 0x300) = (uint32_t)((*(ul *)&icr_entry) & 0xffffffff);
|
||||
}
|
||||
}
|
||||
#include <arch/x86_64/driver/apic/apic.h>
|
||||
|
||||
int ipi_regiserIPI(uint64_t irq_num, void *arg,
|
||||
void (*handler)(uint64_t irq_num, uint64_t param, struct pt_regs *regs),
|
||||
@ -46,4 +12,4 @@ int ipi_regiserIPI(uint64_t irq_num, void *arg,
|
||||
p->flags = 0;
|
||||
p->handler = handler;
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -12,22 +12,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/kprint.h>
|
||||
#include <driver/interrupt/apic/apic.h>
|
||||
|
||||
/**
|
||||
* @brief 发送ipi消息
|
||||
*
|
||||
* @param dest_mode 目标模式
|
||||
* @param deliver_status 投递模式
|
||||
* @param level 信号驱动电平
|
||||
* @param trigger 触发模式
|
||||
* @param vector 中断向量
|
||||
* @param deliver_mode 投递模式
|
||||
* @param dest_shorthand 投递目标速记值
|
||||
* @param destination 投递目标
|
||||
*/
|
||||
void ipi_send_IPI(uint32_t dest_mode, uint32_t deliver_status, uint32_t level, uint32_t trigger,
|
||||
uint32_t vector, uint32_t deliver_mode, uint32_t dest_shorthand, uint32_t destination);
|
||||
#include <arch/x86_64/driver/apic/apic.h>
|
||||
|
||||
/**
|
||||
* @brief ipi中断处理注册函数
|
||||
|
Reference in New Issue
Block a user