使用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:
LoGin
2023-11-07 20:32:06 +08:00
committed by GitHub
parent 4935c74f32
commit 70a4e5550a
63 changed files with 2638 additions and 1367 deletions

View File

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

View File

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

View File

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

View 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

View 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

View 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());
}

View 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();

View 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,
)
};
}
}
}

View 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());
}

View 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(&reg));
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(&reg));
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);
}

View 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);
});
}
}
}

View 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) };
}
}

View 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
}
/// 发送 EOIEnd 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();
}
}
}
}

View File

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

View File

@ -1,3 +1,4 @@
pub mod apic;
mod c_adapter;
pub mod hpet;
pub mod tsc;

View 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());
}

View File

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

View File

@ -1,5 +1,6 @@
#![allow(dead_code)]
mod c_adapter;
pub mod ipi;
use core::{

View File

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

View File

@ -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;
}
}

View File

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