mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
完成中断管理模块重构 (#554)
- 支持中断共享 - 把现有驱动程序移植到新的irq模块 - 使用`ProcessorId`标识处理器id - 尚未实现threaded_irq 性能上,edge irq flow handler里面,对于锁的使用,可能有点问题。为了获取/修改common data还有其他几个结构体的状态,进行了多次加锁和放锁,导致性能降低。这是接下来需要优化的点。
This commit is contained in:
parent
44d051e586
commit
e28411791f
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
@ -10,14 +10,12 @@
|
||||
"glib.h": "c",
|
||||
"asm.h": "c",
|
||||
"memory.h": "c",
|
||||
"irq.h": "c",
|
||||
"multiboot2.h": "c",
|
||||
"kprint.h": "c",
|
||||
"8259a.h": "c",
|
||||
"ptrace.h": "c",
|
||||
"mouse.h": "c",
|
||||
"keyboard.h": "c",
|
||||
"apic.h": "c",
|
||||
"ps2_keyboard.h": "c",
|
||||
"algorithm": "c",
|
||||
"array": "c",
|
||||
@ -27,7 +25,6 @@
|
||||
"cassert": "c",
|
||||
"cctype": "c",
|
||||
"cerrno": "c",
|
||||
"cfloat": "c",
|
||||
"chrono": "c",
|
||||
"climits": "c",
|
||||
"clocale": "c",
|
||||
@ -83,7 +80,6 @@
|
||||
"cinttypes": "c",
|
||||
"cstdbool": "c",
|
||||
"typeinfo": "c",
|
||||
"x86_64_ipi.h": "c",
|
||||
"unistd.h": "c",
|
||||
"syscall_num.h": "c",
|
||||
"stdint.h": "c",
|
||||
@ -92,7 +88,6 @@
|
||||
"types.h": "c",
|
||||
"string.h": "c",
|
||||
"math.h": "c",
|
||||
"ipi.h": "c",
|
||||
"arch.h": "c",
|
||||
"stdio.h": "c",
|
||||
"wait_queue.h": "c",
|
||||
@ -109,10 +104,8 @@
|
||||
"ia64_msi.h": "c",
|
||||
"errno.h": "c",
|
||||
"bug.h": "c",
|
||||
"apic_timer.h": "c",
|
||||
"sched.h": "c",
|
||||
"preempt.h": "c",
|
||||
"softirq.h": "c",
|
||||
"screen_manager.h": "c",
|
||||
"textui.h": "c",
|
||||
"atomic.h": "c",
|
||||
@ -120,7 +113,6 @@
|
||||
"fat_ent.h": "c",
|
||||
"semaphore.h": "c",
|
||||
"mm-types.h": "c",
|
||||
"vfs.h": "c",
|
||||
"current.h": "c",
|
||||
"traceback.h": "c",
|
||||
"bitcount.h": "c",
|
||||
|
@ -18,7 +18,6 @@ impl CFilesArch for X86_64CFilesArch {
|
||||
}
|
||||
|
||||
fn setup_files(&self, _c: &mut Build, files: &mut Vec<PathBuf>) {
|
||||
files.push(arch_path("driver/hpet.c"));
|
||||
// 获取`kernel/src/arch/x86_64/driver/apic`下的所有C文件
|
||||
files.append(&mut FileUtils::list_all_files(
|
||||
&arch_path("driver/apic"),
|
||||
|
@ -162,12 +162,3 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4. 为C提供的接口
|
||||
|
||||
```c
|
||||
extern void rs_softirq_init();
|
||||
extern void rs_raise_softirq(uint32_t sirq_num);
|
||||
extern void rs_unregister_softirq(uint32_t sirq_num);
|
||||
extern void rs_do_softirq();
|
||||
extern void rs_clear_softirq_pending(uint32_t softirq_num);
|
||||
```
|
||||
|
@ -2,6 +2,7 @@ use alloc::vec::Vec;
|
||||
|
||||
use crate::{bitmap_core::BitMapCore, traits::BitMapOps};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AllocBitmap {
|
||||
elements: usize,
|
||||
data: Vec<usize>,
|
||||
|
@ -36,7 +36,7 @@ export ASFLAGS := --64
|
||||
LD_LIST := ""
|
||||
|
||||
|
||||
kernel_subdirs := common driver debug exception smp syscall libs time
|
||||
kernel_subdirs := common driver debug smp syscall libs time
|
||||
|
||||
|
||||
kernel_rust:
|
||||
|
@ -1,6 +1,8 @@
|
||||
use crate::smp::cpu::ProcessorId;
|
||||
|
||||
/// 获取当前cpu的id
|
||||
#[inline]
|
||||
pub fn current_cpu_id() -> u32 {
|
||||
pub fn current_cpu_id() -> ProcessorId {
|
||||
unimplemented!("RiscV64 current_cpu_id")
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{driver::acpi::acpi_manager, kinfo, mm::percpu::PerCpu};
|
||||
use crate::{driver::acpi::acpi_manager, kinfo, mm::percpu::PerCpu, smp::cpu::ProcessorId};
|
||||
|
||||
use super::smp::SMP_BOOT_DATA;
|
||||
|
||||
@ -11,16 +11,19 @@ pub(super) fn early_acpi_boot_init() -> Result<(), SystemError> {
|
||||
let processor_info = platform_info.processor_info.ok_or(SystemError::ENODEV)?;
|
||||
|
||||
unsafe {
|
||||
SMP_BOOT_DATA.set_phys_id(0, processor_info.boot_processor.local_apic_id as usize);
|
||||
let mut cnt = 1;
|
||||
SMP_BOOT_DATA.set_phys_id(
|
||||
ProcessorId::new(0),
|
||||
processor_info.boot_processor.local_apic_id as usize,
|
||||
);
|
||||
let mut cnt = ProcessorId::new(1);
|
||||
for ap in processor_info.application_processors.iter() {
|
||||
if cnt >= PerCpu::MAX_CPU_NUM {
|
||||
if cnt.data() >= PerCpu::MAX_CPU_NUM {
|
||||
break;
|
||||
}
|
||||
SMP_BOOT_DATA.set_phys_id(cnt, ap.local_apic_id as usize);
|
||||
cnt += 1;
|
||||
cnt = ProcessorId::new(cnt.data() + 1);
|
||||
}
|
||||
SMP_BOOT_DATA.set_cpu_count(cnt);
|
||||
SMP_BOOT_DATA.set_cpu_count(cnt.data());
|
||||
SMP_BOOT_DATA.mark_initialized();
|
||||
}
|
||||
kinfo!(
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::time::TimeArch;
|
||||
use crate::{sched::SchedArch, time::TimeArch};
|
||||
|
||||
use super::{driver::tsc::TSCManager, syscall::init_syscall_64, CurrentTimeArch};
|
||||
use super::{driver::tsc::TSCManager, syscall::init_syscall_64, CurrentSchedArch, CurrentTimeArch};
|
||||
|
||||
/// 获取当前的时间戳
|
||||
#[no_mangle]
|
||||
@ -18,3 +18,8 @@ unsafe extern "C" fn rs_tsc_get_cpu_khz() -> u64 {
|
||||
pub unsafe extern "C" fn rs_init_syscall_64() {
|
||||
init_syscall_64();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_init_current_core_sched() {
|
||||
CurrentSchedArch::initial_setup_sched_local();
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
use x86::cpuid::{cpuid, CpuIdResult};
|
||||
|
||||
/// @brief 获取当前cpu的apic id
|
||||
use crate::smp::cpu::ProcessorId;
|
||||
|
||||
/// 获取当前cpu的apic id
|
||||
#[inline]
|
||||
pub fn current_cpu_id() -> u32 {
|
||||
pub fn current_cpu_id() -> ProcessorId {
|
||||
let cpuid_res: CpuIdResult = cpuid!(0x1);
|
||||
let cpu_id = (cpuid_res.ebx >> 24) & 0xff;
|
||||
return cpu_id;
|
||||
return ProcessorId::new(cpu_id);
|
||||
}
|
||||
|
||||
/// 重置cpu
|
||||
|
@ -1,205 +0,0 @@
|
||||
#include "apic.h"
|
||||
#include "apic_timer.h"
|
||||
#include <common/cpu.h>
|
||||
#include <common/glib.h>
|
||||
#include <common/kprint.h>
|
||||
#include <common/printk.h>
|
||||
#include <driver/acpi/acpi.h>
|
||||
#include <exception/softirq.h>
|
||||
#include <process/process.h>
|
||||
#include <sched/sched.h>
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize("O0")
|
||||
// 导出定义在irq.c中的中段门表
|
||||
extern void (*interrupt_table[26])(void);
|
||||
extern uint32_t rs_current_pcb_preempt_count();
|
||||
extern uint32_t rs_current_pcb_pid();
|
||||
extern uint32_t rs_current_pcb_flags();
|
||||
extern void rs_apic_init_bsp();
|
||||
|
||||
extern void rs_apic_local_apic_edge_ack(uint8_t irq_num);
|
||||
|
||||
extern int rs_ioapic_install(uint8_t vector, uint8_t dest, bool level_triggered, bool active_high, bool dest_logical);
|
||||
extern void rs_ioapic_uninstall(uint8_t irq_num);
|
||||
extern void rs_ioapic_enable(uint8_t irq_num);
|
||||
extern void rs_ioapic_disable(uint8_t irq_num);
|
||||
|
||||
/**
|
||||
* @brief 中断服务程序
|
||||
*
|
||||
* @param rsp 中断栈指针
|
||||
* @param number 中断向量号
|
||||
*/
|
||||
void do_IRQ(struct pt_regs *rsp, ul number)
|
||||
{
|
||||
|
||||
if ((rsp->cs & 0x3) == 3)
|
||||
{
|
||||
asm volatile("swapgs" ::: "memory");
|
||||
}
|
||||
if (number < 0x80 && number >= 32) // 以0x80为界限,低于0x80的是外部中断控制器,高于0x80的是Local APIC
|
||||
{
|
||||
// ==========外部中断控制器========
|
||||
irq_desc_t *irq = &interrupt_desc[number - 32];
|
||||
|
||||
// 执行中断上半部处理程序
|
||||
if (irq != NULL && irq->handler != NULL)
|
||||
irq->handler(number, irq->parameter, rsp);
|
||||
else
|
||||
kwarn("Intr vector [%d] does not have a handler!");
|
||||
// 向中断控制器发送应答消息
|
||||
// if (irq->controller != NULL && irq->controller->ack != NULL)
|
||||
// irq->controller->ack(number);
|
||||
// else
|
||||
// rs_apic_local_apic_edge_ack(number);
|
||||
rs_apic_local_apic_edge_ack(number);
|
||||
}
|
||||
else if (number >= 200)
|
||||
{
|
||||
rs_apic_local_apic_edge_ack(number);
|
||||
|
||||
{
|
||||
irq_desc_t *irq = &SMP_IPI_desc[number - 200];
|
||||
if (irq->handler != NULL)
|
||||
irq->handler(number, irq->parameter, rsp);
|
||||
}
|
||||
}
|
||||
else if (number >= 150 && number < 200)
|
||||
{
|
||||
irq_desc_t *irq = &local_apic_interrupt_desc[number - 150];
|
||||
|
||||
// 执行中断上半部处理程序
|
||||
if (irq != NULL && irq->handler != NULL)
|
||||
irq->handler(number, irq->parameter, rsp);
|
||||
else
|
||||
kwarn("Intr vector [%d] does not have a handler!");
|
||||
// 向中断控制器发送应答消息
|
||||
// if (irq->controller != NULL && irq->controller->ack != NULL)
|
||||
// irq->controller->ack(number);
|
||||
// else
|
||||
// rs_apic_local_apic_edge_ack(number);
|
||||
rs_apic_local_apic_edge_ack(number);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
kwarn("do IRQ receive: %d", number);
|
||||
// 忽略未知中断
|
||||
return;
|
||||
}
|
||||
|
||||
// kdebug("before softirq");
|
||||
// 进入软中断处理程序
|
||||
rs_do_softirq();
|
||||
|
||||
// kdebug("after softirq");
|
||||
// 检测当前进程是否持有自旋锁,若持有自旋锁,则不进行抢占式的进程调度
|
||||
if (rs_current_pcb_preempt_count() > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if ((int32_t)rs_current_pcb_preempt_count() < 0)
|
||||
kBUG("current_pcb->preempt_count<0! pid=%d", rs_current_pcb_pid()); // should not be here
|
||||
|
||||
// 检测当前进程是否可被调度
|
||||
if ((rs_current_pcb_flags() & PF_NEED_SCHED) && number == APIC_TIMER_IRQ_NUM)
|
||||
{
|
||||
io_mfence();
|
||||
sched();
|
||||
}
|
||||
}
|
||||
|
||||
// =========== 中断控制操作接口 ============
|
||||
void apic_ioapic_enable(ul irq_num)
|
||||
{
|
||||
rs_ioapic_enable(irq_num);
|
||||
}
|
||||
|
||||
void apic_ioapic_disable(ul irq_num)
|
||||
{
|
||||
rs_ioapic_disable(irq_num);
|
||||
}
|
||||
|
||||
ul apic_ioapic_install(ul irq_num, void *arg)
|
||||
{
|
||||
struct apic_IO_APIC_RTE_entry *entry = (struct apic_IO_APIC_RTE_entry *)arg;
|
||||
uint8_t dest = 0;
|
||||
if (entry->dest_mode)
|
||||
{
|
||||
dest = entry->destination.logical.logical_dest;
|
||||
}
|
||||
else
|
||||
{
|
||||
dest = entry->destination.physical.phy_dest;
|
||||
}
|
||||
|
||||
return rs_ioapic_install(entry->vector, dest, entry->trigger_mode, entry->polarity, entry->dest_mode);
|
||||
}
|
||||
|
||||
void apic_ioapic_uninstall(ul irq_num)
|
||||
{
|
||||
rs_ioapic_uninstall(irq_num);
|
||||
}
|
||||
|
||||
void apic_ioapic_edge_ack(ul irq_num) // 边沿触发
|
||||
{
|
||||
|
||||
rs_apic_local_apic_edge_ack(irq_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief local apic 边沿触发应答
|
||||
*
|
||||
* @param irq_num
|
||||
*/
|
||||
|
||||
void apic_local_apic_edge_ack(ul irq_num)
|
||||
{
|
||||
rs_apic_local_apic_edge_ack(irq_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 构造RTE Entry结构体
|
||||
*
|
||||
* @param entry 返回的结构体
|
||||
* @param vector 中断向量
|
||||
* @param deliver_mode 投递模式
|
||||
* @param dest_mode 目标模式
|
||||
* @param deliver_status 投递状态
|
||||
* @param polarity 电平触发极性
|
||||
* @param irr 远程IRR标志位(只读)
|
||||
* @param trigger 触发模式
|
||||
* @param mask 屏蔽标志位,(0为未屏蔽, 1为已屏蔽)
|
||||
* @param dest_apicID 目标apicID
|
||||
*/
|
||||
void apic_make_rte_entry(struct apic_IO_APIC_RTE_entry *entry, uint8_t vector, uint8_t deliver_mode, uint8_t dest_mode,
|
||||
uint8_t deliver_status, uint8_t polarity, uint8_t irr, uint8_t trigger, uint8_t mask,
|
||||
uint8_t dest_apicID)
|
||||
{
|
||||
|
||||
entry->vector = vector;
|
||||
entry->deliver_mode = deliver_mode;
|
||||
entry->dest_mode = dest_mode;
|
||||
entry->deliver_status = deliver_status;
|
||||
entry->polarity = polarity;
|
||||
entry->remote_IRR = irr;
|
||||
entry->trigger_mode = trigger;
|
||||
entry->mask = mask;
|
||||
|
||||
entry->reserved = 0;
|
||||
|
||||
if (dest_mode == DEST_PHYSICAL)
|
||||
{
|
||||
entry->destination.physical.phy_dest = dest_apicID;
|
||||
entry->destination.physical.reserved1 = 0;
|
||||
entry->destination.physical.reserved2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->destination.logical.logical_dest = dest_apicID;
|
||||
entry->destination.logical.reserved1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
@ -1,284 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/asm.h>
|
||||
#include <process/ptrace.h>
|
||||
#include <exception/irq.h>
|
||||
#include <mm/mm.h>
|
||||
#include <arch/arch.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();
|
||||
|
||||
#if ARCH(I386) || ARCH(X86_64)
|
||||
|
||||
// =========== 中断控制操作接口 ============
|
||||
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边沿触发 应答
|
||||
#else
|
||||
void apic_ioapic_enable(ul irq_num)
|
||||
{
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
void apic_ioapic_disable(ul irq_num)
|
||||
{
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
ul apic_ioapic_install(ul irq_num, void *arg)
|
||||
{
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
void apic_ioapic_uninstall(ul irq_num)
|
||||
{
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
void apic_ioapic_edge_ack(ul irq_num)
|
||||
{
|
||||
while (1)
|
||||
;
|
||||
} // ioapic边沿触发 应答
|
||||
|
||||
// void apic_local_apic_level_ack(ul irq_num);// local apic电平触发 应答
|
||||
void apic_local_apic_edge_ack(ul irq_num)
|
||||
{
|
||||
while (1)
|
||||
;
|
||||
} // local apic边沿触发 应答
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @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
|
@ -1,96 +0,0 @@
|
||||
#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());
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
#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();
|
@ -1,42 +1,111 @@
|
||||
use core::cell::RefCell;
|
||||
|
||||
use crate::arch::driver::tsc::TSCManager;
|
||||
use crate::include::bindings::bindings::APIC_TIMER_IRQ_NUM;
|
||||
use crate::arch::interrupt::TrapFrame;
|
||||
use crate::driver::base::device::DeviceId;
|
||||
use crate::exception::irqdata::{IrqHandlerData, IrqLineStatus};
|
||||
use crate::exception::irqdesc::{
|
||||
irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandleFlags, IrqHandler, IrqReturn,
|
||||
};
|
||||
use crate::exception::manage::irq_manager;
|
||||
use crate::exception::IrqNumber;
|
||||
|
||||
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::smp::cpu::ProcessorId;
|
||||
use crate::time::clocksource::HZ;
|
||||
use alloc::string::ToString;
|
||||
use alloc::sync::Arc;
|
||||
pub use drop;
|
||||
use system_error::SystemError;
|
||||
use x86::cpuid::cpuid;
|
||||
use x86::msr::{wrmsr, IA32_X2APIC_DIV_CONF, IA32_X2APIC_INIT_COUNT};
|
||||
|
||||
use super::lapic_vector::local_apic_chip;
|
||||
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];
|
||||
pub const APIC_TIMER_IRQ_NUM: IrqNumber = IrqNumber::new(151);
|
||||
|
||||
static mut LOCAL_APIC_TIMERS: [RefCell<LocalApicTimer>; PerCpu::MAX_CPU_NUM as usize] =
|
||||
[const { RefCell::new(LocalApicTimer::new()) }; PerCpu::MAX_CPU_NUM as usize];
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[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() }
|
||||
pub(super) fn local_apic_timer_instance(
|
||||
cpu_id: ProcessorId,
|
||||
) -> core::cell::Ref<'static, LocalApicTimer> {
|
||||
unsafe { LOCAL_APIC_TIMERS[cpu_id.data() as usize].borrow() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) fn local_apic_timer_instance_mut(
|
||||
cpu_id: u32,
|
||||
cpu_id: ProcessorId,
|
||||
) -> core::cell::RefMut<'static, LocalApicTimer> {
|
||||
unsafe { LOCAL_APIC_TIMERS[cpu_id as usize].borrow_mut() }
|
||||
unsafe { LOCAL_APIC_TIMERS[cpu_id.data() as usize].borrow_mut() }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LocalApicTimerHandler;
|
||||
|
||||
impl IrqHandler for LocalApicTimerHandler {
|
||||
fn handle(
|
||||
&self,
|
||||
_irq: IrqNumber,
|
||||
_static_data: Option<&dyn IrqHandlerData>,
|
||||
_dynamic_data: Option<Arc<dyn IrqHandlerData>>,
|
||||
) -> Result<IrqReturn, SystemError> {
|
||||
// empty (只是为了让编译通过,不会被调用到。真正的处理函数在LocalApicTimerIrqFlowHandler中)
|
||||
Ok(IrqReturn::NotHandled)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LocalApicTimerIrqFlowHandler;
|
||||
|
||||
impl IrqFlowHandler for LocalApicTimerIrqFlowHandler {
|
||||
fn handle(&self, _irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
|
||||
LocalApicTimer::handle_irq().ok();
|
||||
CurrentApic.send_eoi();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apic_timer_init() {
|
||||
irq_manager()
|
||||
.request_irq(
|
||||
APIC_TIMER_IRQ_NUM,
|
||||
"LocalApic".to_string(),
|
||||
&LocalApicTimerHandler,
|
||||
IrqHandleFlags::IRQF_SHARED | IrqHandleFlags::IRQF_PERCPU,
|
||||
Some(DeviceId::new(Some("lapic timer"), None).unwrap()),
|
||||
)
|
||||
.expect("Apic timer init failed");
|
||||
|
||||
LocalApicTimerIntrController.install();
|
||||
LocalApicTimerIntrController.enable();
|
||||
}
|
||||
|
||||
/// 初始化本地APIC定时器的中断描述符
|
||||
#[inline(never)]
|
||||
pub(super) fn local_apic_timer_irq_desc_init() {
|
||||
let desc = irq_desc_manager().lookup(APIC_TIMER_IRQ_NUM).unwrap();
|
||||
let irq_data: Arc<crate::exception::irqdata::IrqData> = desc.irq_data();
|
||||
let mut chip_info_guard = irq_data.chip_info_write_irqsave();
|
||||
chip_info_guard.set_chip(Some(local_apic_chip().clone()));
|
||||
|
||||
desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
|
||||
drop(chip_info_guard);
|
||||
desc.set_handler(&LocalApicTimerIrqFlowHandler);
|
||||
}
|
||||
|
||||
/// 初始化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);
|
||||
assert!(smp_get_processor_id().data() == 0);
|
||||
let mut local_apic_timer = local_apic_timer_instance_mut(ProcessorId::new(0));
|
||||
local_apic_timer.init(
|
||||
LocalApicTimerMode::Periodic,
|
||||
LocalApicTimer::periodic_default_initial_count(),
|
||||
@ -48,7 +117,7 @@ fn init_bsp_apic_timer() {
|
||||
fn init_ap_apic_timer() {
|
||||
kdebug!("init_ap_apic_timer");
|
||||
let cpu_id = smp_get_processor_id();
|
||||
assert!(cpu_id != 0);
|
||||
assert!(cpu_id.data() != 0);
|
||||
|
||||
let mut local_apic_timer = local_apic_timer_instance_mut(cpu_id);
|
||||
local_apic_timer.init(
|
||||
@ -62,15 +131,16 @@ fn init_ap_apic_timer() {
|
||||
pub(super) struct LocalApicTimerIntrController;
|
||||
|
||||
impl LocalApicTimerIntrController {
|
||||
pub(super) fn install(&self, _irq_num: u8) {
|
||||
pub(super) fn install(&self) {
|
||||
kdebug!("LocalApicTimerIntrController::install");
|
||||
if smp_get_processor_id() == 0 {
|
||||
if smp_get_processor_id().data() == 0 {
|
||||
init_bsp_apic_timer();
|
||||
} else {
|
||||
init_ap_apic_timer();
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(super) fn uninstall(&self) {
|
||||
let cpu_id = smp_get_processor_id();
|
||||
let local_apic_timer = local_apic_timer_instance(cpu_id);
|
||||
@ -157,7 +227,11 @@ impl LocalApicTimer {
|
||||
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);
|
||||
self.setup_lvt(
|
||||
APIC_TIMER_IRQ_NUM.data() as u8,
|
||||
true,
|
||||
LocalApicTimerMode::Periodic,
|
||||
);
|
||||
}
|
||||
|
||||
fn setup_lvt(&mut self, vector: u8, mask: bool, mode: LocalApicTimerMode) {
|
||||
@ -200,9 +274,9 @@ impl LocalApicTimer {
|
||||
return (res.ecx & (1 << 24)) != 0;
|
||||
}
|
||||
|
||||
pub(super) fn handle_irq() -> Result<(), SystemError> {
|
||||
pub(super) fn handle_irq() -> Result<IrqReturn, SystemError> {
|
||||
sched_update_jiffies();
|
||||
return Ok(());
|
||||
return Ok(IrqReturn::Handled);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,43 +1,4 @@
|
||||
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;
|
||||
}
|
||||
use super::{CurrentApic, LocalAPIC};
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_apic_init_ap() -> i32 {
|
||||
@ -47,38 +8,3 @@ pub extern "C" fn rs_apic_init_ap() -> i32 {
|
||||
|
||||
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());
|
||||
}
|
||||
|
9
kernel/src/arch/x86_64/driver/apic/hw_irq.rs
Normal file
9
kernel/src/arch/x86_64/driver/apic/hw_irq.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use crate::{exception::HardwareIrqNumber, int_like};
|
||||
|
||||
int_like!(ApicId, u32);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(super) struct HardwareIrqConfig {
|
||||
pub apic_id: ApicId,
|
||||
pub vector: HardwareIrqNumber,
|
||||
}
|
@ -1,16 +1,26 @@
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use acpi::madt::Madt;
|
||||
use alloc::sync::Arc;
|
||||
use bit_field::BitField;
|
||||
use bitflags::bitflags;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::acpi::acpi_manager,
|
||||
exception::{
|
||||
handle::{edge_irq_handler, fast_eoi_irq_handler},
|
||||
irqchip::{IrqChip, IrqChipData, IrqChipFlags, IrqChipSetMaskResult, IrqChipState},
|
||||
irqdata::{IrqData, IrqLineStatus},
|
||||
irqdesc::{irq_desc_manager, IrqDesc, IrqFlowHandler},
|
||||
manage::irq_manager,
|
||||
IrqNumber,
|
||||
},
|
||||
kdebug, kinfo,
|
||||
libs::{
|
||||
cpumask::CpuMask,
|
||||
once::Once,
|
||||
spinlock::SpinLock,
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
volatile::{volwrite, Volatile},
|
||||
},
|
||||
mm::{
|
||||
@ -22,12 +32,18 @@ use crate::{
|
||||
use super::{CurrentApic, LocalAPIC};
|
||||
|
||||
static mut __IOAPIC: Option<SpinLock<IoApic>> = None;
|
||||
static mut IOAPIC_IR_CHIP: Option<Arc<IoApicChip>> = None;
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
fn IOAPIC() -> &'static SpinLock<IoApic> {
|
||||
unsafe { __IOAPIC.as_ref().unwrap() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) fn ioapic_ir_chip() -> Arc<dyn IrqChip> {
|
||||
unsafe { IOAPIC_IR_CHIP.as_ref().unwrap().clone() }
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct IoApic {
|
||||
reg: *mut u32,
|
||||
@ -253,6 +269,12 @@ impl IoApic {
|
||||
unsafe { (self.read(REG_VER).get_bits(16..24) + 1) as u8 }
|
||||
}
|
||||
|
||||
pub fn pending(&mut self, irq: u8) -> bool {
|
||||
let rte_index = Self::vector_rte_index(irq);
|
||||
let data = unsafe { self.read(REG_TABLE + 2 * rte_index) };
|
||||
data & (1 << 12) != 0
|
||||
}
|
||||
|
||||
fn vector_rte_index(irq_num: u8) -> u8 {
|
||||
assert!(irq_num >= Self::VECTOR_BASE);
|
||||
irq_num - Self::VECTOR_BASE
|
||||
@ -272,12 +294,6 @@ impl IoApic {
|
||||
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
|
||||
@ -307,15 +323,126 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ioapic_init() {
|
||||
#[derive(Debug)]
|
||||
struct IoApicChipData {
|
||||
inner: SpinLock<InnerIoApicChipData>,
|
||||
}
|
||||
|
||||
impl IrqChipData for IoApicChipData {
|
||||
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl IoApicChipData {
|
||||
const DEFAULT: Self = Self::new(0, 0, 0, false, false, false, true);
|
||||
|
||||
const fn new(
|
||||
rte_index: u8,
|
||||
vector: u8,
|
||||
dest: u8,
|
||||
level_triggered: bool,
|
||||
active_high: bool,
|
||||
dest_logic: bool,
|
||||
mask: bool,
|
||||
) -> Self {
|
||||
IoApicChipData {
|
||||
inner: SpinLock::new(InnerIoApicChipData {
|
||||
rte_index,
|
||||
vector,
|
||||
dest,
|
||||
level_triggered,
|
||||
active_high,
|
||||
dest_logic,
|
||||
mask,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn inner(&self) -> SpinLockGuard<InnerIoApicChipData> {
|
||||
self.inner.lock_irqsave()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerIoApicChipData {
|
||||
rte_index: u8,
|
||||
vector: u8,
|
||||
dest: u8,
|
||||
level_triggered: bool,
|
||||
active_high: bool,
|
||||
dest_logic: bool,
|
||||
mask: bool,
|
||||
}
|
||||
|
||||
impl InnerIoApicChipData {
|
||||
/// 把中断数据同步到芯片
|
||||
fn sync_to_chip(&self) -> Result<(), SystemError> {
|
||||
ioapic_install(
|
||||
self.vector,
|
||||
self.dest,
|
||||
self.level_triggered,
|
||||
self.active_high,
|
||||
self.dest_logic,
|
||||
self.mask,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn ioapic_init(ignore: &'static [IrqNumber]) {
|
||||
kinfo!("Initializing ioapic...");
|
||||
let ioapic = unsafe { IoApic::new() };
|
||||
unsafe {
|
||||
__IOAPIC = Some(SpinLock::new(ioapic));
|
||||
}
|
||||
unsafe {
|
||||
IOAPIC_IR_CHIP = Some(Arc::new(IoApicChip));
|
||||
}
|
||||
|
||||
// 绑定irqchip
|
||||
for i in 32..256 {
|
||||
let irq = IrqNumber::new(i);
|
||||
|
||||
if ignore.contains(&irq) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let desc = irq_desc_manager().lookup(irq).unwrap();
|
||||
let irq_data = desc.irq_data();
|
||||
let mut chip_info_guard = irq_data.chip_info_write_irqsave();
|
||||
chip_info_guard.set_chip(Some(ioapic_ir_chip()));
|
||||
let chip_data = IoApicChipData::DEFAULT;
|
||||
chip_data.inner().rte_index = IoApic::vector_rte_index(i as u8);
|
||||
chip_data.inner().vector = i as u8;
|
||||
chip_info_guard.set_chip_data(Some(Arc::new(chip_data)));
|
||||
drop(chip_info_guard);
|
||||
let level = irq_data.is_level_type();
|
||||
|
||||
register_handler(&desc, level);
|
||||
}
|
||||
|
||||
kinfo!("IO Apic initialized.");
|
||||
}
|
||||
|
||||
fn register_handler(desc: &Arc<IrqDesc>, level_triggered: bool) {
|
||||
let fasteoi: bool;
|
||||
if level_triggered {
|
||||
desc.modify_status(IrqLineStatus::empty(), IrqLineStatus::IRQ_LEVEL);
|
||||
fasteoi = true;
|
||||
} else {
|
||||
desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
|
||||
fasteoi = false;
|
||||
}
|
||||
|
||||
let handler: &dyn IrqFlowHandler = if fasteoi {
|
||||
fast_eoi_irq_handler()
|
||||
} else {
|
||||
edge_irq_handler()
|
||||
};
|
||||
desc.set_handler(handler);
|
||||
}
|
||||
|
||||
/// 安装中断
|
||||
///
|
||||
/// ## 参数
|
||||
@ -326,12 +453,13 @@ pub fn ioapic_init() {
|
||||
/// * `active_high` - 是否为高电平有效
|
||||
/// * `dest_logic` - 是否为逻辑模式
|
||||
/// * `mask` - 是否屏蔽
|
||||
pub(super) fn ioapic_install(
|
||||
fn ioapic_install(
|
||||
vector: u8,
|
||||
dest: u8,
|
||||
level_triggered: bool,
|
||||
active_high: bool,
|
||||
dest_logic: bool,
|
||||
mask: bool,
|
||||
) -> Result<(), SystemError> {
|
||||
let rte_index = IoApic::vector_rte_index(vector);
|
||||
return IOAPIC().lock_irqsave().install(
|
||||
@ -341,24 +469,190 @@ pub(super) fn ioapic_install(
|
||||
level_triggered,
|
||||
active_high,
|
||||
dest_logic,
|
||||
true,
|
||||
mask,
|
||||
);
|
||||
}
|
||||
|
||||
/// 卸载中断
|
||||
pub(super) fn ioapic_uninstall(vector: u8) {
|
||||
let rte_index = IoApic::vector_rte_index(vector);
|
||||
IOAPIC().lock_irqsave().disable(rte_index);
|
||||
}
|
||||
/// IoApic中断芯片
|
||||
///
|
||||
/// https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/apic/io_apic.c#1994
|
||||
#[derive(Debug)]
|
||||
struct IoApicChip;
|
||||
|
||||
/// 使能中断
|
||||
pub(super) fn ioapic_enable(vector: u8) {
|
||||
let rte_index = IoApic::vector_rte_index(vector);
|
||||
IOAPIC().lock_irqsave().enable(rte_index);
|
||||
}
|
||||
impl IrqChip for IoApicChip {
|
||||
fn name(&self) -> &'static str {
|
||||
"IR-IO-APIC"
|
||||
}
|
||||
|
||||
/// 禁用中断
|
||||
pub(super) fn ioapic_disable(vector: u8) {
|
||||
let rte_index = IoApic::vector_rte_index(vector);
|
||||
IOAPIC().lock_irqsave().disable(rte_index);
|
||||
fn irq_startup(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
self.irq_unmask(irq)
|
||||
}
|
||||
|
||||
fn irq_mask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
let binding = irq
|
||||
.chip_info_read_irqsave()
|
||||
.chip_data()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
let chip_data = binding
|
||||
.as_any_ref()
|
||||
.downcast_ref::<IoApicChipData>()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
|
||||
let mut chip_data_inner = chip_data.inner();
|
||||
chip_data_inner.mask = true;
|
||||
chip_data_inner.sync_to_chip().ok();
|
||||
|
||||
drop(chip_data_inner);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn can_set_affinity(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn can_set_flow_type(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn irq_set_type(
|
||||
&self,
|
||||
irq: &Arc<IrqData>,
|
||||
flow_type: IrqLineStatus,
|
||||
) -> Result<IrqChipSetMaskResult, SystemError> {
|
||||
let binding = irq
|
||||
.chip_info_read_irqsave()
|
||||
.chip_data()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
let chip_data = binding
|
||||
.as_any_ref()
|
||||
.downcast_ref::<IoApicChipData>()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
let mut chip_data_inner = chip_data.inner();
|
||||
|
||||
let level_triggered = flow_type.is_level_type();
|
||||
let active_high = flow_type.is_level_high().unwrap_or(false);
|
||||
chip_data_inner.active_high = active_high;
|
||||
chip_data_inner.level_triggered = level_triggered;
|
||||
chip_data_inner.sync_to_chip()?;
|
||||
|
||||
return Ok(IrqChipSetMaskResult::SetMaskOk);
|
||||
}
|
||||
|
||||
fn irq_set_affinity(
|
||||
&self,
|
||||
irq: &Arc<IrqData>,
|
||||
cpu: &CpuMask,
|
||||
_force: bool,
|
||||
) -> Result<IrqChipSetMaskResult, SystemError> {
|
||||
// 使用mask的第1个可用CPU
|
||||
let dest = (cpu.first().ok_or(SystemError::EINVAL)?.data() & 0xff) as u8;
|
||||
|
||||
let binding = irq
|
||||
.chip_info_read_irqsave()
|
||||
.chip_data()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
let chip_data = binding
|
||||
.as_any_ref()
|
||||
.downcast_ref::<IoApicChipData>()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
|
||||
let mut chip_data_inner = chip_data.inner();
|
||||
let origin_dest = chip_data_inner.dest;
|
||||
if origin_dest == dest {
|
||||
return Ok(IrqChipSetMaskResult::SetMaskOk);
|
||||
}
|
||||
|
||||
chip_data_inner.dest = dest;
|
||||
|
||||
chip_data_inner.sync_to_chip()?;
|
||||
|
||||
return Ok(IrqChipSetMaskResult::SetMaskOk);
|
||||
}
|
||||
|
||||
fn irq_unmask(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
IOAPIC()
|
||||
.lock_irqsave()
|
||||
.enable(IoApic::vector_rte_index(irq.irq().data() as u8));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn can_mask_ack(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn irq_mask_ack(&self, irq: &Arc<IrqData>) {
|
||||
self.irq_mask(irq).ok();
|
||||
self.irq_eoi(irq);
|
||||
}
|
||||
|
||||
fn irq_eoi(&self, irq: &Arc<IrqData>) {
|
||||
if irq.is_level_type() {
|
||||
IOAPIC().lock_irqsave().level_ack(irq.irq().data() as u8);
|
||||
} else {
|
||||
CurrentApic.send_eoi();
|
||||
}
|
||||
}
|
||||
|
||||
fn retrigger(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
irq_manager().irq_chip_retrigger_hierarchy(irq_data)
|
||||
}
|
||||
|
||||
fn irqchip_state(&self, irq: &Arc<IrqData>, which: IrqChipState) -> Result<bool, SystemError> {
|
||||
let binding = irq
|
||||
.chip_info_read_irqsave()
|
||||
.chip_data()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
let chip_data = binding
|
||||
.as_any_ref()
|
||||
.downcast_ref::<IoApicChipData>()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
|
||||
match which {
|
||||
IrqChipState::Pending => {
|
||||
return Ok(IOAPIC().lock_irqsave().pending(irq.irq().data() as u8));
|
||||
}
|
||||
IrqChipState::Active => {
|
||||
let chip_data_inner = chip_data.inner();
|
||||
return Ok(!chip_data_inner.mask);
|
||||
}
|
||||
IrqChipState::Masked => {
|
||||
let chip_data_inner = chip_data.inner();
|
||||
return Ok(chip_data_inner.mask);
|
||||
}
|
||||
IrqChipState::LineLevel => {
|
||||
let chip_data_inner = chip_data.inner();
|
||||
return Ok(chip_data_inner.active_high);
|
||||
}
|
||||
#[allow(unreachable_patterns)]
|
||||
_ => {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn irq_disable(&self, irq: &Arc<IrqData>) {
|
||||
let binding = irq
|
||||
.chip_info_read_irqsave()
|
||||
.chip_data()
|
||||
.ok_or(SystemError::EINVAL)
|
||||
.unwrap();
|
||||
let chip_data = binding
|
||||
.as_any_ref()
|
||||
.downcast_ref::<IoApicChipData>()
|
||||
.ok_or(SystemError::EINVAL)
|
||||
.unwrap();
|
||||
let mut chip_data_inner = chip_data.inner();
|
||||
chip_data_inner.mask = true;
|
||||
chip_data_inner.sync_to_chip().ok();
|
||||
}
|
||||
|
||||
fn irq_ack(&self, irq_data: &Arc<IrqData>) {
|
||||
// irq_manager().irq_chip_ack_parent(irq_data);
|
||||
self.irq_eoi(irq_data);
|
||||
}
|
||||
|
||||
fn flags(&self) -> IrqChipFlags {
|
||||
IrqChipFlags::IRQCHIP_SKIP_SET_WAKE | IrqChipFlags::IRQCHIP_AFFINITY_PRE_STARTUP
|
||||
}
|
||||
}
|
||||
|
289
kernel/src/arch/x86_64/driver/apic/lapic_vector.rs
Normal file
289
kernel/src/arch/x86_64/driver/apic/lapic_vector.rs
Normal file
@ -0,0 +1,289 @@
|
||||
use core::intrinsics::unlikely;
|
||||
|
||||
use alloc::{string::ToString, sync::Arc};
|
||||
use intertrait::CastFrom;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
driver::apic::{
|
||||
apic_timer::{local_apic_timer_irq_desc_init, APIC_TIMER_IRQ_NUM},
|
||||
ioapic::ioapic_init,
|
||||
},
|
||||
interrupt::{
|
||||
entry::arch_setup_interrupt_gate,
|
||||
ipi::{arch_ipi_handler_init, send_ipi, IPI_NUM_FLUSH_TLB, IPI_NUM_KICK_CPU},
|
||||
msi::{X86MsiAddrHi, X86MsiAddrLoNormal, X86MsiDataNormal, X86_MSI_BASE_ADDRESS_LOW},
|
||||
},
|
||||
},
|
||||
driver::open_firmware::device_node::DeviceNode,
|
||||
exception::{
|
||||
ipi::{IpiKind, IpiTarget},
|
||||
irqchip::{IrqChip, IrqChipData, IrqChipFlags},
|
||||
irqdata::IrqData,
|
||||
irqdomain::{irq_domain_manager, IrqDomain, IrqDomainBusToken, IrqDomainOps},
|
||||
msi::MsiMsg,
|
||||
HardwareIrqNumber, IrqNumber,
|
||||
},
|
||||
kwarn,
|
||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
||||
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
||||
};
|
||||
|
||||
use super::{hw_irq::HardwareIrqConfig, CurrentApic, LocalAPIC};
|
||||
|
||||
static mut LOCAL_APIC_CHIP: Option<Arc<LocalApicChip>> = None;
|
||||
|
||||
pub fn local_apic_chip() -> &'static Arc<LocalApicChip> {
|
||||
unsafe { LOCAL_APIC_CHIP.as_ref().unwrap() }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LocalApicChip {
|
||||
inner: SpinLock<InnerIrqChip>,
|
||||
}
|
||||
|
||||
impl LocalApicChip {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: SpinLock::new(InnerIrqChip {
|
||||
flags: IrqChipFlags::empty(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IrqChip for LocalApicChip {
|
||||
fn name(&self) -> &'static str {
|
||||
"APIC"
|
||||
}
|
||||
|
||||
fn can_set_flow_type(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn irq_disable(&self, _irq: &Arc<IrqData>) {}
|
||||
|
||||
fn irq_ack(&self, _irq: &Arc<IrqData>) {
|
||||
CurrentApic.send_eoi();
|
||||
}
|
||||
|
||||
fn can_set_affinity(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn can_mask_ack(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
// 这里临时处理,后续需要修改
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn irq_unmask(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn irq_compose_msi_msg(&self, irq: &Arc<IrqData>, msg: &mut MsiMsg) {
|
||||
let chip_data = irq.chip_info_read_irqsave().chip_data().unwrap();
|
||||
let apicd = chip_data.ref_any().downcast_ref::<ApicChipData>().unwrap();
|
||||
let cfg = &apicd.inner().hw_irq_cfg;
|
||||
irq_msi_compose_msg(cfg, msg, false);
|
||||
}
|
||||
|
||||
fn retrigger(&self, irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
let chip_data = irq
|
||||
.chip_info_read_irqsave()
|
||||
.chip_data()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
let apicd = chip_data
|
||||
.ref_any()
|
||||
.downcast_ref::<ApicChipData>()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
let inner = apicd.inner();
|
||||
|
||||
send_ipi(
|
||||
IpiKind::SpecVector(inner.vector),
|
||||
IpiTarget::Specified(inner.cpu),
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn flags(&self) -> IrqChipFlags {
|
||||
self.inner.lock_irqsave().flags
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerIrqChip {
|
||||
flags: IrqChipFlags,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ApicChipData {
|
||||
inner: SpinLock<InnerApicChipData>,
|
||||
}
|
||||
|
||||
impl ApicChipData {
|
||||
#[allow(dead_code)]
|
||||
pub fn new(
|
||||
hw_irq_cfg: HardwareIrqConfig,
|
||||
irq: IrqNumber,
|
||||
vector: HardwareIrqNumber,
|
||||
cpu: ProcessorId,
|
||||
) -> Self {
|
||||
Self {
|
||||
inner: SpinLock::new(InnerApicChipData {
|
||||
hw_irq_cfg,
|
||||
irq,
|
||||
vector,
|
||||
prev_vector: None,
|
||||
cpu,
|
||||
prev_cpu: None,
|
||||
status: ApicChipStatus::empty(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> SpinLockGuard<InnerApicChipData> {
|
||||
self.inner.lock_irqsave()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct InnerApicChipData {
|
||||
hw_irq_cfg: HardwareIrqConfig,
|
||||
irq: IrqNumber,
|
||||
vector: HardwareIrqNumber,
|
||||
prev_vector: Option<HardwareIrqNumber>,
|
||||
cpu: ProcessorId,
|
||||
prev_cpu: Option<ProcessorId>,
|
||||
status: ApicChipStatus,
|
||||
}
|
||||
|
||||
impl IrqChipData for ApicChipData {
|
||||
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct ApicChipStatus: u32 {
|
||||
const MOVE_IN_PROGRESS = 1 << 0;
|
||||
const IS_MANAGED = 1 << 1;
|
||||
const CAN_RESERVE = 1 << 2;
|
||||
const HAS_RESERVED = 1 << 3;
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn irq_msi_compose_msg(cfg: &HardwareIrqConfig, msg: &mut MsiMsg, dmar: bool) {
|
||||
*msg = MsiMsg::new_zeroed();
|
||||
|
||||
let arch_data = X86MsiDataNormal::new()
|
||||
.with_delivery_mode(x86::apic::DeliveryMode::Fixed as u8)
|
||||
.with_vector((cfg.vector.data() & 0xff) as u8);
|
||||
let mut address_lo = X86MsiAddrLoNormal::new()
|
||||
.with_base_address(X86_MSI_BASE_ADDRESS_LOW)
|
||||
.with_dest_mode_logical(false)
|
||||
.with_destid_0_7(cfg.apic_id.data() & 0xff);
|
||||
|
||||
let mut address_hi = X86MsiAddrHi::new();
|
||||
|
||||
/*
|
||||
* 只有IOMMU本身可以使用将目标APIC ID放入地址的高位的技术。
|
||||
* 任何其他尝试这样做的东西都只是在写内存,并且需要IR来
|
||||
* 寻址不能在正常的32位地址范围内0xFFExxxxx寻址的APIC。
|
||||
* 这通常是8位,但一些虚拟化程序允许在位5-11使用扩展的目的地ID字段,
|
||||
* 总共支持15位的APIC ID。
|
||||
*/
|
||||
if dmar {
|
||||
address_hi.set_destid_8_31(cfg.apic_id.data() >> 8);
|
||||
} else if cfg.apic_id.data() < 0x8000 {
|
||||
// todo: 判断vmx是否支持 extended destination mode
|
||||
// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/apic/apic.c?fi=__irq_msi_compose_msg#2580
|
||||
address_lo.set_virt_destid_8_14(cfg.apic_id.data() >> 8);
|
||||
} else {
|
||||
if unlikely(cfg.apic_id.data() > 0xff) {
|
||||
kwarn!(
|
||||
"irq_msi_compose_msg: Invalid APIC ID: {}",
|
||||
cfg.apic_id.data()
|
||||
);
|
||||
}
|
||||
}
|
||||
msg.address_hi = address_hi.into();
|
||||
msg.address_lo = address_lo.into();
|
||||
msg.data = arch_data.into();
|
||||
}
|
||||
|
||||
static mut X86_VECTOR_DOMAIN: Option<Arc<IrqDomain>> = None;
|
||||
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn x86_vector_domain() -> &'static Arc<IrqDomain> {
|
||||
unsafe { X86_VECTOR_DOMAIN.as_ref().unwrap() }
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn arch_early_irq_init() -> Result<(), SystemError> {
|
||||
let vec_domain = irq_domain_manager()
|
||||
.create_and_add(
|
||||
"VECTOR".to_string(),
|
||||
&X86VectorDomainOps,
|
||||
IrqNumber::new(32),
|
||||
HardwareIrqNumber::new(32),
|
||||
223,
|
||||
)
|
||||
.ok_or(SystemError::ENOMEM)?;
|
||||
irq_domain_manager().set_default_domain(vec_domain.clone());
|
||||
unsafe { X86_VECTOR_DOMAIN = Some(vec_domain) };
|
||||
|
||||
let apic_chip = Arc::new(LocalApicChip::new());
|
||||
|
||||
unsafe { LOCAL_APIC_CHIP = Some(apic_chip) };
|
||||
|
||||
// todo: add vector matrix
|
||||
// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/apic/vector.c#803
|
||||
kwarn!("arch_early_irq_init: todo: add vector matrix");
|
||||
|
||||
local_apic_timer_irq_desc_init();
|
||||
arch_ipi_handler_init();
|
||||
CurrentApic.init_current_cpu();
|
||||
if smp_get_processor_id().data() == 0 {
|
||||
unsafe { arch_setup_interrupt_gate() };
|
||||
ioapic_init(&[APIC_TIMER_IRQ_NUM, IPI_NUM_KICK_CPU, IPI_NUM_FLUSH_TLB]);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// x86的中断域操作
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/arch/x86/kernel/apic/vector.c#693
|
||||
#[derive(Debug)]
|
||||
struct X86VectorDomainOps;
|
||||
|
||||
impl IrqDomainOps for X86VectorDomainOps {
|
||||
fn match_node(
|
||||
&self,
|
||||
_irq_domain: &Arc<IrqDomain>,
|
||||
_device_node: &Arc<DeviceNode>,
|
||||
_bus_token: IrqDomainBusToken,
|
||||
) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn map(
|
||||
&self,
|
||||
_irq_domain: &Arc<IrqDomain>,
|
||||
_hwirq: HardwareIrqNumber,
|
||||
_virq: IrqNumber,
|
||||
) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) {
|
||||
todo!()
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ use x86::{apic::Icr, msr::IA32_APIC_BASE};
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
driver::apic::{ioapic::ioapic_init, x2apic::X2Apic, xapic::XApic},
|
||||
driver::apic::{hw_irq::ApicId, x2apic::X2Apic, xapic::XApic},
|
||||
io::PortIOArch,
|
||||
CurrentPortIOArch,
|
||||
},
|
||||
@ -22,7 +22,9 @@ use self::{
|
||||
|
||||
pub mod apic_timer;
|
||||
mod c_adapter;
|
||||
pub mod hw_irq;
|
||||
pub mod ioapic;
|
||||
pub mod lapic_vector;
|
||||
pub mod x2apic;
|
||||
pub mod xapic;
|
||||
|
||||
@ -63,7 +65,7 @@ pub trait LocalAPIC {
|
||||
fn max_lvt_entry(&self) -> u8;
|
||||
|
||||
/// @brief 获取当前处理器的APIC ID
|
||||
fn id(&self) -> u32;
|
||||
fn id(&self) -> ApicId;
|
||||
|
||||
/// @brief 设置LVT寄存器
|
||||
///
|
||||
@ -481,20 +483,20 @@ impl LocalAPIC for CurrentApic {
|
||||
|
||||
fn init_current_cpu(&mut self) -> bool {
|
||||
let cpu_id = smp_get_processor_id();
|
||||
if cpu_id == 0 {
|
||||
if cpu_id.data() == 0 {
|
||||
unsafe {
|
||||
self.mask8259a();
|
||||
}
|
||||
}
|
||||
kinfo!("Initializing apic for cpu {}", cpu_id);
|
||||
kinfo!("Initializing apic for cpu {:?}", cpu_id);
|
||||
if X2Apic::support() && X2Apic.init_current_cpu() {
|
||||
if cpu_id == 0 {
|
||||
if cpu_id.data() == 0 {
|
||||
LOCAL_APIC_ENABLE_TYPE.store(LocalApicEnableType::X2Apic, Ordering::SeqCst);
|
||||
}
|
||||
kinfo!("x2APIC initialized for cpu {}", cpu_id);
|
||||
kinfo!("x2APIC initialized for cpu {:?}", cpu_id);
|
||||
} else {
|
||||
kinfo!("x2APIC not supported or failed to initialize, fallback to xAPIC.");
|
||||
if cpu_id == 0 {
|
||||
if cpu_id.data() == 0 {
|
||||
LOCAL_APIC_ENABLE_TYPE.store(LocalApicEnableType::XApic, Ordering::SeqCst);
|
||||
}
|
||||
let apic_base =
|
||||
@ -512,11 +514,9 @@ impl LocalAPIC for CurrentApic {
|
||||
xapic.init_current_cpu();
|
||||
}
|
||||
|
||||
kinfo!("xAPIC initialized for cpu {}", cpu_id);
|
||||
}
|
||||
if cpu_id == 0 {
|
||||
ioapic_init();
|
||||
kinfo!("xAPIC initialized for cpu {:?}", cpu_id);
|
||||
}
|
||||
|
||||
kinfo!("Apic initialized.");
|
||||
return true;
|
||||
}
|
||||
@ -567,7 +567,7 @@ impl LocalAPIC for CurrentApic {
|
||||
}
|
||||
}
|
||||
|
||||
fn id(&self) -> u32 {
|
||||
fn id(&self) -> ApicId {
|
||||
if LOCAL_APIC_ENABLE_TYPE.load(Ordering::SeqCst) == LocalApicEnableType::X2Apic {
|
||||
return X2Apic.id();
|
||||
} else {
|
||||
@ -575,7 +575,7 @@ impl LocalAPIC for CurrentApic {
|
||||
.borrow()
|
||||
.as_ref()
|
||||
.map(|xapic| xapic.id())
|
||||
.unwrap_or(0);
|
||||
.unwrap_or(ApicId::new(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ use x86::msr::{
|
||||
|
||||
use crate::{kdebug, kinfo};
|
||||
|
||||
use super::{LVTRegister, LocalAPIC, LVT};
|
||||
use super::{hw_irq::ApicId, LVTRegister, LocalAPIC, LVT};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct X2Apic;
|
||||
@ -84,8 +84,8 @@ impl LocalAPIC for X2Apic {
|
||||
}
|
||||
|
||||
/// 获取 x2APIC 的 APIC ID
|
||||
fn id(&self) -> u32 {
|
||||
unsafe { rdmsr(IA32_X2APIC_APICID.into()) as u32 }
|
||||
fn id(&self) -> ApicId {
|
||||
unsafe { ApicId::new(rdmsr(IA32_X2APIC_APICID.into()) as u32) }
|
||||
}
|
||||
|
||||
/// 设置 Local Vector Table (LVT) 寄存器
|
||||
|
@ -14,15 +14,15 @@ use crate::{
|
||||
smp::core::smp_get_processor_id,
|
||||
};
|
||||
|
||||
use super::{LVTRegister, LocalAPIC, LVT};
|
||||
use super::{hw_irq::ApicId, 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];
|
||||
static mut XAPIC_INSTANCES: [RefCell<Option<XApic>>; PerCpu::MAX_CPU_NUM as usize] =
|
||||
[const { RefCell::new(None) }; PerCpu::MAX_CPU_NUM as usize];
|
||||
|
||||
#[inline(always)]
|
||||
pub(super) fn current_xapic_instance() -> &'static RefCell<Option<XApic>> {
|
||||
unsafe { &XAPIC_INSTANCES.as_ref()[smp_get_processor_id() as usize] }
|
||||
unsafe { &XAPIC_INSTANCES.as_ref()[smp_get_processor_id().data() as usize] }
|
||||
}
|
||||
|
||||
/// TODO:统一变量
|
||||
@ -300,8 +300,8 @@ impl LocalAPIC for XApic {
|
||||
}
|
||||
|
||||
/// 获取ID
|
||||
fn id(&self) -> u32 {
|
||||
unsafe { self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ID.into()) >> 24 }
|
||||
fn id(&self) -> ApicId {
|
||||
unsafe { ApicId::new(self.read(XApicOffset::LOCAL_APIC_OFFSET_Local_APIC_ID.into()) >> 24) }
|
||||
}
|
||||
|
||||
/// 设置LVT寄存器的值
|
||||
|
@ -1,6 +0,0 @@
|
||||
use super::hpet::hpet_instance;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_handle_hpet_irq(timer_num: u32) {
|
||||
hpet_instance().handle_irq(timer_num);
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
#include <common/glib.h>
|
||||
#include <common/kprint.h>
|
||||
#include <arch/x86_64/driver/apic/apic.h>
|
||||
|
||||
extern void rs_handle_hpet_irq(uint32_t timer_num);
|
||||
|
||||
hardware_intr_controller HPET_intr_controller =
|
||||
{
|
||||
.enable = apic_ioapic_enable,
|
||||
.disable = apic_ioapic_disable,
|
||||
.install = apic_ioapic_install,
|
||||
.uninstall = apic_ioapic_uninstall,
|
||||
.ack = apic_ioapic_edge_ack,
|
||||
};
|
||||
|
||||
void HPET_handler(uint64_t number, uint64_t param, struct pt_regs *regs)
|
||||
{
|
||||
rs_handle_hpet_irq(param);
|
||||
}
|
||||
|
||||
void c_hpet_register_irq()
|
||||
{
|
||||
struct apic_IO_APIC_RTE_entry entry;
|
||||
apic_make_rte_entry(&entry, 34, IO_APIC_FIXED, DEST_PHYSICAL, IDLE, POLARITY_HIGH, IRR_RESET, EDGE_TRIGGER, MASKED, 0);
|
||||
irq_register(34, &entry, &HPET_handler, 0, &HPET_intr_controller, "HPET0");
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
use core::{
|
||||
ffi::c_void,
|
||||
intrinsics::unlikely,
|
||||
mem::size_of,
|
||||
ptr::NonNull,
|
||||
@ -7,6 +6,7 @@ use core::{
|
||||
};
|
||||
|
||||
use acpi::HpetInfo;
|
||||
use alloc::{string::ToString, sync::Arc};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
@ -16,8 +16,11 @@ use crate::{
|
||||
timers::hpet::{HpetRegisters, HpetTimerRegisters},
|
||||
},
|
||||
exception::{
|
||||
irqdata::IrqHandlerData,
|
||||
irqdesc::{IrqHandleFlags, IrqHandler, IrqReturn},
|
||||
manage::irq_manager,
|
||||
softirq::{softirq_vectors, SoftirqNumber},
|
||||
InterruptArch,
|
||||
InterruptArch, IrqNumber,
|
||||
},
|
||||
kdebug, kerror, kinfo,
|
||||
libs::{
|
||||
@ -31,10 +34,6 @@ use crate::{
|
||||
time::timer::{clock, timer_get_first_expire, update_timer_jiffies},
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
fn c_hpet_register_irq() -> c_void;
|
||||
}
|
||||
|
||||
static mut HPET_INSTANCE: Option<Hpet> = None;
|
||||
|
||||
#[inline(always)]
|
||||
@ -58,6 +57,8 @@ impl Hpet {
|
||||
/// HPET0 中断间隔为 10ms
|
||||
pub const HPET0_INTERVAL_USEC: u64 = 10000;
|
||||
|
||||
const HPET0_IRQ: IrqNumber = IrqNumber::new(34);
|
||||
|
||||
fn new(mut hpet_info: HpetInfo) -> Result<Self, SystemError> {
|
||||
let paddr = PhysAddr::new(hpet_info.base_address);
|
||||
let map_size = size_of::<HpetRegisters>();
|
||||
@ -107,6 +108,8 @@ impl Hpet {
|
||||
|
||||
/// 使能HPET
|
||||
pub fn hpet_enable(&self) -> Result<(), SystemError> {
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
|
||||
// !!!这里是临时糊代码的,需要在apic重构的时候修改!!!
|
||||
let (inner_guard, regs) = unsafe { self.hpet_regs_mut() };
|
||||
let freq = regs.frequency();
|
||||
@ -135,8 +138,14 @@ impl Hpet {
|
||||
}
|
||||
drop(inner_guard);
|
||||
|
||||
// todo!("register irq in C");
|
||||
unsafe { c_hpet_register_irq() };
|
||||
irq_manager().request_irq(
|
||||
Self::HPET0_IRQ,
|
||||
"HPET0".to_string(),
|
||||
&HpetIrqHandler,
|
||||
IrqHandleFlags::IRQF_TRIGGER_RISING,
|
||||
None,
|
||||
)?;
|
||||
|
||||
self.enabled.store(true, Ordering::SeqCst);
|
||||
|
||||
let (inner_guard, regs) = unsafe { self.hpet_regs_mut() };
|
||||
@ -147,6 +156,8 @@ impl Hpet {
|
||||
drop(inner_guard);
|
||||
|
||||
kinfo!("HPET enabled");
|
||||
|
||||
drop(irq_guard);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -251,3 +262,18 @@ pub fn hpet_init() -> Result<(), SystemError> {
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct HpetIrqHandler;
|
||||
|
||||
impl IrqHandler for HpetIrqHandler {
|
||||
fn handle(
|
||||
&self,
|
||||
_irq: IrqNumber,
|
||||
_static_data: Option<&dyn IrqHandlerData>,
|
||||
_dynamic_data: Option<Arc<dyn IrqHandlerData>>,
|
||||
) -> Result<IrqReturn, SystemError> {
|
||||
hpet_instance().handle_irq(0);
|
||||
return Ok(IrqReturn::Handled);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
pub mod apic;
|
||||
mod c_adapter;
|
||||
pub mod hpet;
|
||||
pub mod tsc;
|
||||
pub mod video;
|
||||
|
@ -1,30 +0,0 @@
|
||||
/**
|
||||
* @file ipi.h
|
||||
* @author fslongjin(longjin@RinGoTek.cn)
|
||||
* @brief 多核通信驱动
|
||||
* @version 0.1
|
||||
* @date 2022-04-07
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <common/kprint.h>
|
||||
#include <arch/x86_64/driver/apic/apic.h>
|
||||
|
||||
/**
|
||||
* @brief ipi中断处理注册函数
|
||||
*
|
||||
* @param irq_num 中断向量号
|
||||
* @param arg 参数
|
||||
* @param handler 处理函数
|
||||
* @param param 参数
|
||||
* @param controller 当前为NULL
|
||||
* @param irq_name ipi中断名
|
||||
* @return int 成功:0
|
||||
*/
|
||||
int ipi_regiserIPI(uint64_t irq_num, void *arg,
|
||||
void (*handler)(uint64_t irq_num, uint64_t param, struct pt_regs *regs),
|
||||
uint64_t param, hardware_intr_controller *controller, char *irq_name);
|
@ -1,3 +1,5 @@
|
||||
use crate::smp::cpu::ProcessorId;
|
||||
|
||||
use super::ipi::{ipi_send_smp_init, ipi_send_smp_startup};
|
||||
|
||||
#[no_mangle]
|
||||
@ -9,7 +11,7 @@ unsafe extern "C" fn rs_ipi_send_smp_init() -> i32 {
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_ipi_send_smp_startup(target_cpu: u32) -> i32 {
|
||||
return ipi_send_smp_startup(target_cpu)
|
||||
return ipi_send_smp_startup(ProcessorId::new(target_cpu))
|
||||
.map(|_| 0)
|
||||
.unwrap_or_else(|e| e.to_posix_errno());
|
||||
}
|
||||
|
@ -57,7 +57,8 @@ macro_rules! interrupt_handler {
|
||||
lea rax, ret_from_intr[rip]
|
||||
push rax
|
||||
mov rsi, {irqnum}
|
||||
jmp do_IRQ
|
||||
jmp x86_64_do_irq
|
||||
// jmp do_IRQ
|
||||
"
|
||||
),
|
||||
irqnum = const($name),
|
||||
@ -294,7 +295,7 @@ interrupt_handler!(254);
|
||||
interrupt_handler!(255);
|
||||
|
||||
#[inline(never)]
|
||||
pub(super) unsafe fn setup_interrupt_gate() {
|
||||
pub unsafe fn arch_setup_interrupt_gate() {
|
||||
set_intr_gate(32, 0, VirtAddr::new(irq_handler32 as usize));
|
||||
set_intr_gate(33, 0, VirtAddr::new(irq_handler33 as usize));
|
||||
set_intr_gate(34, 0, VirtAddr::new(irq_handler34 as usize));
|
||||
|
54
kernel/src/arch/x86_64/interrupt/handle.rs
Normal file
54
kernel/src/arch/x86_64/interrupt/handle.rs
Normal file
@ -0,0 +1,54 @@
|
||||
use core::intrinsics::likely;
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
driver::apic::{apic_timer::APIC_TIMER_IRQ_NUM, CurrentApic, LocalAPIC},
|
||||
sched::sched,
|
||||
},
|
||||
exception::{irqdesc::irq_desc_manager, softirq::do_softirq, IrqNumber},
|
||||
process::{
|
||||
process::{current_pcb_flags, current_pcb_preempt_count},
|
||||
ProcessFlags,
|
||||
},
|
||||
};
|
||||
|
||||
use super::TrapFrame;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn x86_64_do_irq(trap_frame: &mut TrapFrame, vector: u32) {
|
||||
// swapgs
|
||||
|
||||
if trap_frame.from_user() {
|
||||
x86_64::registers::segmentation::GS::swap();
|
||||
// 拒绝用户态中断
|
||||
return;
|
||||
}
|
||||
|
||||
// 由于x86上面,虚拟中断号与物理中断号是一一对应的,所以这里直接使用vector作为中断号来查询irqdesc
|
||||
|
||||
let desc = irq_desc_manager().lookup(IrqNumber::new(vector));
|
||||
|
||||
if likely(desc.is_some()) {
|
||||
let desc = desc.unwrap();
|
||||
let handler = desc.handler();
|
||||
if likely(handler.is_some()) {
|
||||
handler.unwrap().handle(&desc, trap_frame);
|
||||
} else {
|
||||
CurrentApic.send_eoi();
|
||||
}
|
||||
} else {
|
||||
CurrentApic.send_eoi();
|
||||
}
|
||||
|
||||
do_softirq();
|
||||
|
||||
if current_pcb_preempt_count() > 0 {
|
||||
return;
|
||||
}
|
||||
// 检测当前进程是否可被调度
|
||||
if (current_pcb_flags().contains(ProcessFlags::NEED_SCHEDULE))
|
||||
&& vector == APIC_TIMER_IRQ_NUM.data()
|
||||
{
|
||||
sched();
|
||||
}
|
||||
}
|
@ -1,20 +1,33 @@
|
||||
use alloc::sync::Arc;
|
||||
use system_error::SystemError;
|
||||
use x86::apic::ApicId;
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
driver::apic::{CurrentApic, LocalAPIC},
|
||||
driver::apic::{lapic_vector::local_apic_chip, CurrentApic, LocalAPIC},
|
||||
smp::SMP_BOOT_DATA,
|
||||
},
|
||||
exception::ipi::{IpiKind, IpiTarget},
|
||||
exception::{
|
||||
ipi::{FlushTLBIpiHandler, IpiKind, IpiTarget, KickCpuIpiHandler},
|
||||
irqdata::{IrqData, IrqLineStatus},
|
||||
irqdesc::{irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandler},
|
||||
HardwareIrqNumber, IrqNumber,
|
||||
},
|
||||
kerror,
|
||||
smp::cpu::ProcessorId,
|
||||
};
|
||||
|
||||
use super::TrapFrame;
|
||||
|
||||
pub const IPI_NUM_KICK_CPU: IrqNumber = IrqNumber::new(200);
|
||||
pub const IPI_NUM_FLUSH_TLB: IrqNumber = IrqNumber::new(201);
|
||||
/// IPI的种类(架构相关,指定了向量号)
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[repr(u8)]
|
||||
#[repr(u32)]
|
||||
pub enum ArchIpiKind {
|
||||
KickCpu = 200,
|
||||
FlushTLB = 201,
|
||||
KickCpu = IPI_NUM_KICK_CPU.data(),
|
||||
FlushTLB = IPI_NUM_FLUSH_TLB.data(),
|
||||
SpecVector(HardwareIrqNumber),
|
||||
}
|
||||
|
||||
impl From<IpiKind> for ArchIpiKind {
|
||||
@ -22,6 +35,17 @@ impl From<IpiKind> for ArchIpiKind {
|
||||
match kind {
|
||||
IpiKind::KickCpu => ArchIpiKind::KickCpu,
|
||||
IpiKind::FlushTLB => ArchIpiKind::FlushTLB,
|
||||
IpiKind::SpecVector(vec) => ArchIpiKind::SpecVector(vec),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for ArchIpiKind {
|
||||
fn into(self) -> u8 {
|
||||
match self {
|
||||
ArchIpiKind::KickCpu => IPI_NUM_KICK_CPU.data() as u8,
|
||||
ArchIpiKind::FlushTLB => IPI_NUM_FLUSH_TLB.data() as u8,
|
||||
ArchIpiKind::SpecVector(vec) => (vec.data() & 0xFF) as u8,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,7 +70,7 @@ impl From<IpiTarget> for ArchIpiTarget {
|
||||
IpiTarget::All => ArchIpiTarget::All,
|
||||
IpiTarget::Other => ArchIpiTarget::Other,
|
||||
IpiTarget::Specified(cpu_id) => {
|
||||
ArchIpiTarget::Specified(Self::cpu_id_to_apic_id(cpu_id as u32))
|
||||
ArchIpiTarget::Specified(Self::cpu_id_to_apic_id(cpu_id))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -78,11 +102,11 @@ impl ArchIpiTarget {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn cpu_id_to_apic_id(cpu_id: u32) -> x86::apic::ApicId {
|
||||
fn cpu_id_to_apic_id(cpu_id: ProcessorId) -> x86::apic::ApicId {
|
||||
if CurrentApic.x2apic_enabled() {
|
||||
x86::apic::ApicId::X2Apic(cpu_id as u32)
|
||||
x86::apic::ApicId::X2Apic(cpu_id.data() as u32)
|
||||
} else {
|
||||
x86::apic::ApicId::XApic(cpu_id as u8)
|
||||
x86::apic::ApicId::XApic(cpu_id.data() as u8)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -102,7 +126,7 @@ impl Into<x86::apic::DestinationShorthand> for ArchIpiTarget {
|
||||
pub fn send_ipi(kind: IpiKind, target: IpiTarget) {
|
||||
// kdebug!("send_ipi: {:?} {:?}", kind, target);
|
||||
|
||||
let ipi_vec = ArchIpiKind::from(kind) as u8;
|
||||
let ipi_vec = ArchIpiKind::from(kind).into();
|
||||
let target = ArchIpiTarget::from(target);
|
||||
let shorthand: x86::apic::DestinationShorthand = target.into();
|
||||
let destination: x86::apic::ApicId = target.into();
|
||||
@ -170,11 +194,11 @@ pub fn ipi_send_smp_init() -> Result<(), SystemError> {
|
||||
/// ## 参数
|
||||
///
|
||||
/// * `target_cpu` - 目标CPU
|
||||
pub fn ipi_send_smp_startup(target_cpu: u32) -> Result<(), SystemError> {
|
||||
if target_cpu as usize >= SMP_BOOT_DATA.cpu_count() {
|
||||
pub fn ipi_send_smp_startup(target_cpu: ProcessorId) -> Result<(), SystemError> {
|
||||
if target_cpu.data() as usize >= SMP_BOOT_DATA.cpu_count() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
let target: ArchIpiTarget = IpiTarget::Specified(target_cpu as usize).into();
|
||||
let target: ArchIpiTarget = IpiTarget::Specified(target_cpu).into();
|
||||
|
||||
let icr = if CurrentApic.x2apic_enabled() {
|
||||
x86::apic::Icr::for_x2apic(
|
||||
@ -203,3 +227,42 @@ pub fn ipi_send_smp_startup(target_cpu: u32) -> Result<(), SystemError> {
|
||||
CurrentApic.write_icr(icr);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 初始化IPI处理函数
|
||||
pub fn arch_ipi_handler_init() {
|
||||
do_init_irq_handler(IPI_NUM_KICK_CPU);
|
||||
do_init_irq_handler(IPI_NUM_FLUSH_TLB);
|
||||
}
|
||||
|
||||
fn do_init_irq_handler(irq: IrqNumber) {
|
||||
let desc = irq_desc_manager().lookup(irq).unwrap();
|
||||
let irq_data: Arc<IrqData> = desc.irq_data();
|
||||
let mut chip_info_guard = irq_data.chip_info_write_irqsave();
|
||||
chip_info_guard.set_chip(Some(local_apic_chip().clone()));
|
||||
|
||||
desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
|
||||
drop(chip_info_guard);
|
||||
desc.set_handler(&X86_64IpiIrqFlowHandler);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct X86_64IpiIrqFlowHandler;
|
||||
|
||||
impl IrqFlowHandler for X86_64IpiIrqFlowHandler {
|
||||
fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
|
||||
let irq = irq_desc.irq_data().irq();
|
||||
match irq {
|
||||
IPI_NUM_KICK_CPU => {
|
||||
KickCpuIpiHandler.handle(irq, None, None).ok();
|
||||
}
|
||||
IPI_NUM_FLUSH_TLB => {
|
||||
FlushTLBIpiHandler.handle(irq, None, None).ok();
|
||||
}
|
||||
_ => {
|
||||
kerror!("Unknown IPI: {}", irq.data());
|
||||
}
|
||||
}
|
||||
|
||||
CurrentApic.send_eoi();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
mod c_adapter;
|
||||
pub(super) mod entry;
|
||||
mod handle;
|
||||
pub mod ipi;
|
||||
pub mod msi;
|
||||
pub mod trap;
|
||||
|
||||
use core::{
|
||||
@ -16,11 +18,9 @@ use crate::{
|
||||
kerror,
|
||||
};
|
||||
|
||||
use self::entry::setup_interrupt_gate;
|
||||
|
||||
use super::{
|
||||
asm::irqflags::{local_irq_restore, local_irq_save},
|
||||
driver::apic::{CurrentApic, LocalAPIC},
|
||||
driver::apic::{lapic_vector::arch_early_irq_init, CurrentApic, LocalAPIC},
|
||||
};
|
||||
|
||||
/// @brief 关闭中断
|
||||
@ -45,8 +45,7 @@ impl InterruptArch for X86_64InterruptArch {
|
||||
#[inline(never)]
|
||||
unsafe fn arch_irq_init() -> Result<(), SystemError> {
|
||||
CurrentIrqArch::interrupt_disable();
|
||||
setup_interrupt_gate();
|
||||
CurrentApic.init_current_cpu();
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
unsafe fn interrupt_enable() {
|
||||
@ -90,6 +89,10 @@ impl InterruptArch for X86_64InterruptArch {
|
||||
kerror!("Unexpected IRQ trap at vector {}", irq.data());
|
||||
CurrentApic.send_eoi();
|
||||
}
|
||||
|
||||
fn arch_early_irq_init() -> Result<(), SystemError> {
|
||||
arch_early_irq_init()
|
||||
}
|
||||
}
|
||||
|
||||
/// 中断栈帧结构体
|
||||
|
89
kernel/src/arch/x86_64/interrupt/msi.rs
Normal file
89
kernel/src/arch/x86_64/interrupt/msi.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use bitfield_struct::bitfield;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum X86MsiData {
|
||||
Normal(X86MsiDataNormal),
|
||||
Dmar(X86MsiDataDmar),
|
||||
}
|
||||
|
||||
#[bitfield(u32)]
|
||||
pub struct X86MsiDataNormal {
|
||||
#[bits(8)]
|
||||
pub vector: u8,
|
||||
#[bits(3)]
|
||||
pub delivery_mode: u8,
|
||||
#[bits(1)]
|
||||
pub dest_mode_logical: bool,
|
||||
#[bits(2)]
|
||||
reserved: u8,
|
||||
#[bits(1)]
|
||||
pub active_low: bool,
|
||||
#[bits(1)]
|
||||
pub is_level_triggered: bool,
|
||||
#[bits(16)]
|
||||
reserved2: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct X86MsiDataDmar {
|
||||
pub dmar_subhandle: u32,
|
||||
}
|
||||
|
||||
impl X86MsiDataDmar {
|
||||
#[allow(dead_code)]
|
||||
pub const fn new(dmar_subhandle: u32) -> Self {
|
||||
X86MsiDataDmar { dmar_subhandle }
|
||||
}
|
||||
}
|
||||
|
||||
pub const X86_MSI_BASE_ADDRESS_LOW: u32 = 0xfee00000 >> 20;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum X86MsiAddrLo {
|
||||
Normal(X86MsiAddrLoNormal),
|
||||
Dmar(X86MsiAddrLoDmar),
|
||||
}
|
||||
|
||||
#[bitfield(u32)]
|
||||
pub struct X86MsiAddrLoNormal {
|
||||
#[bits(2)]
|
||||
reserved_0: u32,
|
||||
#[bits(1)]
|
||||
pub dest_mode_logical: bool,
|
||||
#[bits(1)]
|
||||
pub redirecti_hint: bool,
|
||||
#[bits(1)]
|
||||
reserved_1: bool,
|
||||
#[bits(7)]
|
||||
pub virt_destid_8_14: u32,
|
||||
#[bits(8)]
|
||||
pub destid_0_7: u32,
|
||||
#[bits(12)]
|
||||
pub base_address: u32,
|
||||
}
|
||||
|
||||
#[bitfield(u32)]
|
||||
pub struct X86MsiAddrLoDmar {
|
||||
#[bits(2)]
|
||||
reserved_0: u32,
|
||||
#[bits(1)]
|
||||
pub index_15: bool,
|
||||
#[bits(1)]
|
||||
pub subhandle_valid: bool,
|
||||
#[bits(1)]
|
||||
pub format: bool,
|
||||
#[bits(15)]
|
||||
pub index_0_14: u32,
|
||||
#[bits(12)]
|
||||
pub base_address: u32,
|
||||
}
|
||||
|
||||
#[bitfield(u32)]
|
||||
pub struct X86MsiAddrHi {
|
||||
#[bits(8)]
|
||||
reserved: u32,
|
||||
#[bits(24)]
|
||||
pub destid_8_31: u32,
|
||||
}
|
@ -73,7 +73,7 @@ unsafe extern "C" fn do_divide_error(regs: &'static TrapFrame, error_code: u64)
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Divide Error");
|
||||
@ -87,7 +87,7 @@ unsafe extern "C" fn do_debug(regs: &'static TrapFrame, error_code: u64) {
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Debug Exception");
|
||||
@ -101,7 +101,7 @@ unsafe extern "C" fn do_nmi(regs: &'static TrapFrame, error_code: u64) {
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("NMI Interrupt");
|
||||
@ -115,7 +115,7 @@ unsafe extern "C" fn do_int3(regs: &'static TrapFrame, error_code: u64) {
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Int3");
|
||||
@ -129,7 +129,7 @@ unsafe extern "C" fn do_overflow(regs: &'static TrapFrame, error_code: u64) {
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Overflow Exception");
|
||||
@ -143,7 +143,7 @@ unsafe extern "C" fn do_bounds(regs: &'static TrapFrame, error_code: u64) {
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Bounds Check");
|
||||
@ -157,7 +157,7 @@ unsafe extern "C" fn do_undefined_opcode(regs: &'static TrapFrame, error_code: u
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Undefined Opcode");
|
||||
@ -171,7 +171,7 @@ unsafe extern "C" fn do_dev_not_avaliable(regs: &'static TrapFrame, error_code:
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Device Not Available");
|
||||
@ -185,7 +185,7 @@ unsafe extern "C" fn do_double_fault(regs: &'static TrapFrame, error_code: u64)
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Double Fault");
|
||||
@ -199,7 +199,7 @@ unsafe extern "C" fn do_coprocessor_segment_overrun(regs: &'static TrapFrame, er
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Coprocessor Segment Overrun");
|
||||
@ -236,7 +236,7 @@ unsafe extern "C" fn do_invalid_TSS(regs: &'static TrapFrame, error_code: u64) {
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid(),
|
||||
msg1,
|
||||
msg2
|
||||
@ -252,7 +252,7 @@ unsafe extern "C" fn do_segment_not_exists(regs: &'static TrapFrame, error_code:
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Segment Not Exists");
|
||||
@ -266,7 +266,7 @@ unsafe extern "C" fn do_stack_segment_fault(regs: &'static TrapFrame, error_code
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Stack Segment Fault");
|
||||
@ -313,7 +313,7 @@ Segment Selector Index: {:#x}\n
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid(),
|
||||
msg1, msg2, msg3,
|
||||
error_code & 0xfff8
|
||||
@ -329,7 +329,7 @@ unsafe extern "C" fn do_page_fault(regs: &'static TrapFrame, error_code: u64) {
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid(),
|
||||
x86::controlregs::cr2()
|
||||
);
|
||||
@ -370,7 +370,7 @@ unsafe extern "C" fn do_x87_FPU_error(regs: &'static TrapFrame, error_code: u64)
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("x87 FPU Error");
|
||||
@ -384,7 +384,7 @@ unsafe extern "C" fn do_alignment_check(regs: &'static TrapFrame, error_code: u6
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Alignment Check");
|
||||
@ -398,7 +398,7 @@ unsafe extern "C" fn do_machine_check(regs: &'static TrapFrame, error_code: u64)
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Machine Check");
|
||||
@ -412,7 +412,7 @@ unsafe extern "C" fn do_SIMD_exception(regs: &'static TrapFrame, error_code: u64
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("SIMD Exception");
|
||||
@ -426,7 +426,7 @@ unsafe extern "C" fn do_virtualization_exception(regs: &'static TrapFrame, error
|
||||
error_code,
|
||||
regs.rsp,
|
||||
regs.rip,
|
||||
smp_get_processor_id(),
|
||||
smp_get_processor_id().data(),
|
||||
ProcessManager::current_pid()
|
||||
);
|
||||
panic!("Virtualization Exception");
|
||||
|
@ -1,15 +0,0 @@
|
||||
#include "x86_64_ipi.h"
|
||||
#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),
|
||||
uint64_t param, hardware_intr_controller *controller, char *irq_name)
|
||||
{
|
||||
irq_desc_t *p = &SMP_IPI_desc[irq_num - 200];
|
||||
p->controller = NULL; // 由于ipi不涉及到具体的硬件操作,因此不需要controller
|
||||
p->irq_name = irq_name;
|
||||
p->parameter = param;
|
||||
p->flags = 0;
|
||||
p->handler = handler;
|
||||
return 0;
|
||||
}
|
@ -4,6 +4,8 @@ use crate::arch::MMArch;
|
||||
use crate::mm::page::PageFlags;
|
||||
use crate::mm::{PageTableKind, PhysAddr, VirtAddr};
|
||||
use crate::smp::core::smp_get_processor_id;
|
||||
use crate::smp::cpu::AtomicProcessorId;
|
||||
use crate::smp::cpu::ProcessorId;
|
||||
use core::sync::atomic::{compiler_fence, AtomicUsize, Ordering};
|
||||
use system_error::SystemError;
|
||||
use x86::msr;
|
||||
@ -25,9 +27,9 @@ pub fn check_ept_features() -> Result<(), SystemError> {
|
||||
|
||||
/// 标志当前没有处理器持有内核映射器的锁
|
||||
/// 之所以需要这个标志,是因为AtomicUsize::new(0)会把0当作一个处理器的id
|
||||
const EPT_MAPPER_NO_PROCESSOR: usize = !0;
|
||||
const EPT_MAPPER_NO_PROCESSOR: ProcessorId = ProcessorId::INVALID;
|
||||
/// 当前持有内核映射器锁的处理器
|
||||
static EPT_MAPPER_LOCK_OWNER: AtomicUsize = AtomicUsize::new(EPT_MAPPER_NO_PROCESSOR);
|
||||
static EPT_MAPPER_LOCK_OWNER: AtomicProcessorId = AtomicProcessorId::new(EPT_MAPPER_NO_PROCESSOR);
|
||||
/// 内核映射器的锁计数器
|
||||
static EPT_MAPPER_LOCK_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
@ -41,7 +43,7 @@ pub struct EptMapper {
|
||||
}
|
||||
|
||||
impl EptMapper {
|
||||
fn lock_cpu(cpuid: usize, mapper: PageMapper) -> Self {
|
||||
fn lock_cpu(cpuid: ProcessorId, mapper: PageMapper) -> Self {
|
||||
loop {
|
||||
match EPT_MAPPER_LOCK_OWNER.compare_exchange_weak(
|
||||
EPT_MAPPER_NO_PROCESSOR,
|
||||
@ -69,7 +71,7 @@ impl EptMapper {
|
||||
/// @brief 锁定内核映射器, 并返回一个内核映射器对象
|
||||
#[inline(always)]
|
||||
pub fn lock() -> Self {
|
||||
let cpuid = smp_get_processor_id() as usize;
|
||||
let cpuid = smp_get_processor_id();
|
||||
let mapper = unsafe { PageMapper::current(PageTableKind::EPT, LockedFrameAllocator) };
|
||||
return Self::lock_cpu(cpuid, mapper);
|
||||
}
|
||||
|
@ -32,24 +32,24 @@ pub unsafe fn switch_fs_and_gs(fs: SegmentSelector, gs: SegmentSelector) {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TSSManager {
|
||||
tss: [TaskStateSegment; PerCpu::MAX_CPU_NUM],
|
||||
tss: [TaskStateSegment; PerCpu::MAX_CPU_NUM as usize],
|
||||
}
|
||||
|
||||
impl TSSManager {
|
||||
const fn new() -> Self {
|
||||
return Self {
|
||||
tss: [TaskStateSegment::new(); PerCpu::MAX_CPU_NUM],
|
||||
tss: [TaskStateSegment::new(); PerCpu::MAX_CPU_NUM as usize],
|
||||
};
|
||||
}
|
||||
|
||||
/// 获取当前CPU的TSS
|
||||
pub unsafe fn current_tss() -> &'static mut TaskStateSegment {
|
||||
&mut TSS_MANAGER.tss[smp_get_processor_id() as usize]
|
||||
&mut TSS_MANAGER.tss[smp_get_processor_id().data() as usize]
|
||||
}
|
||||
|
||||
/// 加载当前CPU的TSS
|
||||
pub unsafe fn load_tr() {
|
||||
let index = (10 + smp_get_processor_id() * 2) as u16;
|
||||
let index = (10 + smp_get_processor_id().data() * 2) as u16;
|
||||
let selector = SegmentSelector::new(index, Ring::Ring0);
|
||||
|
||||
Self::set_tss_descriptor(
|
||||
|
@ -1,9 +1,11 @@
|
||||
use core::hint::spin_loop;
|
||||
|
||||
use crate::{
|
||||
exception::InterruptArch, include::bindings::bindings::enter_syscall_int, sched::SchedArch,
|
||||
syscall::SYS_SCHED,
|
||||
smp::core::smp_get_processor_id, syscall::SYS_SCHED,
|
||||
};
|
||||
|
||||
use super::CurrentIrqArch;
|
||||
use super::{driver::apic::apic_timer::apic_timer_init, CurrentIrqArch};
|
||||
|
||||
/// @brief 若内核代码不处在中断上下文中,那么将可以使用本函数,发起一个sys_sched系统调用,然后运行调度器。
|
||||
/// 由于只能在中断上下文中进行进程切换,因此需要发起一个系统调用SYS_SCHED。
|
||||
@ -14,9 +16,7 @@ pub extern "C" fn sched() {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn apic_timer_init();
|
||||
}
|
||||
static mut BSP_INIT_OK: bool = false;
|
||||
|
||||
pub struct X86_64SchedArch;
|
||||
|
||||
@ -33,8 +33,23 @@ impl SchedArch for X86_64SchedArch {
|
||||
}
|
||||
|
||||
fn initial_setup_sched_local() {
|
||||
unsafe {
|
||||
apic_timer_init();
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
|
||||
let cpu_id = smp_get_processor_id();
|
||||
|
||||
if cpu_id.data() != 0 {
|
||||
while !unsafe { BSP_INIT_OK } {
|
||||
spin_loop();
|
||||
}
|
||||
}
|
||||
|
||||
apic_timer_init();
|
||||
if smp_get_processor_id().data() == 0 {
|
||||
unsafe {
|
||||
BSP_INIT_OK = true;
|
||||
}
|
||||
}
|
||||
|
||||
drop(irq_guard);
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
libs::rwlock::RwLock,
|
||||
mm::percpu::PerCpu,
|
||||
process::ProcessManager,
|
||||
smp::{core::smp_get_processor_id, SMPArch},
|
||||
smp::{core::smp_get_processor_id, cpu::ProcessorId, SMPArch},
|
||||
};
|
||||
|
||||
use super::{acpi::early_acpi_boot_init, CurrentIrqArch};
|
||||
@ -35,7 +35,7 @@ struct ApStartStackInfo {
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn smp_ap_start() -> ! {
|
||||
CurrentIrqArch::interrupt_disable();
|
||||
let vaddr = cpu_core_info[smp_get_processor_id() as usize].stack_start as usize;
|
||||
let vaddr = cpu_core_info[smp_get_processor_id().data() as usize].stack_start as usize;
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
let v = ApStartStackInfo { vaddr };
|
||||
smp_init_switch_stack(&v);
|
||||
@ -55,8 +55,8 @@ unsafe extern "sysv64" fn smp_init_switch_stack(st: &ApStartStackInfo) -> ! {
|
||||
|
||||
unsafe extern "C" fn smp_ap_start_stage1() -> ! {
|
||||
let id = smp_get_processor_id();
|
||||
kdebug!("smp_ap_start_stage1: id: {}\n", id);
|
||||
let current_idle = ProcessManager::idle_pcb()[smp_get_processor_id() as usize].clone();
|
||||
kdebug!("smp_ap_start_stage1: id: {}\n", id.data());
|
||||
let current_idle = ProcessManager::idle_pcb()[smp_get_processor_id().data() as usize].clone();
|
||||
|
||||
let tss = TSSManager::current_tss();
|
||||
|
||||
@ -80,7 +80,7 @@ pub struct SmpBootData {
|
||||
/// CPU的物理ID(指的是Local APIC ID)
|
||||
///
|
||||
/// 这里必须保证第0项的是bsp的物理ID
|
||||
phys_id: [usize; PerCpu::MAX_CPU_NUM],
|
||||
phys_id: [usize; PerCpu::MAX_CPU_NUM as usize],
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -99,17 +99,17 @@ impl SmpBootData {
|
||||
self.phys_id[0]
|
||||
}
|
||||
|
||||
pub unsafe fn set_cpu_count(&self, cpu_count: usize) {
|
||||
pub unsafe fn set_cpu_count(&self, cpu_count: u32) {
|
||||
if self.initialized.load(Ordering::SeqCst) == false {
|
||||
let p = self as *const SmpBootData as *mut SmpBootData;
|
||||
(*p).cpu_count = cpu_count;
|
||||
(*p).cpu_count = cpu_count.try_into().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn set_phys_id(&self, cpu_id: usize, phys_id: usize) {
|
||||
pub unsafe fn set_phys_id(&self, cpu_id: ProcessorId, phys_id: usize) {
|
||||
if self.initialized.load(Ordering::SeqCst) == false {
|
||||
let p = self as *const SmpBootData as *mut SmpBootData;
|
||||
(*p).phys_id[cpu_id] = phys_id;
|
||||
(*p).phys_id[cpu_id.data() as usize] = phys_id;
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,19 +122,19 @@ impl SmpBootData {
|
||||
pub(super) static SMP_BOOT_DATA: SmpBootData = SmpBootData {
|
||||
initialized: AtomicBool::new(false),
|
||||
cpu_count: 0,
|
||||
phys_id: [0; PerCpu::MAX_CPU_NUM],
|
||||
phys_id: [0; PerCpu::MAX_CPU_NUM as usize],
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct X86_64SmpManager {
|
||||
ia64_cpu_to_sapicid: RwLock<[Option<usize>; PerCpu::MAX_CPU_NUM]>,
|
||||
ia64_cpu_to_sapicid: RwLock<[Option<usize>; PerCpu::MAX_CPU_NUM as usize]>,
|
||||
}
|
||||
|
||||
impl X86_64SmpManager {
|
||||
pub const fn new() -> Self {
|
||||
return Self {
|
||||
ia64_cpu_to_sapicid: RwLock::new([None; PerCpu::MAX_CPU_NUM]),
|
||||
ia64_cpu_to_sapicid: RwLock::new([None; PerCpu::MAX_CPU_NUM as usize]),
|
||||
};
|
||||
}
|
||||
/// initialize the logical cpu number to APIC ID mapping
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
CFLAGS += -I .
|
||||
|
||||
kernel_driver_subdirs:=pci acpi disk keyboard mouse multiboot2 timers hid
|
||||
kernel_driver_subdirs:=acpi disk multiboot2 timers hid
|
||||
|
||||
ECHO:
|
||||
@echo "$@"
|
||||
|
@ -50,7 +50,7 @@ pub fn driver_manager() -> &'static DriverManager {
|
||||
/// 否则在运行时会报错
|
||||
pub trait Driver: Sync + Send + Debug + KObject {
|
||||
fn coredump(&self, _device: &Arc<dyn Device>) -> Result<(), SystemError> {
|
||||
Err(SystemError::EOPNOTSUPP_OR_ENOTSUP)
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
/// @brief: 获取驱动标识符
|
||||
|
@ -9,6 +9,7 @@ use crate::{
|
||||
acpi::glue::acpi_device_notify,
|
||||
base::map::{LockedDevsMap, LockedKObjMap},
|
||||
},
|
||||
exception::irqdata::IrqHandlerData,
|
||||
filesystem::{
|
||||
sysfs::{
|
||||
file::sysfs_emit_str, sysfs_instance, Attribute, AttributeGroup, SysFSOps,
|
||||
@ -875,7 +876,7 @@ impl DeviceMatcher<&str> for DeviceMatchName {
|
||||
}
|
||||
|
||||
/// Cookie to identify the device
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub struct DeviceId {
|
||||
data: Option<&'static str>,
|
||||
allocated: Option<String>,
|
||||
@ -883,7 +884,7 @@ pub struct DeviceId {
|
||||
|
||||
impl DeviceId {
|
||||
#[allow(dead_code)]
|
||||
pub fn new(data: Option<&'static str>, allocated: Option<String>) -> Option<Self> {
|
||||
pub fn new(data: Option<&'static str>, allocated: Option<String>) -> Option<Arc<Self>> {
|
||||
if data.is_none() && allocated.is_none() {
|
||||
return None;
|
||||
}
|
||||
@ -893,7 +894,7 @@ impl DeviceId {
|
||||
return None;
|
||||
}
|
||||
|
||||
return Some(Self { data, allocated });
|
||||
return Some(Arc::new(Self { data, allocated }));
|
||||
}
|
||||
|
||||
pub fn id(&self) -> Option<&str> {
|
||||
@ -904,6 +905,7 @@ impl DeviceId {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn set_allocated(&mut self, allocated: String) {
|
||||
self.allocated = Some(allocated);
|
||||
self.data = None;
|
||||
@ -915,3 +917,7 @@ impl PartialEq for DeviceId {
|
||||
return self.id() == other.id();
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for DeviceId {}
|
||||
|
||||
impl IrqHandlerData for DeviceId {}
|
||||
|
@ -1 +1,46 @@
|
||||
use bitfield_struct::bitfield;
|
||||
|
||||
pub mod ps2_device;
|
||||
|
||||
/// PS2键盘控制器的状态寄存器
|
||||
#[bitfield(u8)]
|
||||
pub struct Ps2StatusRegister {
|
||||
/// 输出缓冲区满标志
|
||||
///
|
||||
/// (必须在尝试从 IO 端口 0x60 读取数据之前设置)
|
||||
pub outbuf_full: bool,
|
||||
|
||||
/// 输入缓冲区满标志
|
||||
///
|
||||
/// (在尝试向 IO 端口 0x60 或 IO 端口 0x64 写入数据之前必须清除)
|
||||
pub inbuf_full: bool,
|
||||
|
||||
/// 系统标志
|
||||
///
|
||||
/// 如果系统通过自检 (POST),则意味着在复位时被清除并由固件设置(通过 PS/2 控制器配置字节)
|
||||
pub system_flag: bool,
|
||||
|
||||
/// 命令/数据标志
|
||||
///
|
||||
/// (0 = 写入输入缓冲区的数据是 PS/2 设备的数据,1 = 写入输入缓冲区的数据是 PS/2 控制器命令的数据)
|
||||
pub command_data: bool,
|
||||
|
||||
/// 未知标志1
|
||||
///
|
||||
/// 可能是“键盘锁”(现代系统中更可能未使用)
|
||||
pub unknown1: bool,
|
||||
|
||||
/// 未知标志2
|
||||
///
|
||||
/// 可能是“接收超时”或“第二个 PS/2 端口输出缓冲区已满”
|
||||
pub unknown2: bool,
|
||||
/// 超时错误标志
|
||||
///
|
||||
/// 超时错误(0 = 无错误,1 = 超时错误)
|
||||
pub timeout_error: bool,
|
||||
|
||||
/// 奇偶校验错误标志
|
||||
///
|
||||
/// (0 = 无错误,1 = 奇偶校验错误)
|
||||
pub parity_error: bool,
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use core::hint::spin_loop;
|
||||
use alloc::{
|
||||
string::ToString,
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use kdepends::ringbuffer::{AllocRingBuffer, RingBuffer};
|
||||
use system_error::SystemError;
|
||||
@ -637,7 +638,7 @@ impl IndexNode for Ps2MouseDevice {
|
||||
self
|
||||
}
|
||||
|
||||
fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, SystemError> {
|
||||
fn list(&self) -> Result<Vec<alloc::string::String>, SystemError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
arch::{io::PortIOArch, CurrentPortIOArch},
|
||||
driver::{
|
||||
base::{
|
||||
device::{bus::Bus, driver::Driver, Device, IdTable},
|
||||
device::{bus::Bus, driver::Driver, Device, DeviceId, IdTable},
|
||||
kobject::{KObjType, KObject, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
},
|
||||
@ -19,6 +19,12 @@ use crate::{
|
||||
serio_driver::{serio_driver_manager, SerioDriver},
|
||||
},
|
||||
},
|
||||
exception::{
|
||||
irqdata::IrqHandlerData,
|
||||
irqdesc::{IrqHandleFlags, IrqHandler, IrqReturn},
|
||||
manage::irq_manager,
|
||||
IrqNumber,
|
||||
},
|
||||
filesystem::kernfs::KernFSInode,
|
||||
init::initcall::INITCALL_DEVICE,
|
||||
libs::{
|
||||
@ -29,18 +35,30 @@ use crate::{
|
||||
|
||||
use super::ps_mouse_device::{ps2_mouse_device, Ps2MouseDevice};
|
||||
|
||||
extern "C" {
|
||||
fn c_ps2_mouse_init();
|
||||
}
|
||||
const PS2_MOUSE_IRQ_NUM: IrqNumber = IrqNumber::new(0x2c);
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn ps2_mouse_driver_interrupt() {
|
||||
if let Some(psmouse_device) = ps2_mouse_device() {
|
||||
ps2_mouse_driver()
|
||||
.interrupt(&(psmouse_device as Arc<dyn SerioDevice>), 0, 0)
|
||||
.ok();
|
||||
} else {
|
||||
unsafe { CurrentPortIOArch::in8(0x60) };
|
||||
unsafe extern "C" fn ps2_mouse_driver_interrupt() {}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Ps2MouseIrqHandler;
|
||||
|
||||
impl IrqHandler for Ps2MouseIrqHandler {
|
||||
fn handle(
|
||||
&self,
|
||||
_irq: IrqNumber,
|
||||
_static_data: Option<&dyn IrqHandlerData>,
|
||||
_dev_id: Option<Arc<dyn IrqHandlerData>>,
|
||||
) -> Result<IrqReturn, SystemError> {
|
||||
if let Some(psmouse_device) = ps2_mouse_device() {
|
||||
return Ok(ps2_mouse_driver()
|
||||
.interrupt(&(psmouse_device as Arc<dyn SerioDevice>), 0, 0)
|
||||
.map(|_| IrqReturn::Handled)
|
||||
.unwrap_or_else(|_| IrqReturn::NotHandled));
|
||||
} else {
|
||||
unsafe { CurrentPortIOArch::in8(0x60) };
|
||||
return Ok(IrqReturn::NotHandled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,7 +244,13 @@ impl SerioDriver for Ps2MouseDriver {
|
||||
device.set_driver(Some(self.inner.lock_irqsave().self_ref.clone()));
|
||||
|
||||
device.init()?;
|
||||
unsafe { c_ps2_mouse_init() };
|
||||
irq_manager().request_irq(
|
||||
PS2_MOUSE_IRQ_NUM,
|
||||
"psmouse".to_string(),
|
||||
&Ps2MouseIrqHandler,
|
||||
IrqHandleFlags::IRQF_SHARED | IrqHandleFlags::IRQF_TRIGGER_RISING,
|
||||
Some(DeviceId::new(Some(Self::NAME), None).unwrap()),
|
||||
)?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -1,10 +0,0 @@
|
||||
SRC = $(wildcard *.c)
|
||||
OBJ = $(SRC:.c=.o)
|
||||
CFLAGS += -I .
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all: $(OBJ)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
@ -1,24 +1 @@
|
||||
use crate::init::initcall::INITCALL_LATE;
|
||||
use core::ffi::c_void;
|
||||
use system_error::SystemError;
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
pub mod ps2_keyboard;
|
||||
// pub mod ps2_keyboard_inode;
|
||||
|
||||
extern "C" {
|
||||
fn ps2_keyboard_init() -> c_void;
|
||||
}
|
||||
|
||||
/// 初始化ps2键盘
|
||||
///
|
||||
/// todo: 将ps2键盘适配到设备驱动模型后,把初始化时机改为INITCALL_DEVICE
|
||||
///
|
||||
/// 当前是LATE的原因是键盘驱动的TypeOneFSM需要在tty设备初始化之后才能工作。
|
||||
#[unified_init(INITCALL_LATE)]
|
||||
fn rs_ps2_keyboard_init() -> Result<(), SystemError> {
|
||||
unsafe {
|
||||
ps2_keyboard_init();
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -1,209 +0,0 @@
|
||||
#include "ps2_keyboard.h"
|
||||
#include <arch/x86_64/driver/apic/apic.h>
|
||||
#include <mm/mm.h>
|
||||
#include <mm/slab.h>
|
||||
#include <common/printk.h>
|
||||
#include <filesystem/vfs/VFS.h>
|
||||
#include <common/spinlock.h>
|
||||
#include <common/kfifo.h>
|
||||
|
||||
// 键盘输入缓冲区
|
||||
static struct kfifo_t kb_buf;
|
||||
|
||||
extern void ps2_keyboard_register(struct vfs_file_operations_t *);
|
||||
extern void ps2_keyboard_parse_keycode(uint8_t input);
|
||||
|
||||
// 缓冲区读写锁
|
||||
static spinlock_t ps2_kb_buf_rw_lock;
|
||||
|
||||
/**
|
||||
* @brief 重置ps2键盘输入缓冲区
|
||||
*
|
||||
* @param kbp 缓冲区对象指针
|
||||
*/
|
||||
static void ps2_keyboard_reset_buffer(struct kfifo_t *kbp)
|
||||
{
|
||||
kfifo_reset(kbp);
|
||||
}
|
||||
struct apic_IO_APIC_RTE_entry entry;
|
||||
|
||||
hardware_intr_controller ps2_keyboard_intr_controller =
|
||||
{
|
||||
.enable = apic_ioapic_enable,
|
||||
.disable = apic_ioapic_disable,
|
||||
.install = apic_ioapic_install,
|
||||
.uninstall = apic_ioapic_uninstall,
|
||||
.ack = apic_ioapic_edge_ack,
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 打开键盘文件
|
||||
*
|
||||
* @param inode 所在的inode
|
||||
* @param filp 文件指针
|
||||
* @return long
|
||||
*/
|
||||
long ps2_keyboard_open(void *inode, void *filp)
|
||||
{
|
||||
ps2_keyboard_reset_buffer(&kb_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 关闭键盘文件
|
||||
*
|
||||
* @param inode 所在的inode
|
||||
* @param filp 文件指针
|
||||
* @return long
|
||||
*/
|
||||
long ps2_keyboard_close(void *inode, void *filp)
|
||||
{
|
||||
ps2_keyboard_reset_buffer(&kb_buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 键盘io控制接口
|
||||
*
|
||||
* @param inode 所在的inode
|
||||
* @param filp 键盘文件指针
|
||||
* @param cmd 命令
|
||||
* @param arg 参数
|
||||
* @return long
|
||||
*/
|
||||
long ps2_keyboard_ioctl(void *inode, void *filp, uint64_t cmd, uint64_t arg)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case KEYBOARD_CMD_RESET_BUFFER:
|
||||
ps2_keyboard_reset_buffer(&kb_buf);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取键盘文件的操作接口
|
||||
*
|
||||
* @param filp 文件指针
|
||||
* @param buf 输出缓冲区
|
||||
* @param count 要读取的字节数
|
||||
* @param position 读取的位置
|
||||
* @return long 读取的字节数
|
||||
*/
|
||||
long ps2_keyboard_read(void *filp, char *buf, int64_t count, long *position)
|
||||
{
|
||||
// 缓冲区为空则等待
|
||||
while (kfifo_empty(&kb_buf))
|
||||
;
|
||||
|
||||
count = (count > kb_buf.size) ? kb_buf.size : count;
|
||||
return kfifo_out(&kb_buf, buf, count);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 键盘文件写入接口(无作用,空)
|
||||
*
|
||||
* @param filp
|
||||
* @param buf
|
||||
* @param count
|
||||
* @param position
|
||||
* @return long
|
||||
*/
|
||||
long ps2_keyboard_write(void *filp, char *buf, int64_t count, long *position)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @brief ps2键盘驱动的虚拟文件接口
|
||||
*
|
||||
*/
|
||||
struct vfs_file_operations_t ps2_keyboard_fops =
|
||||
{
|
||||
.open = ps2_keyboard_open,
|
||||
.close = ps2_keyboard_close,
|
||||
.ioctl = ps2_keyboard_ioctl,
|
||||
.read = ps2_keyboard_read,
|
||||
.write = ps2_keyboard_write,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 键盘中断处理函数(中断上半部)
|
||||
* 将数据存入缓冲区
|
||||
* @param irq_num 中断向量号
|
||||
* @param param 参数
|
||||
* @param regs 寄存器信息
|
||||
*/
|
||||
void ps2_keyboard_handler(ul irq_num, ul buf_vaddr, struct pt_regs *regs)
|
||||
{
|
||||
unsigned char x = io_in8(PORT_PS2_KEYBOARD_DATA);
|
||||
ps2_keyboard_parse_keycode((uint8_t)x);
|
||||
}
|
||||
/**
|
||||
* @brief 初始化键盘驱动程序的函数
|
||||
*
|
||||
*/
|
||||
void ps2_keyboard_init()
|
||||
{
|
||||
|
||||
// ======= 初始化键盘循环队列缓冲区 ===========
|
||||
|
||||
// 初始化键盘循环队列缓冲区
|
||||
kfifo_alloc(&kb_buf, ps2_keyboard_buffer_size, 0);
|
||||
|
||||
// ======== 初始化中断RTE entry ==========
|
||||
|
||||
entry.vector = PS2_KEYBOARD_INTR_VECTOR; // 设置中断向量号
|
||||
entry.deliver_mode = IO_APIC_FIXED; // 投递模式:混合
|
||||
entry.dest_mode = DEST_PHYSICAL; // 物理模式投递中断
|
||||
entry.deliver_status = IDLE;
|
||||
entry.trigger_mode = EDGE_TRIGGER; // 设置边沿触发
|
||||
entry.polarity = POLARITY_HIGH; // 高电平触发
|
||||
entry.remote_IRR = IRR_RESET;
|
||||
entry.mask = MASKED;
|
||||
entry.reserved = 0;
|
||||
|
||||
entry.destination.physical.reserved1 = 0;
|
||||
entry.destination.physical.reserved2 = 0;
|
||||
entry.destination.physical.phy_dest = 0; // 设置投递到BSP处理器
|
||||
|
||||
// ======== 初始化键盘控制器,写入配置值 =========
|
||||
wait_ps2_keyboard_write();
|
||||
io_out8(PORT_PS2_KEYBOARD_CONTROL, PS2_KEYBOARD_COMMAND_WRITE);
|
||||
wait_ps2_keyboard_write();
|
||||
io_out8(PORT_PS2_KEYBOARD_DATA, PS2_KEYBOARD_PARAM_INIT);
|
||||
wait_ps2_keyboard_write();
|
||||
|
||||
// 执行一百万次nop,等待键盘控制器把命令执行完毕
|
||||
for (int i = 0; i < 1000; ++i)
|
||||
for (int j = 0; j < 1000; ++j)
|
||||
nop();
|
||||
|
||||
|
||||
// 初始化键盘缓冲区的读写锁
|
||||
spin_init(&ps2_kb_buf_rw_lock);
|
||||
|
||||
// 注册中断处理程序
|
||||
irq_register(PS2_KEYBOARD_INTR_VECTOR, &entry, &ps2_keyboard_handler, (ul)&kb_buf, &ps2_keyboard_intr_controller, "ps/2 keyboard");
|
||||
|
||||
// 先读一下键盘的数据,防止由于在键盘初始化之前,由于按键被按下从而导致接收不到中断。
|
||||
io_in8(PORT_PS2_KEYBOARD_DATA);
|
||||
// 将设备挂载到devfs
|
||||
ps2_keyboard_register(&ps2_keyboard_fops);
|
||||
|
||||
kinfo("ps/2 keyboard registered.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 键盘驱动卸载函数
|
||||
*
|
||||
*/
|
||||
void ps2_keyboard_exit()
|
||||
{
|
||||
irq_unregister(PS2_KEYBOARD_INTR_VECTOR);
|
||||
kfifo_free_alloc(&kb_buf);
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/glib.h>
|
||||
|
||||
#define PS2_KEYBOARD_INTR_VECTOR 0x21 // 键盘的中断向量号
|
||||
|
||||
// 定义键盘循环队列缓冲区大小为100bytes
|
||||
#define ps2_keyboard_buffer_size 8
|
||||
|
||||
#define KEYBOARD_CMD_RESET_BUFFER 1
|
||||
|
||||
#define PORT_PS2_KEYBOARD_DATA 0x60
|
||||
#define PORT_PS2_KEYBOARD_STATUS 0x64
|
||||
#define PORT_PS2_KEYBOARD_CONTROL 0x64
|
||||
|
||||
#define PS2_KEYBOARD_COMMAND_WRITE 0x60 // 向键盘发送配置命令
|
||||
#define PS2_KEYBOARD_COMMAND_READ 0x20 // 读取键盘的配置值
|
||||
#define PS2_KEYBOARD_PARAM_INIT 0x47 // 初始化键盘控制器的配置值
|
||||
|
||||
// ========= 检测键盘控制器输入/输出缓冲区是否已满
|
||||
#define PS2_KEYBOARD_FLAG_OUTBUF_FULL 0x01 // 键盘的输出缓冲区已满标志位
|
||||
#define PS2_KEYBOARD_FLAG_INBUF_FULL 0x02 // 键盘的输入缓冲区已满标志位
|
||||
|
||||
// 等待向键盘控制器写入信息完成
|
||||
// todo: bugfix:在不包含ps2键盘控制器的机器上,这里会卡死
|
||||
#define wait_ps2_keyboard_write() \
|
||||
while (io_in8(PORT_PS2_KEYBOARD_STATUS) & PS2_KEYBOARD_FLAG_INBUF_FULL)
|
||||
// #define wait_ps2_keyboard_write() (1)
|
||||
// 等待从键盘控制器读取信息完成
|
||||
#define wait_ps2_keyboard_read() \
|
||||
while (io_in8(PORT_PS2_KEYBOARD_STATUS) & PS2_KEYBOARD_FLAG_OUTBUF_FULL)
|
||||
// #define wait_ps2_keyboard_read() (1)
|
||||
|
||||
extern struct vfs_file_operations_t ps2_keyboard_fops;
|
||||
|
||||
/**
|
||||
* @brief 键盘驱动卸载函数
|
||||
*
|
||||
*/
|
||||
void ps2_keyboard_exit();
|
@ -1,9 +1,24 @@
|
||||
use core::{ffi::c_void, sync::atomic::AtomicI32};
|
||||
use core::hint::spin_loop;
|
||||
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use alloc::{
|
||||
string::ToString,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
use crate::{
|
||||
driver::base::device::device_number::{DeviceNumber, Major},
|
||||
arch::{io::PortIOArch, CurrentPortIOArch},
|
||||
driver::{
|
||||
base::device::device_number::{DeviceNumber, Major},
|
||||
input::ps2_dev::Ps2StatusRegister,
|
||||
},
|
||||
exception::{
|
||||
irqdata::IrqHandlerData,
|
||||
irqdesc::{IrqHandleFlags, IrqHandler, IrqReturn},
|
||||
manage::irq_manager,
|
||||
IrqNumber,
|
||||
},
|
||||
filesystem::{
|
||||
devfs::{devfs_register, DevFS, DeviceINode},
|
||||
vfs::{
|
||||
@ -11,13 +26,30 @@ use crate::{
|
||||
FileSystem, FileType, IndexNode, Metadata,
|
||||
},
|
||||
},
|
||||
include::bindings::bindings::vfs_file_operations_t,
|
||||
init::initcall::INITCALL_DEVICE,
|
||||
libs::{keyboard_parser::TypeOneFSM, rwlock::RwLock, spinlock::SpinLock},
|
||||
time::TimeSpec,
|
||||
};
|
||||
use system_error::SystemError;
|
||||
|
||||
/// PS2键盘的中断向量号
|
||||
const PS2_KEYBOARD_INTR_VECTOR: IrqNumber = IrqNumber::new(0x21);
|
||||
|
||||
const PORT_PS2_KEYBOARD_DATA: u8 = 0x60;
|
||||
const PORT_PS2_KEYBOARD_STATUS: u8 = 0x64;
|
||||
const PORT_PS2_KEYBOARD_CONTROL: u8 = 0x64;
|
||||
|
||||
/// 向键盘发送配置命令
|
||||
const PS2_KEYBOARD_COMMAND_WRITE: u8 = 0x60;
|
||||
|
||||
/// 读取键盘的配置值
|
||||
#[allow(dead_code)]
|
||||
const PS2_KEYBOARD_COMMAND_READ: u8 = 0x20;
|
||||
/// 初始化键盘控制器的配置值
|
||||
const PS2_KEYBOARD_PARAM_INIT: u8 = 0x47;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LockedPS2KeyBoardInode(RwLock<PS2KeyBoardInode>, AtomicI32); // self.1 用来记录有多少个文件打开了这个inode
|
||||
pub struct LockedPS2KeyBoardInode(RwLock<PS2KeyBoardInode>);
|
||||
|
||||
lazy_static! {
|
||||
static ref PS2_KEYBOARD_FSM: SpinLock<TypeOneFSM> = SpinLock::new(TypeOneFSM::new());
|
||||
@ -33,17 +65,14 @@ pub struct PS2KeyBoardInode {
|
||||
fs: Weak<DevFS>,
|
||||
/// INode 元数据
|
||||
metadata: Metadata,
|
||||
/// 键盘操作函数
|
||||
f_ops: vfs_file_operations_t,
|
||||
}
|
||||
|
||||
impl LockedPS2KeyBoardInode {
|
||||
pub fn new(f_ops: &vfs_file_operations_t) -> Arc<Self> {
|
||||
pub fn new() -> Arc<Self> {
|
||||
let inode = PS2KeyBoardInode {
|
||||
// uuid: Uuid::new_v5(),
|
||||
self_ref: Weak::default(),
|
||||
fs: Weak::default(),
|
||||
f_ops: f_ops.clone(), // 从引用复制一遍获取所有权
|
||||
metadata: Metadata {
|
||||
dev_id: 1,
|
||||
inode_id: generate_inode_id(),
|
||||
@ -62,10 +91,7 @@ impl LockedPS2KeyBoardInode {
|
||||
},
|
||||
};
|
||||
|
||||
let result = Arc::new(LockedPS2KeyBoardInode(
|
||||
RwLock::new(inode),
|
||||
AtomicI32::new(0),
|
||||
));
|
||||
let result = Arc::new(LockedPS2KeyBoardInode(RwLock::new(inode)));
|
||||
result.0.write().self_ref = Arc::downgrade(&result);
|
||||
|
||||
return result;
|
||||
@ -78,9 +104,8 @@ impl DeviceINode for LockedPS2KeyBoardInode {
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle] // 不重命名
|
||||
pub extern "C" fn ps2_keyboard_register(f_ops: &vfs_file_operations_t) {
|
||||
devfs_register("ps2_keyboard", LockedPS2KeyBoardInode::new(f_ops))
|
||||
fn ps2_keyboard_register() {
|
||||
devfs_register("ps2_keyboard", LockedPS2KeyBoardInode::new())
|
||||
.expect("Failed to register ps/2 keyboard");
|
||||
}
|
||||
|
||||
@ -88,21 +113,11 @@ impl IndexNode for LockedPS2KeyBoardInode {
|
||||
fn read_at(
|
||||
&self,
|
||||
_offset: usize,
|
||||
len: usize,
|
||||
buf: &mut [u8],
|
||||
_len: usize,
|
||||
_buf: &mut [u8],
|
||||
_data: &mut FilePrivateData,
|
||||
) -> Result<usize, SystemError> {
|
||||
let guard = self.0.read();
|
||||
let func = guard.f_ops.read.unwrap();
|
||||
let r = unsafe {
|
||||
func(
|
||||
0 as *mut c_void,
|
||||
&mut buf[0..len] as *mut [u8] as *mut i8,
|
||||
len as i64,
|
||||
0 as *mut i64,
|
||||
)
|
||||
};
|
||||
return Ok(r as usize);
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
@ -112,28 +127,14 @@ impl IndexNode for LockedPS2KeyBoardInode {
|
||||
_buf: &[u8],
|
||||
_data: &mut FilePrivateData,
|
||||
) -> Result<usize, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
fn open(&self, _data: &mut FilePrivateData, _mode: &FileMode) -> Result<(), SystemError> {
|
||||
let prev_ref_count = self.1.fetch_add(1, core::sync::atomic::Ordering::SeqCst);
|
||||
if prev_ref_count == 0 {
|
||||
// 第一次打开,需要初始化
|
||||
let guard = self.0.write();
|
||||
let func = guard.f_ops.open.unwrap();
|
||||
let _ = unsafe { func(0 as *mut c_void, 0 as *mut c_void) };
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> {
|
||||
let prev_ref_count = self.1.fetch_sub(1, core::sync::atomic::Ordering::SeqCst);
|
||||
if prev_ref_count == 1 {
|
||||
// 最后一次关闭,需要释放
|
||||
let guard = self.0.write();
|
||||
let func = guard.f_ops.close.unwrap();
|
||||
let _ = unsafe { func(0 as *mut c_void, 0 as *mut c_void) };
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@ -166,9 +167,85 @@ impl IndexNode for LockedPS2KeyBoardInode {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[no_mangle]
|
||||
/// for test
|
||||
pub extern "C" fn ps2_keyboard_parse_keycode(input: u8) {
|
||||
PS2_KEYBOARD_FSM.lock().parse(input);
|
||||
#[derive(Debug)]
|
||||
struct Ps2KeyboardIrqHandler;
|
||||
|
||||
impl IrqHandler for Ps2KeyboardIrqHandler {
|
||||
fn handle(
|
||||
&self,
|
||||
_irq: IrqNumber,
|
||||
_static_data: Option<&dyn IrqHandlerData>,
|
||||
_dev_id: Option<Arc<dyn IrqHandlerData>>,
|
||||
) -> Result<IrqReturn, SystemError> {
|
||||
// 先检查状态寄存器,看看是否有数据
|
||||
let status = unsafe { CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_STATUS.into()) };
|
||||
let status = Ps2StatusRegister::from(status);
|
||||
if !status.outbuf_full() {
|
||||
return Ok(IrqReturn::NotHandled);
|
||||
}
|
||||
|
||||
let input = unsafe { CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_DATA.into()) };
|
||||
// wait_ps2_keyboard_read();
|
||||
PS2_KEYBOARD_FSM.lock().parse(input);
|
||||
|
||||
return Ok(IrqReturn::Handled);
|
||||
}
|
||||
}
|
||||
|
||||
impl Ps2KeyboardIrqHandler {
|
||||
const INTR_HANDLE_FLAGS: IrqHandleFlags =
|
||||
IrqHandleFlags::from_bits_truncate(IrqHandleFlags::IRQF_TRIGGER_RISING.bits());
|
||||
}
|
||||
|
||||
/// 等待 PS/2 键盘的输入缓冲区为空
|
||||
fn wait_ps2_keyboard_write() {
|
||||
let mut status: Ps2StatusRegister;
|
||||
loop {
|
||||
status = Ps2StatusRegister::from(unsafe {
|
||||
CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_STATUS.into())
|
||||
});
|
||||
if !status.inbuf_full() {
|
||||
break;
|
||||
}
|
||||
|
||||
spin_loop();
|
||||
}
|
||||
}
|
||||
#[unified_init(INITCALL_DEVICE)]
|
||||
fn ps2_keyboard_init() -> Result<(), SystemError> {
|
||||
// ======== 初始化键盘控制器,写入配置值 =========
|
||||
wait_ps2_keyboard_write();
|
||||
unsafe {
|
||||
CurrentPortIOArch::out8(PORT_PS2_KEYBOARD_CONTROL.into(), PS2_KEYBOARD_COMMAND_WRITE);
|
||||
wait_ps2_keyboard_write();
|
||||
CurrentPortIOArch::out8(PORT_PS2_KEYBOARD_DATA.into(), PS2_KEYBOARD_PARAM_INIT);
|
||||
wait_ps2_keyboard_write();
|
||||
}
|
||||
|
||||
// 执行一百万次nop,等待键盘控制器把命令执行完毕
|
||||
for _ in 0..1000000 {
|
||||
spin_loop();
|
||||
}
|
||||
|
||||
irq_manager()
|
||||
.request_irq(
|
||||
PS2_KEYBOARD_INTR_VECTOR,
|
||||
"ps2keyboard".to_string(),
|
||||
&Ps2KeyboardIrqHandler,
|
||||
Ps2KeyboardIrqHandler::INTR_HANDLE_FLAGS,
|
||||
None,
|
||||
)
|
||||
.expect("Failed to request irq for ps2 keyboard");
|
||||
|
||||
// 先读一下键盘的数据,防止由于在键盘初始化之前,由于按键被按下从而导致接收不到中断。
|
||||
let status = unsafe { CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_STATUS.into()) };
|
||||
let status = Ps2StatusRegister::from(status);
|
||||
if status.outbuf_full() {
|
||||
unsafe { CurrentPortIOArch::in8(PORT_PS2_KEYBOARD_DATA.into()) };
|
||||
}
|
||||
|
||||
// 将设备挂载到devfs
|
||||
ps2_keyboard_register();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,10 +0,0 @@
|
||||
SRC = $(wildcard *.c)
|
||||
OBJ = $(SRC:.c=.o)
|
||||
CFLAGS += -I .
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all: $(OBJ)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
@ -1,58 +0,0 @@
|
||||
#include "ps2_mouse.h"
|
||||
#include <arch/x86_64/driver/apic/apic.h>
|
||||
#include <mm/mm.h>
|
||||
#include <mm/slab.h>
|
||||
#include <common/printk.h>
|
||||
#include <common/kprint.h>
|
||||
|
||||
extern void ps2_mouse_driver_interrupt();
|
||||
|
||||
/**
|
||||
* @brief 鼠标中断处理函数(中断上半部)
|
||||
* 将数据存入缓冲区
|
||||
* @param irq_num 中断向量号
|
||||
* @param param 参数
|
||||
* @param regs 寄存器信息
|
||||
*/
|
||||
void ps2_mouse_handler(ul irq_num, ul param, struct pt_regs *regs)
|
||||
{
|
||||
ps2_mouse_driver_interrupt();
|
||||
}
|
||||
|
||||
struct apic_IO_APIC_RTE_entry ps2_mouse_entry;
|
||||
|
||||
hardware_intr_controller ps2_mouse_intr_controller =
|
||||
{
|
||||
.enable = apic_ioapic_enable,
|
||||
.disable = apic_ioapic_disable,
|
||||
.install = apic_ioapic_install,
|
||||
.uninstall = apic_ioapic_uninstall,
|
||||
.ack = apic_ioapic_edge_ack,
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 初始化鼠标驱动程序
|
||||
*
|
||||
*/
|
||||
void c_ps2_mouse_init()
|
||||
{
|
||||
// ======== 初始化中断RTE entry ==========
|
||||
|
||||
ps2_mouse_entry.vector = PS2_MOUSE_INTR_VECTOR; // 设置中断向量号
|
||||
ps2_mouse_entry.deliver_mode = IO_APIC_FIXED; // 投递模式:混合
|
||||
ps2_mouse_entry.dest_mode = DEST_PHYSICAL; // 物理模式投递中断
|
||||
ps2_mouse_entry.deliver_status = IDLE;
|
||||
ps2_mouse_entry.trigger_mode = EDGE_TRIGGER; // 设置边沿触发
|
||||
ps2_mouse_entry.polarity = POLARITY_HIGH; // 高电平触发
|
||||
ps2_mouse_entry.remote_IRR = IRR_RESET;
|
||||
ps2_mouse_entry.mask = MASKED;
|
||||
ps2_mouse_entry.reserved = 0;
|
||||
|
||||
ps2_mouse_entry.destination.physical.reserved1 = 0;
|
||||
ps2_mouse_entry.destination.physical.reserved2 = 0;
|
||||
ps2_mouse_entry.destination.physical.phy_dest = 0; // 设置投递到BSP处理器
|
||||
|
||||
// 注册中断处理程序
|
||||
irq_register(PS2_MOUSE_INTR_VECTOR, &ps2_mouse_entry, &ps2_mouse_handler, 0, &ps2_mouse_intr_controller, "ps/2 mouse");
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/glib.h>
|
||||
|
||||
#define PS2_MOUSE_INTR_VECTOR 0x2c // 鼠标的中断向量号
|
||||
|
||||
#define KEYBOARD_COMMAND_SEND_TO_PS2_MOUSE 0xd4 // 键盘控制器向鼠标设备发送数据的命令
|
||||
|
||||
#define PS2_MOUSE_GET_ID 0xf2 // 获取鼠标的ID
|
||||
#define PS2_MOUSE_SET_SAMPLING_RATE 0xf3 // 设置鼠标的采样率
|
||||
#define PS2_MOUSE_ENABLE 0xf4 // 允许鼠标设备发送数据包
|
||||
#define PS2_MOUSE_DISABLE 0xf5 // 禁止鼠标设备发送数据包
|
||||
#define PS2_MOUSE_SET_DEFAULT_SAMPLING_RATE 0xf6 // 设置使用默认采样率100hz,分辨率4px/mm
|
||||
#define PS2_MOUSE_RESEND_LAST_PACKET 0xfe // 重新发送上一条数据包
|
||||
#define PS2_MOUSE_RESET 0xff // 重启鼠标
|
||||
|
||||
#define KEYBOARD_COMMAND_ENABLE_PS2_MOUSE_PORT 0xa8 // 通过键盘控制器开启鼠标端口的命令
|
||||
|
||||
#define ps2_mouse_buffer_size 360
|
||||
|
||||
#define PORT_KEYBOARD_DATA 0x60
|
||||
#define PORT_KEYBOARD_STATUS 0x64
|
||||
#define PORT_KEYBOARD_CONTROL 0x64
|
||||
|
||||
#define KEYBOARD_COMMAND_WRITE 0x60 // 向键盘发送配置命令
|
||||
#define KEYBOARD_COMMAND_READ 0x20 // 读取键盘的配置值
|
||||
#define KEYBOARD_PARAM_INIT 0x47 // 初始化键盘控制器的配置值
|
||||
|
||||
// ========= 检测键盘控制器输入/输出缓冲区是否已满
|
||||
#define KEYBOARD_FLAG_OUTBUF_FULL 0x01 // 键盘的输出缓冲区已满标志位
|
||||
#define KEYBOARD_FLAG_INBUF_FULL 0x02 // 键盘的输入缓冲区已满标志位
|
||||
|
||||
|
||||
/**
|
||||
* @brief 初始化鼠标驱动程序
|
||||
*
|
||||
*/
|
||||
void c_ps2_mouse_init();
|
@ -1,6 +1,8 @@
|
||||
// 参考手册: PCIe* GbE Controllers Open Source Software Developer’s Manual
|
||||
// Refernce: PCIe* GbE Controllers Open Source Software Developer’s Manual
|
||||
|
||||
use alloc::string::ToString;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use core::intrinsics::unlikely;
|
||||
use core::mem::size_of;
|
||||
@ -9,15 +11,18 @@ use core::slice::{from_raw_parts, from_raw_parts_mut};
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
use super::e1000e_driver::e1000e_driver_init;
|
||||
use crate::driver::base::device::DeviceId;
|
||||
use crate::driver::net::dma::{dma_alloc, dma_dealloc};
|
||||
use crate::driver::net::irq_handle::DefaultNetIrqHandler;
|
||||
use crate::driver::pci::pci::{
|
||||
get_pci_device_structure_mut, PciDeviceStructure, PciDeviceStructureGeneralDevice, PciError,
|
||||
PCI_DEVICE_LINKEDLIST,
|
||||
};
|
||||
use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqMsg, IRQ};
|
||||
use crate::include::bindings::bindings::pt_regs;
|
||||
use crate::exception::IrqNumber;
|
||||
|
||||
use crate::libs::volatile::{ReadOnly, Volatile, WriteOnly};
|
||||
use crate::net::net_core::poll_ifaces_try_lock_onetime;
|
||||
|
||||
use crate::{kdebug, kinfo};
|
||||
|
||||
const PAGE_SIZE: usize = 4096;
|
||||
@ -55,7 +60,7 @@ const E1000E_REG_SIZE: u8 = 4;
|
||||
const E1000E_DMA_PAGES: usize = 1;
|
||||
|
||||
// 中断相关
|
||||
const E1000E_RECV_VECTOR: u16 = 57;
|
||||
const E1000E_RECV_VECTOR: IrqNumber = IrqNumber::new(57);
|
||||
|
||||
// napi队列中暂时存储的buffer个数
|
||||
const E1000E_RECV_NAPI: usize = 1024;
|
||||
@ -157,12 +162,6 @@ impl E1000EBuffer {
|
||||
}
|
||||
}
|
||||
|
||||
// 中断处理函数, 调用协议栈的poll函数,未来可能会用napi来替换这里
|
||||
// Interrupt handler
|
||||
unsafe extern "C" fn e1000e_irq_handler(_irq_num: u64, _irq_paramer: u64, _regs: *mut pt_regs) {
|
||||
poll_ifaces_try_lock_onetime().ok();
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct E1000EDevice {
|
||||
// 设备寄存器
|
||||
@ -201,7 +200,10 @@ impl E1000EDevice {
|
||||
// 从PCI标准设备进行驱动初始化
|
||||
// init the device for PCI standard device struct
|
||||
#[allow(unused_assignments)]
|
||||
pub fn new(device: &mut PciDeviceStructureGeneralDevice) -> Result<Self, E1000EPciError> {
|
||||
pub fn new(
|
||||
device: &mut PciDeviceStructureGeneralDevice,
|
||||
device_id: Arc<DeviceId>,
|
||||
) -> Result<Self, E1000EPciError> {
|
||||
// 从BAR0获取我们需要的寄存器
|
||||
// Build registers sturcts from BAR0
|
||||
device.bar_ioremap().unwrap()?;
|
||||
@ -230,10 +232,9 @@ impl E1000EDevice {
|
||||
let msg = PciIrqMsg {
|
||||
irq_common_message: IrqCommonMsg::init_from(
|
||||
0,
|
||||
"E1000E_RECV_IRQ",
|
||||
0,
|
||||
e1000e_irq_handler,
|
||||
None,
|
||||
"E1000E_RECV_IRQ".to_string(),
|
||||
&DefaultNetIrqHandler,
|
||||
device_id,
|
||||
),
|
||||
irq_specific_message: IrqSpecificMsg::msi_default(),
|
||||
};
|
||||
@ -619,7 +620,12 @@ pub fn e1000e_probe() -> Result<u64, E1000EPciError> {
|
||||
"Detected e1000e PCI device with device id {:#x}",
|
||||
header.device_id
|
||||
);
|
||||
let e1000e = E1000EDevice::new(standard_device)?;
|
||||
|
||||
// todo: 根据pci的path来生成device id
|
||||
let e1000e = E1000EDevice::new(
|
||||
standard_device,
|
||||
DeviceId::new(None, Some(format!("e1000e_{}", header.device_id))).unwrap(),
|
||||
)?;
|
||||
e1000e_driver_init(e1000e);
|
||||
}
|
||||
}
|
||||
|
27
kernel/src/driver/net/irq_handle.rs
Normal file
27
kernel/src/driver/net/irq_handle.rs
Normal file
@ -0,0 +1,27 @@
|
||||
use alloc::sync::Arc;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
exception::{
|
||||
irqdata::IrqHandlerData,
|
||||
irqdesc::{IrqHandler, IrqReturn},
|
||||
IrqNumber,
|
||||
},
|
||||
net::net_core::poll_ifaces_try_lock_onetime,
|
||||
};
|
||||
|
||||
/// 默认的网卡中断处理函数
|
||||
#[derive(Debug)]
|
||||
pub struct DefaultNetIrqHandler;
|
||||
|
||||
impl IrqHandler for DefaultNetIrqHandler {
|
||||
fn handle(
|
||||
&self,
|
||||
_irq: IrqNumber,
|
||||
_static_data: Option<&dyn IrqHandlerData>,
|
||||
_dynamic_data: Option<Arc<dyn IrqHandlerData>>,
|
||||
) -> Result<IrqReturn, SystemError> {
|
||||
poll_ifaces_try_lock_onetime().ok();
|
||||
Ok(IrqReturn::Handled)
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ use system_error::SystemError;
|
||||
|
||||
mod dma;
|
||||
pub mod e1000e;
|
||||
pub mod irq_handle;
|
||||
pub mod virtio_net;
|
||||
|
||||
pub trait NetDriver: Driver {
|
||||
|
@ -15,14 +15,15 @@ use super::NetDriver;
|
||||
use crate::{
|
||||
driver::{
|
||||
base::{
|
||||
device::{bus::Bus, driver::Driver, Device, IdTable},
|
||||
device::{bus::Bus, driver::Driver, Device, DeviceId, IdTable},
|
||||
kobject::{KObjType, KObject, KObjectState},
|
||||
},
|
||||
virtio::virtio_impl::HalImpl,
|
||||
virtio::{irq::virtio_irq_manager, virtio_impl::HalImpl, VirtIODevice},
|
||||
},
|
||||
exception::{irqdesc::IrqReturn, IrqNumber},
|
||||
kerror, kinfo,
|
||||
libs::spinlock::SpinLock,
|
||||
net::{generate_iface_id, NET_DRIVERS},
|
||||
net::{generate_iface_id, net_core::poll_ifaces_try_lock_onetime, NET_DRIVERS},
|
||||
time::Instant,
|
||||
};
|
||||
use system_error::SystemError;
|
||||
@ -40,7 +41,8 @@ impl<T: Transport> Clone for VirtioNICDriver<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 网卡驱动的包裹器,这是为了获取网卡驱动的可变引用而设计的。
|
||||
/// 网卡驱动的包裹器,这是为了获取网卡驱动的可变引用而设计的。
|
||||
///
|
||||
/// 由于smoltcp的设计,导致需要在poll的时候获取网卡驱动的可变引用,
|
||||
/// 同时需要在token的consume里面获取可变引用。为了避免双重加锁,所以需要这个包裹器。
|
||||
struct VirtioNICDriverWrapper<T: Transport>(UnsafeCell<VirtioNICDriver<T>>);
|
||||
@ -76,6 +78,7 @@ pub struct VirtioInterface<T: Transport> {
|
||||
iface_id: usize,
|
||||
iface: SpinLock<smoltcp::iface::Interface>,
|
||||
name: String,
|
||||
dev_id: Arc<DeviceId>,
|
||||
}
|
||||
|
||||
impl<T: Transport> Debug for VirtioInterface<T> {
|
||||
@ -90,7 +93,7 @@ impl<T: Transport> Debug for VirtioInterface<T> {
|
||||
}
|
||||
|
||||
impl<T: Transport> VirtioInterface<T> {
|
||||
pub fn new(mut driver: VirtioNICDriver<T>) -> Arc<Self> {
|
||||
pub fn new(mut driver: VirtioNICDriver<T>, dev_id: Arc<DeviceId>) -> Arc<Self> {
|
||||
let iface_id = generate_iface_id();
|
||||
let mut iface_config = smoltcp::iface::Config::new();
|
||||
|
||||
@ -109,12 +112,31 @@ impl<T: Transport> VirtioInterface<T> {
|
||||
iface_id,
|
||||
iface: SpinLock::new(iface),
|
||||
name: format!("eth{}", iface_id),
|
||||
dev_id,
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Transport + 'static> VirtIODevice for VirtioInterface<T> {
|
||||
fn handle_irq(&self, _irq: IrqNumber) -> Result<IrqReturn, SystemError> {
|
||||
poll_ifaces_try_lock_onetime().ok();
|
||||
return Ok(IrqReturn::Handled);
|
||||
}
|
||||
|
||||
fn dev_id(&self) -> &Arc<DeviceId> {
|
||||
return &self.dev_id;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Transport> Drop for VirtioInterface<T> {
|
||||
fn drop(&mut self) {
|
||||
// 从全局的网卡接口信息表中删除这个网卡的接口信息
|
||||
NET_DRIVERS.write_irqsave().remove(&self.iface_id);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static + Transport> VirtioNICDriver<T> {
|
||||
pub fn new(driver_net: VirtIONet<HalImpl, T, 2>) -> Self {
|
||||
let mut iface_config = smoltcp::iface::Config::new();
|
||||
@ -223,7 +245,7 @@ impl<T: Transport> phy::RxToken for VirtioNetToken<T> {
|
||||
}
|
||||
|
||||
/// @brief virtio-net 驱动的初始化与测试
|
||||
pub fn virtio_net<T: Transport + 'static>(transport: T) {
|
||||
pub fn virtio_net<T: Transport + 'static>(transport: T, dev_id: Arc<DeviceId>) {
|
||||
let driver_net: VirtIONet<HalImpl, T, 2> =
|
||||
match VirtIONet::<HalImpl, T, 2>::new(transport, 4096) {
|
||||
Ok(net) => net,
|
||||
@ -234,12 +256,16 @@ pub fn virtio_net<T: Transport + 'static>(transport: T) {
|
||||
};
|
||||
let mac = smoltcp::wire::EthernetAddress::from_bytes(&driver_net.mac_address());
|
||||
let driver: VirtioNICDriver<T> = VirtioNICDriver::new(driver_net);
|
||||
let iface = VirtioInterface::new(driver);
|
||||
let iface = VirtioInterface::new(driver, dev_id);
|
||||
let name = iface.name.clone();
|
||||
// 将网卡的接口信息注册到全局的网卡接口信息表中
|
||||
NET_DRIVERS
|
||||
.write_irqsave()
|
||||
.insert(iface.nic_id(), iface.clone());
|
||||
|
||||
virtio_irq_manager()
|
||||
.register_device(iface.clone())
|
||||
.expect("Register virtio net failed");
|
||||
kinfo!(
|
||||
"Virtio-net driver init successfully!\tNetDevID: [{}], MAC: [{}]",
|
||||
name,
|
||||
|
@ -1,11 +0,0 @@
|
||||
SRC = $(wildcard *.c)
|
||||
OBJ = $(SRC:.c=.o)
|
||||
CFLAGS += -I .
|
||||
|
||||
.PHONY: all
|
||||
|
||||
all: $(OBJ)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
use super::pci_irq::{IrqType, PciIrqError};
|
||||
use crate::arch::{PciArch, TraitPciArch};
|
||||
use crate::exception::IrqNumber;
|
||||
use crate::include::bindings::bindings::PAGE_2M_SIZE;
|
||||
use crate::libs::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
|
||||
@ -371,7 +372,7 @@ pub trait PciDeviceStructure: Send + Sync {
|
||||
/// @brief 返回结构体中的irq_type的可变引用
|
||||
fn irq_type_mut(&mut self) -> Option<&mut IrqType>;
|
||||
/// @brief 返回结构体中的irq_vector的可变引用
|
||||
fn irq_vector_mut(&mut self) -> Option<&mut Vec<u16>>;
|
||||
fn irq_vector_mut(&mut self) -> Option<&mut Vec<IrqNumber>>;
|
||||
}
|
||||
|
||||
/// Pci_Device_Structure_Header PCI设备结构体共有的头部
|
||||
@ -404,7 +405,7 @@ pub struct PciDeviceStructureGeneralDevice {
|
||||
// 中断结构体,包括legacy,msi,msix三种情况
|
||||
pub irq_type: IrqType,
|
||||
// 使用的中断号的vec集合
|
||||
pub irq_vector: Vec<u16>,
|
||||
pub irq_vector: Vec<IrqNumber>,
|
||||
pub standard_device_bar: PciStandardDeviceBar,
|
||||
pub cardbus_cis_pointer: u32, // 指向卡信息结构,供在 CardBus 和 PCI 之间共享芯片的设备使用。
|
||||
pub subsystem_vendor_id: u16,
|
||||
@ -464,7 +465,7 @@ impl PciDeviceStructure for PciDeviceStructureGeneralDevice {
|
||||
Some(&mut self.irq_type)
|
||||
}
|
||||
#[inline(always)]
|
||||
fn irq_vector_mut(&mut self) -> Option<&mut Vec<u16>> {
|
||||
fn irq_vector_mut(&mut self) -> Option<&mut Vec<IrqNumber>> {
|
||||
Some(&mut self.irq_vector)
|
||||
}
|
||||
}
|
||||
@ -476,7 +477,7 @@ pub struct PciDeviceStructurePciToPciBridge {
|
||||
// 中断结构体,包括legacy,msi,msix三种情况
|
||||
pub irq_type: IrqType,
|
||||
// 使用的中断号的vec集合
|
||||
pub irq_vector: Vec<u16>,
|
||||
pub irq_vector: Vec<IrqNumber>,
|
||||
pub bar0: u32,
|
||||
pub bar1: u32,
|
||||
pub primary_bus_number: u8,
|
||||
@ -528,7 +529,7 @@ impl PciDeviceStructure for PciDeviceStructurePciToPciBridge {
|
||||
Some(&mut self.irq_type)
|
||||
}
|
||||
#[inline(always)]
|
||||
fn irq_vector_mut(&mut self) -> Option<&mut Vec<u16>> {
|
||||
fn irq_vector_mut(&mut self) -> Option<&mut Vec<IrqNumber>> {
|
||||
Some(&mut self.irq_vector)
|
||||
}
|
||||
}
|
||||
@ -587,7 +588,7 @@ impl PciDeviceStructure for PciDeviceStructurePciToCardbusBridge {
|
||||
None
|
||||
}
|
||||
#[inline(always)]
|
||||
fn irq_vector_mut(&mut self) -> Option<&mut Vec<u16>> {
|
||||
fn irq_vector_mut(&mut self) -> Option<&mut Vec<IrqNumber>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -1,95 +0,0 @@
|
||||
#include "pci_irq.h"
|
||||
#include "exception/irq.h"
|
||||
#include <common/errno.h>
|
||||
#include <common/kprint.h>
|
||||
#include "common/string.h"
|
||||
#include "mm/slab.h"
|
||||
|
||||
// 现在pci设备的中断由自己进行控制,这些不执行内容的函数是为了适配旧的中断处理机制
|
||||
void pci_irq_enable(ul irq_num)
|
||||
{
|
||||
}
|
||||
void pci_irq_disable(ul irq_num)
|
||||
{
|
||||
}
|
||||
ul pci_irq_install(ul num , void* data)
|
||||
{
|
||||
}
|
||||
void pci_irq_uninstall(ul irq_num)
|
||||
{
|
||||
}
|
||||
/// @brief 与本操作系统的中断机制进行交互,把中断处理函数等注册到中断结构体中(被rust调用)
|
||||
/// @param irq_num 要进行注册的中断号
|
||||
/// @param pci_irq_handler 对应的中断处理函数
|
||||
/// @param parameter 中断处理函数传入参数
|
||||
/// @param irq_name 中断名字
|
||||
/// @param pci_irq_ack 对于中断的回复,为NULL时会使用默认回应
|
||||
uint16_t c_irq_install(ul irq_num, void (*pci_irq_handler)(ul irq_num, ul parameter, struct pt_regs *regs), ul parameter, const char *irq_name, void (*pci_irq_ack)(ul irq_num))
|
||||
{
|
||||
// 由于为I/O APIC分配的中断向量号是从32开始的,因此要减去32才是对应的interrupt_desc的元素
|
||||
irq_desc_t *p = NULL;
|
||||
hardware_intr_controller *pci_interrupt_controller = NULL;
|
||||
if (irq_num >= 32 && irq_num < 0x80)
|
||||
p = &interrupt_desc[irq_num - 32];
|
||||
else if (irq_num >= 150 && irq_num < 200)
|
||||
p = &local_apic_interrupt_desc[irq_num - 150];
|
||||
else
|
||||
{
|
||||
// kerror("irq install for pci irq: invalid irq num: %ld.", irq_num);
|
||||
return EINVAL;
|
||||
}
|
||||
if (p->irq_name != NULL)
|
||||
{
|
||||
return EAGAIN;
|
||||
}
|
||||
pci_interrupt_controller = kzalloc(sizeof(hardware_intr_controller), 0);
|
||||
if (pci_interrupt_controller)
|
||||
{
|
||||
pci_interrupt_controller->enable = pci_irq_enable;
|
||||
pci_interrupt_controller->disable = pci_irq_disable;
|
||||
pci_interrupt_controller->install = pci_irq_install;
|
||||
pci_interrupt_controller->uninstall = pci_irq_uninstall;
|
||||
pci_interrupt_controller->ack = pci_irq_ack;
|
||||
p->controller = pci_interrupt_controller;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EAGAIN;
|
||||
}
|
||||
size_t namelen = strlen(irq_name) + 1;
|
||||
p->irq_name = (char *)kzalloc(namelen, 0);
|
||||
memset(p->irq_name, 0, namelen);
|
||||
strncpy(p->irq_name, irq_name, namelen);
|
||||
p->parameter = parameter;
|
||||
p->flags = 0;
|
||||
p->handler = pci_irq_handler;
|
||||
return 0;
|
||||
};
|
||||
|
||||
/// @brief 与本操作系统的中断机制进行交互,把中断处理函数等从中断结构体中移除,需要释放空间的进行空间的释放
|
||||
/// @param irq_num 要进行注销的中断号
|
||||
void c_irq_uninstall(ul irq_num)
|
||||
{
|
||||
// 由于为I/O APIC分配的中断向量号是从32开始的,因此要减去32才是对应的interrupt_desc的元素
|
||||
irq_desc_t *p = NULL;
|
||||
if (irq_num >= 32 && irq_num < 0x80)
|
||||
p = &interrupt_desc[irq_num - 32];
|
||||
else if (irq_num >= 150 && irq_num < 200)
|
||||
p = &local_apic_interrupt_desc[irq_num - 150];
|
||||
else
|
||||
{
|
||||
kerror("irq install for pci irq: invalid irq num: %ld.", irq_num);
|
||||
}
|
||||
if (p->irq_name != NULL)
|
||||
{
|
||||
kfree(p->irq_name);
|
||||
p->irq_name = NULL;
|
||||
}
|
||||
if (p->controller != NULL)
|
||||
{
|
||||
kfree(p->controller);
|
||||
p->controller = NULL;
|
||||
}
|
||||
p->parameter = 0;
|
||||
p->handler = NULL;
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
#include <common/glib.h>
|
||||
#include <process/ptrace.h>
|
||||
uint16_t c_irq_install(ul irq_num,void (*pci_irq_handler)(ul irq_num, ul parameter, struct pt_regs *regs),ul parameter,const char *irq_name,void (*pci_irq_ack)(ul irq_num));
|
||||
void c_irq_uninstall(ul irq_num);
|
@ -3,16 +3,19 @@
|
||||
use core::mem::size_of;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
use alloc::ffi::CString;
|
||||
use alloc::string::String;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use system_error::SystemError;
|
||||
|
||||
use super::pci::{PciDeviceStructure, PciDeviceStructureGeneralDevice, PciError};
|
||||
use crate::arch::msi::{arch_msi_message_address, arch_msi_message_data};
|
||||
use crate::arch::{PciArch, TraitPciArch};
|
||||
use crate::include::bindings::bindings::{
|
||||
c_irq_install, c_irq_uninstall, pt_regs, ul, EAGAIN, EINVAL,
|
||||
};
|
||||
|
||||
use crate::driver::base::device::DeviceId;
|
||||
use crate::exception::irqdesc::{IrqHandleFlags, IrqHandler};
|
||||
use crate::exception::manage::irq_manager;
|
||||
use crate::exception::IrqNumber;
|
||||
use crate::libs::volatile::{volread, volwrite, Volatile};
|
||||
|
||||
/// MSIX表的一项
|
||||
@ -37,8 +40,8 @@ pub enum PciIrqError {
|
||||
PciDeviceNotSupportIrq,
|
||||
IrqTypeUnmatch,
|
||||
InvalidIrqIndex(u16),
|
||||
InvalidIrqNum(u16),
|
||||
IrqNumOccupied(u16),
|
||||
InvalidIrqNum(IrqNumber),
|
||||
IrqNumOccupied(IrqNumber),
|
||||
DeviceIrqOverflow,
|
||||
MxiIrqNumWrong,
|
||||
PciBarNotInited,
|
||||
@ -78,29 +81,35 @@ pub struct PciIrqMsg {
|
||||
// PCI设备install中断时需要传递的共同参数
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IrqCommonMsg {
|
||||
irq_index: u16, //要install的中断号在PCI设备中的irq_vector的index
|
||||
irq_name: CString, //中断名字
|
||||
irq_parameter: u16, //中断额外参数,可传入中断处理函数
|
||||
irq_hander: unsafe extern "C" fn(irq_num: ul, parameter: ul, regs: *mut pt_regs), // 中断处理函数
|
||||
irq_ack: Option<unsafe extern "C" fn(irq_num: ul)>, // 中断的ack,可为None,若为None则中断处理中会正常通知中断结束,不为None则调用传入的函数进行回复
|
||||
irq_index: u16, //要install的中断号在PCI设备中的irq_vector的index
|
||||
irq_name: String, //中断名字
|
||||
irq_hander: &'static dyn IrqHandler, // 中断处理函数
|
||||
/// 全局设备标志符
|
||||
dev_id: Arc<DeviceId>,
|
||||
}
|
||||
|
||||
impl IrqCommonMsg {
|
||||
pub fn init_from(
|
||||
irq_index: u16,
|
||||
irq_name: &str,
|
||||
irq_parameter: u16,
|
||||
irq_hander: unsafe extern "C" fn(irq_num: ul, parameter: ul, regs: *mut pt_regs),
|
||||
irq_ack: Option<unsafe extern "C" fn(irq_num: ul)>,
|
||||
irq_name: String,
|
||||
irq_hander: &'static dyn IrqHandler,
|
||||
dev_id: Arc<DeviceId>,
|
||||
) -> Self {
|
||||
IrqCommonMsg {
|
||||
irq_index,
|
||||
irq_name: CString::new(irq_name).expect("CString::new failed"),
|
||||
irq_parameter,
|
||||
irq_name,
|
||||
irq_hander,
|
||||
irq_ack,
|
||||
dev_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_handler(&mut self, irq_hander: &'static dyn IrqHandler) {
|
||||
self.irq_hander = irq_hander;
|
||||
}
|
||||
|
||||
pub fn dev_id(&self) -> &Arc<DeviceId> {
|
||||
&self.dev_id
|
||||
}
|
||||
}
|
||||
|
||||
// PCI设备install中断时需要传递的特有参数,Msi代表MSI与MSIX
|
||||
@ -347,28 +356,43 @@ pub trait PciInterrupt: PciDeviceStructure {
|
||||
}
|
||||
let irq_num =
|
||||
self.irq_vector_mut().unwrap()[msg.irq_common_message.irq_index as usize];
|
||||
|
||||
let irq_num = IrqNumber::new(irq_num.into());
|
||||
let common_msg = &msg.irq_common_message;
|
||||
let result = unsafe {
|
||||
c_irq_install(
|
||||
irq_num as u64,
|
||||
Some(common_msg.irq_hander),
|
||||
common_msg.irq_parameter as u64,
|
||||
common_msg.irq_name.as_ptr(),
|
||||
common_msg.irq_ack,
|
||||
)
|
||||
};
|
||||
match result as u32 {
|
||||
EINVAL => {
|
||||
|
||||
let result = irq_manager().request_irq(
|
||||
irq_num,
|
||||
common_msg.irq_name.clone(),
|
||||
common_msg.irq_hander,
|
||||
IrqHandleFlags::empty(),
|
||||
Some(common_msg.dev_id.clone()),
|
||||
);
|
||||
|
||||
match result {
|
||||
Ok(_) => {}
|
||||
Err(SystemError::EINVAL) => {
|
||||
return Err(PciError::PciIrqError(PciIrqError::InvalidIrqNum(irq_num)));
|
||||
}
|
||||
EAGAIN => {
|
||||
|
||||
Err(SystemError::EAGAIN_OR_EWOULDBLOCK) => {
|
||||
return Err(PciError::PciIrqError(PciIrqError::IrqNumOccupied(
|
||||
irq_num,
|
||||
)));
|
||||
}
|
||||
|
||||
Err(_) => {
|
||||
kerror!(
|
||||
"Failed to request pci irq {} for device {}",
|
||||
irq_num.data(),
|
||||
&common_msg.irq_name
|
||||
);
|
||||
return Err(PciError::PciIrqError(PciIrqError::IrqNumOccupied(
|
||||
irq_num,
|
||||
)));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
//MSI中断只需配置一次PCI寄存器
|
||||
|
||||
// MSI中断只需配置一次PCI寄存器
|
||||
if common_msg.irq_index == 0 {
|
||||
let msg_address = arch_msi_message_address(0);
|
||||
let trigger = match msg.irq_specific_message {
|
||||
@ -377,8 +401,8 @@ pub trait PciInterrupt: PciDeviceStructure {
|
||||
}
|
||||
IrqSpecificMsg::Msi { trigger_mode, .. } => trigger_mode,
|
||||
};
|
||||
let msg_data = arch_msi_message_data(irq_num, 0, trigger);
|
||||
//写入Message Data和Message Address
|
||||
let msg_data = arch_msi_message_data(irq_num.data() as u16, 0, trigger);
|
||||
// 写入Message Data和Message Address
|
||||
if address_64 {
|
||||
PciArch::write_config(
|
||||
&self.common_header().bus_device_function,
|
||||
@ -496,26 +520,39 @@ pub trait PciInterrupt: PciDeviceStructure {
|
||||
}
|
||||
let irq_num =
|
||||
self.irq_vector_mut().unwrap()[msg.irq_common_message.irq_index as usize];
|
||||
|
||||
let common_msg = &msg.irq_common_message;
|
||||
let result = unsafe {
|
||||
c_irq_install(
|
||||
irq_num as u64,
|
||||
Some(common_msg.irq_hander),
|
||||
common_msg.irq_parameter as u64,
|
||||
common_msg.irq_name.as_ptr(),
|
||||
common_msg.irq_ack,
|
||||
)
|
||||
};
|
||||
match result as u32 {
|
||||
EINVAL => {
|
||||
|
||||
let result = irq_manager().request_irq(
|
||||
irq_num,
|
||||
common_msg.irq_name.clone(),
|
||||
common_msg.irq_hander,
|
||||
IrqHandleFlags::empty(),
|
||||
Some(common_msg.dev_id.clone()),
|
||||
);
|
||||
|
||||
match result {
|
||||
Ok(_) => {}
|
||||
Err(SystemError::EINVAL) => {
|
||||
return Err(PciError::PciIrqError(PciIrqError::InvalidIrqNum(irq_num)));
|
||||
}
|
||||
EAGAIN => {
|
||||
|
||||
Err(SystemError::EAGAIN_OR_EWOULDBLOCK) => {
|
||||
return Err(PciError::PciIrqError(PciIrqError::IrqNumOccupied(
|
||||
irq_num,
|
||||
)));
|
||||
}
|
||||
|
||||
Err(_) => {
|
||||
kerror!(
|
||||
"Failed to request pci irq {} for device {}",
|
||||
irq_num.data(),
|
||||
&common_msg.irq_name
|
||||
);
|
||||
return Err(PciError::PciIrqError(PciIrqError::IrqNumOccupied(
|
||||
irq_num,
|
||||
)));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let msg_address = arch_msi_message_address(0);
|
||||
@ -525,7 +562,7 @@ pub trait PciInterrupt: PciDeviceStructure {
|
||||
}
|
||||
IrqSpecificMsg::Msi { trigger_mode, .. } => trigger_mode,
|
||||
};
|
||||
let msg_data = arch_msi_message_data(irq_num, 0, trigger);
|
||||
let msg_data = arch_msi_message_data(irq_num.data() as u16, 0, trigger);
|
||||
//写入Message Data和Message Address
|
||||
let pcistandardbar = self
|
||||
.bar()
|
||||
@ -589,9 +626,8 @@ pub trait PciInterrupt: PciDeviceStructure {
|
||||
..
|
||||
} => {
|
||||
for vector in self.irq_vector_mut().unwrap() {
|
||||
unsafe {
|
||||
c_irq_uninstall(vector.clone() as u64);
|
||||
}
|
||||
let irq = IrqNumber::new((*vector).into());
|
||||
irq_manager().free_irq(irq, None);
|
||||
}
|
||||
PciArch::write_config(&self.common_header().bus_device_function, cap_offset, 0);
|
||||
PciArch::write_config(
|
||||
@ -636,9 +672,8 @@ pub trait PciInterrupt: PciDeviceStructure {
|
||||
..
|
||||
} => {
|
||||
for vector in self.irq_vector_mut().unwrap() {
|
||||
unsafe {
|
||||
c_irq_uninstall(vector.clone() as u64);
|
||||
}
|
||||
let irq = IrqNumber::new((*vector).into());
|
||||
irq_manager().free_irq(irq, None);
|
||||
}
|
||||
PciArch::write_config(&self.common_header().bus_device_function, cap_offset, 0);
|
||||
let pcistandardbar = self
|
||||
|
85
kernel/src/driver/virtio/irq.rs
Normal file
85
kernel/src/driver/virtio/irq.rs
Normal file
@ -0,0 +1,85 @@
|
||||
use alloc::sync::Arc;
|
||||
use hashbrown::HashMap;
|
||||
use system_error::SystemError;
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
use crate::{driver::base::device::DeviceId, init::initcall::INITCALL_CORE, libs::rwlock::RwLock};
|
||||
|
||||
use super::VirtIODevice;
|
||||
|
||||
static mut VIRTIO_IRQ_MANAGER: Option<VirtIOIrqManager> = None;
|
||||
|
||||
#[inline(always)]
|
||||
pub fn virtio_irq_manager() -> &'static VirtIOIrqManager {
|
||||
unsafe { VIRTIO_IRQ_MANAGER.as_ref().unwrap() }
|
||||
}
|
||||
|
||||
pub struct VirtIOIrqManager {
|
||||
map: RwLock<HashMap<Arc<DeviceId>, Arc<dyn VirtIODevice>>>,
|
||||
}
|
||||
|
||||
impl VirtIOIrqManager {
|
||||
fn new() -> Self {
|
||||
VirtIOIrqManager {
|
||||
map: RwLock::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
|
||||
/// 注册一个新的设备到virtio中断请求(IRQ)映射中。
|
||||
///
|
||||
/// # 参数
|
||||
///
|
||||
/// - `device` - 实现了 `VirtIODevice` trait 的设备对象,被封装在 `Arc` 智能指针中。
|
||||
///
|
||||
/// # 返回值
|
||||
///
|
||||
/// - 如果设备成功注册,返回 `Ok(())`。
|
||||
/// - 如果设备ID已经存在于映射中,返回 `Err(SystemError::EEXIST)`。
|
||||
pub fn register_device(&self, device: Arc<dyn VirtIODevice>) -> Result<(), SystemError> {
|
||||
let mut map = self.map.write_irqsave();
|
||||
|
||||
if map.contains_key(device.dev_id()) {
|
||||
return Err(SystemError::EEXIST);
|
||||
}
|
||||
|
||||
map.insert(device.dev_id().clone(), device);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 取消注册设备
|
||||
///
|
||||
/// 这个函数会从内部映射中移除指定的设备。设备是通过设备ID来识别的。
|
||||
///
|
||||
/// # 参数
|
||||
///
|
||||
/// - `device` - 需要被取消注册的设备,它是一个实现了 `VirtIODevice` trait 的智能指针。
|
||||
#[allow(dead_code)]
|
||||
pub fn unregister_device(&self, dev_id: &Arc<DeviceId>) {
|
||||
let mut map = self.map.write_irqsave();
|
||||
map.remove(dev_id);
|
||||
}
|
||||
|
||||
/// 查找并返回指定设备ID的设备。
|
||||
///
|
||||
/// # 参数
|
||||
/// - `dev_id` - 我们要查找的设备的设备ID。
|
||||
///
|
||||
/// # 返回
|
||||
/// - 如果找到了设备,返回一个包含设备的`Option<Arc<dyn VirtIODevice>>`。
|
||||
/// - 如果没有找到设备,返回`None`。
|
||||
|
||||
pub fn lookup_device(&self, dev_id: &Arc<DeviceId>) -> Option<Arc<dyn VirtIODevice>> {
|
||||
let map = self.map.read_irqsave();
|
||||
map.get(dev_id).map(|x| x.clone())
|
||||
}
|
||||
}
|
||||
|
||||
#[unified_init(INITCALL_CORE)]
|
||||
fn init_virtio_irq_manager() -> Result<(), SystemError> {
|
||||
let manager = VirtIOIrqManager::new();
|
||||
unsafe {
|
||||
VIRTIO_IRQ_MANAGER = Some(manager);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
@ -1,3 +1,19 @@
|
||||
use core::any::Any;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::exception::{irqdesc::IrqReturn, IrqNumber};
|
||||
|
||||
use super::base::device::DeviceId;
|
||||
|
||||
pub(super) mod irq;
|
||||
pub mod transport_pci;
|
||||
pub mod virtio;
|
||||
pub mod virtio_impl;
|
||||
|
||||
pub trait VirtIODevice: Send + Sync + Any {
|
||||
fn handle_irq(&self, _irq: IrqNumber) -> Result<IrqReturn, SystemError>;
|
||||
|
||||
fn dev_id(&self) -> &Arc<DeviceId>;
|
||||
}
|
||||
|
@ -1,22 +1,31 @@
|
||||
//! PCI transport for VirtIO.
|
||||
use crate::arch::{PciArch, TraitPciArch};
|
||||
use crate::driver::base::device::DeviceId;
|
||||
use crate::driver::pci::pci::{
|
||||
BusDeviceFunction, PciDeviceStructure, PciDeviceStructureGeneralDevice, PciError,
|
||||
PciStandardDeviceBar, PCI_CAP_ID_VNDR,
|
||||
};
|
||||
|
||||
use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqMsg, IRQ};
|
||||
use crate::include::bindings::bindings::pt_regs;
|
||||
use crate::driver::virtio::irq::virtio_irq_manager;
|
||||
use crate::exception::irqdata::IrqHandlerData;
|
||||
use crate::exception::irqdesc::{IrqHandler, IrqReturn};
|
||||
|
||||
use crate::exception::IrqNumber;
|
||||
|
||||
use crate::libs::volatile::{
|
||||
volread, volwrite, ReadOnly, Volatile, VolatileReadable, VolatileWritable, WriteOnly,
|
||||
};
|
||||
use crate::mm::VirtAddr;
|
||||
use crate::net::net_core::poll_ifaces_try_lock_onetime;
|
||||
|
||||
use alloc::string::ToString;
|
||||
use alloc::sync::Arc;
|
||||
use core::{
|
||||
fmt::{self, Display, Formatter},
|
||||
mem::{align_of, size_of},
|
||||
ptr::{self, addr_of_mut, NonNull},
|
||||
};
|
||||
use system_error::SystemError;
|
||||
use virtio_drivers::{
|
||||
transport::{DeviceStatus, DeviceType, Transport},
|
||||
Error, Hal, PhysAddr,
|
||||
@ -57,7 +66,7 @@ const VIRTIO_PCI_CAP_ISR_CFG: u8 = 3;
|
||||
const VIRTIO_PCI_CAP_DEVICE_CFG: u8 = 4;
|
||||
|
||||
/// Virtio设备接收中断的设备号
|
||||
const VIRTIO_RECV_VECTOR: u16 = 56;
|
||||
const VIRTIO_RECV_VECTOR: IrqNumber = IrqNumber::new(56);
|
||||
/// Virtio设备接收中断的设备号的表项号
|
||||
const VIRTIO_RECV_VECTOR_INDEX: u16 = 0;
|
||||
// 接收的queue号
|
||||
@ -82,6 +91,7 @@ fn device_type(pci_device_id: u16) -> DeviceType {
|
||||
/// PCI transport for VirtIO.
|
||||
///
|
||||
/// Ref: 4.1 Virtio Over PCI Bus
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PciTransport {
|
||||
device_type: DeviceType,
|
||||
@ -96,21 +106,24 @@ pub struct PciTransport {
|
||||
isr_status: NonNull<Volatile<u8>>,
|
||||
/// The VirtIO device-specific configuration within some BAR.
|
||||
config_space: Option<NonNull<[u32]>>,
|
||||
}
|
||||
|
||||
unsafe extern "C" fn virtio_irq_hander(_irq_num: u64, _irq_paramer: u64, _regs: *mut pt_regs) {
|
||||
// kdebug!("12345");
|
||||
poll_ifaces_try_lock_onetime().ok();
|
||||
irq: IrqNumber,
|
||||
dev_id: Arc<DeviceId>,
|
||||
}
|
||||
|
||||
impl PciTransport {
|
||||
/// Construct a new PCI VirtIO device driver for the given device function on the given PCI
|
||||
/// root controller.
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `device` - The PCI device structure for the VirtIO device.
|
||||
/// - `irq_handler` - An optional handler for the device's interrupt. If `None`, a default
|
||||
/// handler `DefaultVirtioIrqHandler` will be used.
|
||||
pub fn new<H: Hal>(
|
||||
device: &mut PciDeviceStructureGeneralDevice,
|
||||
dev_id: Arc<DeviceId>,
|
||||
) -> Result<Self, VirtioPciError> {
|
||||
let irq = VIRTIO_RECV_VECTOR;
|
||||
let header = &device.common_header;
|
||||
let bus_device_function = header.bus_device_function;
|
||||
if header.vendor_id != VIRTIO_VENDOR_ID {
|
||||
@ -128,7 +141,7 @@ impl PciTransport {
|
||||
let standard_device = device.as_standard_device_mut().unwrap();
|
||||
// 目前缺少对PCI设备中断号的统一管理,所以这里需要指定一个中断号。不能与其他中断重复
|
||||
let irq_vector = standard_device.irq_vector_mut().unwrap();
|
||||
irq_vector.push(VIRTIO_RECV_VECTOR);
|
||||
irq_vector.push(irq);
|
||||
standard_device
|
||||
.irq_init(IRQ::PCI_IRQ_MSIX)
|
||||
.expect("IRQ init failed");
|
||||
@ -136,10 +149,9 @@ impl PciTransport {
|
||||
let msg = PciIrqMsg {
|
||||
irq_common_message: IrqCommonMsg::init_from(
|
||||
0,
|
||||
"Virtio_Recv_IRQ",
|
||||
0,
|
||||
virtio_irq_hander,
|
||||
None,
|
||||
"Virtio_IRQ".to_string(),
|
||||
&DefaultVirtioIrqHandler,
|
||||
dev_id.clone(),
|
||||
),
|
||||
irq_specific_message: IrqSpecificMsg::msi_default(),
|
||||
};
|
||||
@ -222,6 +234,8 @@ impl PciTransport {
|
||||
notify_off_multiplier,
|
||||
isr_status,
|
||||
config_space,
|
||||
irq,
|
||||
dev_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -374,7 +388,9 @@ impl Transport for PciTransport {
|
||||
impl Drop for PciTransport {
|
||||
fn drop(&mut self) {
|
||||
// Reset the device when the transport is dropped.
|
||||
self.set_status(DeviceStatus::empty())
|
||||
self.set_status(DeviceStatus::empty());
|
||||
|
||||
// todo: 调用pci的中断释放函数,并且在virtio_irq_manager里面删除对应的设备的中断
|
||||
}
|
||||
}
|
||||
|
||||
@ -544,3 +560,36 @@ fn get_bar_region_slice<T>(
|
||||
fn nonnull_slice_from_raw_parts<T>(data: NonNull<T>, len: usize) -> NonNull<[T]> {
|
||||
NonNull::new(ptr::slice_from_raw_parts_mut(data.as_ptr(), len)).unwrap()
|
||||
}
|
||||
|
||||
/// `DefaultVirtioIrqHandler` 是一个默认的virtio设备中断处理程序。
|
||||
///
|
||||
/// 当虚拟设备产生中断时,该处理程序会被调用。
|
||||
///
|
||||
/// 它首先检查设备ID是否存在,然后尝试查找与设备ID关联的设备。
|
||||
/// 如果找到设备,它会调用设备的 `handle_irq` 方法来处理中断。
|
||||
/// 如果没有找到设备,它会记录一条警告并返回 `IrqReturn::NotHandled`,表示中断未被处理。
|
||||
#[derive(Debug)]
|
||||
struct DefaultVirtioIrqHandler;
|
||||
|
||||
impl IrqHandler for DefaultVirtioIrqHandler {
|
||||
fn handle(
|
||||
&self,
|
||||
irq: IrqNumber,
|
||||
_static_data: Option<&dyn IrqHandlerData>,
|
||||
dev_id: Option<Arc<dyn IrqHandlerData>>,
|
||||
) -> Result<IrqReturn, SystemError> {
|
||||
let dev_id = dev_id.ok_or(SystemError::EINVAL)?;
|
||||
let dev_id = dev_id
|
||||
.arc_any()
|
||||
.downcast::<DeviceId>()
|
||||
.map_err(|_| SystemError::EINVAL)?;
|
||||
|
||||
if let Some(dev) = virtio_irq_manager().lookup_device(&dev_id) {
|
||||
return dev.handle_irq(irq);
|
||||
} else {
|
||||
// 未绑定具体设备,因此无法处理中断
|
||||
|
||||
return Ok(IrqReturn::NotHandled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use super::transport_pci::PciTransport;
|
||||
use super::virtio_impl::HalImpl;
|
||||
use crate::driver::base::device::DeviceId;
|
||||
use crate::driver::net::virtio_net::virtio_net;
|
||||
use crate::driver::pci::pci::{
|
||||
get_pci_device_structure_mut, PciDeviceStructure, PciDeviceStructureGeneralDevice,
|
||||
@ -7,6 +8,7 @@ use crate::driver::pci::pci::{
|
||||
};
|
||||
use crate::libs::rwlock::RwLockWriteGuard;
|
||||
use crate::{kdebug, kerror, kwarn};
|
||||
use alloc::sync::Arc;
|
||||
use alloc::{boxed::Box, collections::LinkedList};
|
||||
use virtio_drivers::transport::{DeviceType, Transport};
|
||||
const NETWORK_CLASS: u8 = 0x2;
|
||||
@ -23,14 +25,16 @@ pub fn virtio_probe() {
|
||||
let mut list = PCI_DEVICE_LINKEDLIST.write();
|
||||
if let Ok(virtio_list) = virtio_device_search(&mut list) {
|
||||
for virtio_device in virtio_list {
|
||||
match PciTransport::new::<HalImpl>(virtio_device) {
|
||||
let dev_id = virtio_device.common_header.device_id;
|
||||
let dev_id = DeviceId::new(None, Some(format!("virtio_{}", dev_id))).unwrap();
|
||||
match PciTransport::new::<HalImpl>(virtio_device, dev_id.clone()) {
|
||||
Ok(mut transport) => {
|
||||
kdebug!(
|
||||
"Detected virtio PCI device with device type {:?}, features {:#018x}",
|
||||
transport.device_type(),
|
||||
transport.read_device_features(),
|
||||
);
|
||||
virtio_device_init(transport);
|
||||
virtio_device_init(transport, dev_id);
|
||||
}
|
||||
Err(err) => {
|
||||
kerror!("Pci transport create failed because of error: {}", err);
|
||||
@ -43,7 +47,7 @@ pub fn virtio_probe() {
|
||||
}
|
||||
|
||||
///@brief 为virtio设备寻找对应的驱动进行初始化
|
||||
fn virtio_device_init(transport: impl Transport + 'static) {
|
||||
fn virtio_device_init(transport: impl Transport + 'static, dev_id: Arc<DeviceId>) {
|
||||
match transport.device_type() {
|
||||
DeviceType::Block => {
|
||||
kwarn!("Not support virtio_block device for now");
|
||||
@ -54,7 +58,7 @@ fn virtio_device_init(transport: impl Transport + 'static) {
|
||||
DeviceType::Input => {
|
||||
kwarn!("Not support virtio_input device for now");
|
||||
}
|
||||
DeviceType::Network => virtio_net(transport),
|
||||
DeviceType::Network => virtio_net(transport, dev_id),
|
||||
t => {
|
||||
kwarn!("Unrecognized virtio device: {:?}", t);
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
|
||||
CFLAGS += -I .
|
||||
|
||||
|
||||
all: irq.o
|
||||
|
||||
irq.o: irq.c
|
||||
$(CC) $(CFLAGS) -c irq.c -o irq.o
|
@ -41,10 +41,23 @@ impl IrqChip for NoIrqChip {
|
||||
fn name(&self) -> &'static str {
|
||||
"none"
|
||||
}
|
||||
|
||||
fn can_mask_ack(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn can_set_affinity(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn can_set_flow_type(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn irq_disable(&self, _irq: &Arc<IrqData>) {}
|
||||
|
||||
fn irq_ack(&self, irq: &Arc<IrqData>) {
|
||||
@ -78,17 +91,26 @@ impl IrqChip for DummyIrqChip {
|
||||
"dummy"
|
||||
}
|
||||
|
||||
fn can_mask_ack(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn can_set_flow_type(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn can_set_affinity(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn irq_disable(&self, _irq: &Arc<IrqData>) {}
|
||||
|
||||
fn irq_ack(&self, _irq: &Arc<IrqData>) {}
|
||||
|
||||
fn irq_mask(&self, _irq: &Arc<IrqData>) {}
|
||||
fn irq_unmask(&self, _irq: &Arc<IrqData>) {}
|
||||
|
||||
fn irq_startup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,10 +1,22 @@
|
||||
use alloc::sync::Arc;
|
||||
use core::{intrinsics::unlikely, ops::BitAnd};
|
||||
|
||||
use crate::arch::CurrentIrqArch;
|
||||
use alloc::sync::Arc;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{interrupt::TrapFrame, CurrentIrqArch},
|
||||
exception::irqdesc::InnerIrqDesc,
|
||||
libs::spinlock::SpinLockGuard,
|
||||
process::{ProcessFlags, ProcessManager},
|
||||
};
|
||||
|
||||
use super::{
|
||||
irqdesc::{IrqDesc, IrqFlowHandler},
|
||||
InterruptArch,
|
||||
irqdata::{IrqData, IrqHandlerData, IrqStatus},
|
||||
irqdesc::{
|
||||
InnerIrqAction, IrqDesc, IrqDescState, IrqFlowHandler, IrqReturn, ThreadedHandlerFlags,
|
||||
},
|
||||
manage::{irq_manager, IrqManager},
|
||||
InterruptArch, IrqNumber,
|
||||
};
|
||||
|
||||
/// 获取用于处理错误的中断的处理程序
|
||||
@ -13,15 +25,220 @@ pub fn bad_irq_handler() -> &'static dyn IrqFlowHandler {
|
||||
&HandleBadIrq
|
||||
}
|
||||
|
||||
/// 获取用于处理快速EOI的中断的处理程序
|
||||
#[inline(always)]
|
||||
pub fn fast_eoi_irq_handler() -> &'static dyn IrqFlowHandler {
|
||||
&FastEOIIrqHandler
|
||||
}
|
||||
|
||||
/// 获取用于处理边沿触发中断的处理程序
|
||||
#[inline(always)]
|
||||
pub fn edge_irq_handler() -> &'static dyn IrqFlowHandler {
|
||||
&EdgeIrqHandler
|
||||
}
|
||||
|
||||
/// handle spurious and unhandled irqs
|
||||
#[derive(Debug)]
|
||||
struct HandleBadIrq;
|
||||
|
||||
impl IrqFlowHandler for HandleBadIrq {
|
||||
/// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/handle.c?fi=handle_bad_irq#33
|
||||
fn handle(&self, irq_desc: &Arc<IrqDesc>) {
|
||||
fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
|
||||
// todo: print_irq_desc
|
||||
// todo: 增加kstat计数
|
||||
CurrentIrqArch::ack_bad_irq(irq_desc.irq());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FastEOIIrqHandler;
|
||||
|
||||
impl IrqFlowHandler for FastEOIIrqHandler {
|
||||
fn handle(&self, _irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
|
||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/chip.c?r=&mo=17578&fi=689#689
|
||||
todo!("FastEOIIrqHandler");
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct EdgeIrqHandler;
|
||||
|
||||
impl IrqFlowHandler for EdgeIrqHandler {
|
||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/chip.c?fi=handle_edge_irq#775
|
||||
fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
|
||||
let mut desc_inner_guard: SpinLockGuard<'_, InnerIrqDesc> = irq_desc.inner();
|
||||
if !irq_may_run(&desc_inner_guard) {
|
||||
// kdebug!("!irq_may_run");
|
||||
desc_inner_guard
|
||||
.internal_state_mut()
|
||||
.insert(IrqDescState::IRQS_PENDING);
|
||||
mask_ack_irq(desc_inner_guard.irq_data());
|
||||
return;
|
||||
}
|
||||
|
||||
if desc_inner_guard.common_data().disabled() {
|
||||
// kdebug!("desc_inner_guard.common_data().disabled()");
|
||||
desc_inner_guard
|
||||
.internal_state_mut()
|
||||
.insert(IrqDescState::IRQS_PENDING);
|
||||
mask_ack_irq(desc_inner_guard.irq_data());
|
||||
return;
|
||||
}
|
||||
|
||||
let irq_data = desc_inner_guard.irq_data().clone();
|
||||
|
||||
irq_data.chip_info_read_irqsave().chip().irq_ack(&irq_data);
|
||||
|
||||
loop {
|
||||
if unlikely(desc_inner_guard.actions().is_empty()) {
|
||||
kdebug!("no action for irq {}", irq_data.irq().data());
|
||||
irq_manager().mask_irq(&irq_data);
|
||||
return;
|
||||
}
|
||||
|
||||
// 当我们在处理一个中断时,如果另一个中断到来,我们本可以屏蔽它.
|
||||
// 如果在此期间没有被禁用,请重新启用它。
|
||||
if desc_inner_guard
|
||||
.internal_state()
|
||||
.contains(IrqDescState::IRQS_PENDING)
|
||||
{
|
||||
let status = desc_inner_guard.common_data().status();
|
||||
if status.disabled() == false && status.masked() {
|
||||
// kdebug!("re-enable irq");
|
||||
irq_manager().unmask_irq(&desc_inner_guard);
|
||||
}
|
||||
}
|
||||
|
||||
// kdebug!("handle_irq_event");
|
||||
|
||||
desc_inner_guard
|
||||
.internal_state_mut()
|
||||
.remove(IrqDescState::IRQS_PENDING);
|
||||
desc_inner_guard.common_data().set_inprogress();
|
||||
|
||||
drop(desc_inner_guard);
|
||||
|
||||
let _r = do_handle_irq_event(irq_desc);
|
||||
|
||||
desc_inner_guard = irq_desc.inner();
|
||||
desc_inner_guard.common_data().clear_inprogress();
|
||||
|
||||
if !(desc_inner_guard
|
||||
.internal_state()
|
||||
.contains(IrqDescState::IRQS_PENDING)
|
||||
&& desc_inner_guard.common_data().disabled() == false)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 判断中断是否可以运行
|
||||
fn irq_may_run(desc_inner_guard: &SpinLockGuard<'_, InnerIrqDesc>) -> bool {
|
||||
let mask = IrqStatus::IRQD_IRQ_INPROGRESS | IrqStatus::IRQD_WAKEUP_ARMED;
|
||||
let status = desc_inner_guard.common_data().status();
|
||||
|
||||
// 如果中断不在处理中并且没有被唤醒,则可以运行
|
||||
if status.bitand(mask).is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// todo: 检查其他处理器是否在轮询当前中断
|
||||
return false;
|
||||
}
|
||||
|
||||
fn mask_ack_irq(irq_data: &Arc<IrqData>) {
|
||||
let chip = irq_data.chip_info_read_irqsave().chip();
|
||||
if chip.can_mask_ack() {
|
||||
chip.irq_mask_ack(&irq_data);
|
||||
irq_data.common_data().set_masked();
|
||||
} else {
|
||||
irq_manager().mask_irq(irq_data);
|
||||
chip.irq_ack(&irq_data);
|
||||
}
|
||||
}
|
||||
|
||||
impl IrqManager {
|
||||
pub(super) fn do_irq_wake_thread(
|
||||
&self,
|
||||
desc: &Arc<IrqDesc>,
|
||||
action_inner: &mut SpinLockGuard<'_, InnerIrqAction>,
|
||||
) {
|
||||
let thread = action_inner.thread();
|
||||
|
||||
if thread.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
let thread = thread.unwrap();
|
||||
if thread.flags().contains(ProcessFlags::EXITING) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果线程已经在运行,我们不需要唤醒它
|
||||
if action_inner
|
||||
.thread_flags_mut()
|
||||
.test_and_set_bit(ThreadedHandlerFlags::IRQTF_RUNTHREAD)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
desc.inc_threads_active();
|
||||
|
||||
ProcessManager::wakeup(&thread).ok();
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理中断事件
|
||||
///
|
||||
/// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/handle.c?fi=handle_irq_event#139
|
||||
#[inline(never)]
|
||||
fn do_handle_irq_event(desc: &Arc<IrqDesc>) -> Result<(), SystemError> {
|
||||
let desc_inner_guard = desc.inner();
|
||||
let irq_data = desc_inner_guard.irq_data().clone();
|
||||
let actions = desc_inner_guard.actions().clone();
|
||||
drop(desc_inner_guard);
|
||||
|
||||
let irq = irq_data.irq();
|
||||
let mut r = Ok(IrqReturn::NotHandled);
|
||||
|
||||
for action in actions {
|
||||
let mut action_inner: SpinLockGuard<'_, InnerIrqAction> = action.inner();
|
||||
// kdebug!("do_handle_irq_event: action: {:?}", action_inner.name());
|
||||
let dynamic_data = action_inner
|
||||
.dev_id()
|
||||
.clone()
|
||||
.map(|d| d as Arc<dyn IrqHandlerData>);
|
||||
r = action_inner
|
||||
.handler()
|
||||
.unwrap()
|
||||
.handle(irq, None, dynamic_data);
|
||||
|
||||
if let Ok(IrqReturn::WakeThread) = r {
|
||||
if unlikely(action_inner.thread_fn().is_none()) {
|
||||
warn_no_thread(irq, &mut action_inner);
|
||||
} else {
|
||||
irq_manager().do_irq_wake_thread(desc, &mut action_inner);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return r.map(|_| ());
|
||||
}
|
||||
|
||||
fn warn_no_thread(irq: IrqNumber, action_inner: &mut SpinLockGuard<'_, InnerIrqAction>) {
|
||||
// warn on once
|
||||
if action_inner
|
||||
.thread_flags_mut()
|
||||
.test_and_set_bit(ThreadedHandlerFlags::IRQTF_WARNED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
kwarn!(
|
||||
"irq {}, device {} returned IRQ_WAKE_THREAD, but no threaded handler",
|
||||
irq.data(),
|
||||
action_inner.name()
|
||||
);
|
||||
}
|
||||
|
@ -2,7 +2,10 @@ use system_error::SystemError;
|
||||
|
||||
use crate::arch::CurrentIrqArch;
|
||||
|
||||
use super::{dummychip::dummy_chip_init, irqdesc::early_irq_init, InterruptArch};
|
||||
use super::{
|
||||
dummychip::dummy_chip_init, irqdesc::early_irq_init, irqdomain::irq_domain_manager_init,
|
||||
InterruptArch,
|
||||
};
|
||||
|
||||
/// 初始化中断
|
||||
#[inline(never)]
|
||||
@ -10,6 +13,7 @@ pub fn irq_init() -> Result<(), SystemError> {
|
||||
// todo: 通用初始化
|
||||
|
||||
dummy_chip_init();
|
||||
irq_domain_manager_init();
|
||||
early_irq_init().expect("early_irq_init failed");
|
||||
|
||||
// 初始化架构相关的中断
|
||||
|
@ -1,9 +1,25 @@
|
||||
use alloc::sync::Arc;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{sched::sched, MMArch},
|
||||
mm::MemoryManagementArch,
|
||||
smp::cpu::ProcessorId,
|
||||
};
|
||||
|
||||
use super::{
|
||||
irqdata::IrqHandlerData,
|
||||
irqdesc::{IrqHandler, IrqReturn},
|
||||
HardwareIrqNumber, IrqNumber,
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum IpiKind {
|
||||
KickCpu,
|
||||
FlushTLB,
|
||||
/// 指定中断向量号
|
||||
SpecVector(HardwareIrqNumber),
|
||||
}
|
||||
|
||||
/// IPI投递目标
|
||||
@ -17,5 +33,38 @@ pub enum IpiTarget {
|
||||
/// 除了当前CPU以外的所有CPU
|
||||
Other,
|
||||
/// 指定的CPU
|
||||
Specified(usize),
|
||||
Specified(ProcessorId),
|
||||
}
|
||||
|
||||
/// 处理跨核心CPU唤醒的IPI
|
||||
#[derive(Debug)]
|
||||
pub struct KickCpuIpiHandler;
|
||||
|
||||
impl IrqHandler for KickCpuIpiHandler {
|
||||
fn handle(
|
||||
&self,
|
||||
_irq: IrqNumber,
|
||||
_static_data: Option<&dyn IrqHandlerData>,
|
||||
_dynamic_data: Option<Arc<dyn IrqHandlerData>>,
|
||||
) -> Result<IrqReturn, SystemError> {
|
||||
sched();
|
||||
Ok(IrqReturn::Handled)
|
||||
}
|
||||
}
|
||||
|
||||
/// 处理TLB刷新的IPI
|
||||
#[derive(Debug)]
|
||||
pub struct FlushTLBIpiHandler;
|
||||
|
||||
impl IrqHandler for FlushTLBIpiHandler {
|
||||
fn handle(
|
||||
&self,
|
||||
_irq: IrqNumber,
|
||||
_static_data: Option<&dyn IrqHandlerData>,
|
||||
_dynamic_data: Option<Arc<dyn IrqHandlerData>>,
|
||||
) -> Result<IrqReturn, SystemError> {
|
||||
unsafe { MMArch::invalidate_all() };
|
||||
|
||||
Ok(IrqReturn::Handled)
|
||||
}
|
||||
}
|
||||
|
@ -1,84 +0,0 @@
|
||||
|
||||
#include "irq.h"
|
||||
#include <common/errno.h>
|
||||
|
||||
|
||||
#include <common/asm.h>
|
||||
#include <common/printk.h>
|
||||
#include <common/string.h>
|
||||
#include <mm/slab.h>
|
||||
#include <arch/arch.h>
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize("O0")
|
||||
|
||||
/**
|
||||
* @brief 中断注册函数
|
||||
*
|
||||
* @param irq_num 中断向量号
|
||||
* @param arg 传递给中断安装接口的参数
|
||||
* @param handler 中断处理函数
|
||||
* @param paramater 中断处理函数的参数
|
||||
* @param controller 中断控制器结构
|
||||
* @param irq_name 中断名
|
||||
* @return int
|
||||
*/
|
||||
int irq_register(ul irq_num, void *arg, void (*handler)(ul irq_num, ul parameter, struct pt_regs *regs), ul paramater,
|
||||
hardware_intr_controller *controller, char *irq_name)
|
||||
{
|
||||
// 由于为I/O APIC分配的中断向量号是从32开始的,因此要减去32才是对应的interrupt_desc的元素
|
||||
irq_desc_t *p = NULL;
|
||||
if (irq_num >= 32 && irq_num < 0x80)
|
||||
p = &interrupt_desc[irq_num - 32];
|
||||
else if (irq_num >= 150 && irq_num < 200)
|
||||
p = &local_apic_interrupt_desc[irq_num - 150];
|
||||
else
|
||||
{
|
||||
kerror("irq_register(): invalid irq num: %ld.", irq_num);
|
||||
return -EINVAL;
|
||||
}
|
||||
p->controller = controller;
|
||||
if (p->irq_name == NULL)
|
||||
{
|
||||
int namelen = sizeof(strlen(irq_name) + 1);
|
||||
p->irq_name = (char *)kmalloc(namelen, 0);
|
||||
memset(p->irq_name, 0, namelen);
|
||||
strncpy(p->irq_name, irq_name, namelen);
|
||||
}
|
||||
|
||||
p->parameter = paramater;
|
||||
p->flags = 0;
|
||||
p->handler = handler;
|
||||
io_mfence();
|
||||
p->controller->install(irq_num, arg);
|
||||
io_mfence();
|
||||
p->controller->enable(irq_num);
|
||||
io_mfence();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 中断注销函数
|
||||
*
|
||||
* @param irq_num 中断向量号
|
||||
* @return int
|
||||
*/
|
||||
int irq_unregister(ul irq_num)
|
||||
{
|
||||
irq_desc_t *p = &interrupt_desc[irq_num - 32];
|
||||
p->controller->disable(irq_num);
|
||||
p->controller->uninstall(irq_num);
|
||||
|
||||
p->controller = NULL;
|
||||
if (p->irq_name)
|
||||
kfree(p->irq_name);
|
||||
p->irq_name = NULL;
|
||||
p->parameter = (ul)NULL;
|
||||
p->flags = 0;
|
||||
p->handler = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#pragma GCC optimize("O0")
|
@ -1,175 +0,0 @@
|
||||
/**
|
||||
* @file irq.h
|
||||
* @author longjin
|
||||
* @brief 中断处理程序
|
||||
* @version 0.1
|
||||
* @date 2022-01-28
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <common/glib.h>
|
||||
|
||||
#include <process/ptrace.h>
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("O0")
|
||||
|
||||
#define IRQ_NUM 26
|
||||
#define SMP_IRQ_NUM 10
|
||||
#define LOCAL_APIC_IRQ_NUM 50
|
||||
|
||||
extern void (*interrupt_table[IRQ_NUM])(void);
|
||||
extern void do_IRQ(struct pt_regs *regs, ul number);
|
||||
|
||||
|
||||
extern void (*SMP_interrupt_table[SMP_IRQ_NUM])(void);
|
||||
|
||||
extern void (*syscall_intr_table[1])(void);
|
||||
extern void (*local_apic_interrupt_table[LOCAL_APIC_IRQ_NUM])(void);
|
||||
|
||||
/* ========= 中断向量分配表 ==========
|
||||
|
||||
0~255 IDT
|
||||
|
||||
0 ~ 31 trap fault abort for system
|
||||
0 devide error
|
||||
1 debug
|
||||
2 NMI
|
||||
3 breakpoint
|
||||
4 overflow
|
||||
5 bound range
|
||||
6 undefined opcode
|
||||
7 device not available
|
||||
8 double fault
|
||||
9 coprocessor segment overrun
|
||||
10 invalid TSS
|
||||
11 segment not present
|
||||
12 stack segment fault
|
||||
13 general protection
|
||||
14 page fault
|
||||
15
|
||||
16 x87 FPU error
|
||||
17 alignment check
|
||||
18 machine check
|
||||
19 SIMD exception
|
||||
20 virtualization exception
|
||||
21 ~ 31 Do not use
|
||||
|
||||
32 ~ 55 I/O APIC
|
||||
32 8259A
|
||||
33 keyboard
|
||||
34 HPET timer 0,8254 counter 0
|
||||
35 serial port A
|
||||
36 serial port B
|
||||
37 parallel port
|
||||
38 floppy
|
||||
39 parallel port
|
||||
40 RTC,HPET timer 1
|
||||
41 Generic
|
||||
42 Generic
|
||||
43 HPET timer 2
|
||||
44 HPET timer 3 / mouse
|
||||
45 FERR#
|
||||
46 SATA primary
|
||||
47 SATA secondary
|
||||
48 PIRQA
|
||||
49 PIRQB
|
||||
50 PIRQC
|
||||
51 PIRQD
|
||||
52 PIRQE
|
||||
53 PIRQF
|
||||
54 PIRQG
|
||||
55 PIRQH
|
||||
56 VIRTIO_RECV
|
||||
57 E1000E_RECV
|
||||
|
||||
|
||||
0x80 system call
|
||||
0x81 system interrupt 系统中断
|
||||
|
||||
[150,200) Local APIC
|
||||
150 CMCI
|
||||
151 Timer
|
||||
152 Thermal Monitor
|
||||
153 Performance Counter
|
||||
154 LINT0
|
||||
155 LINT1
|
||||
156 Error
|
||||
157 xhci_controller_0
|
||||
158 xhci_controller_1
|
||||
159 xhci_controller_2
|
||||
160 xhci_controller_3
|
||||
|
||||
200 ~ 255 MP IPI
|
||||
|
||||
200 kick cpu 功能(使得某个核心立即运行进程调度)
|
||||
|
||||
*/
|
||||
|
||||
#define APIC_TIMER_IRQ_NUM 151
|
||||
|
||||
typedef struct hardware_intr_type
|
||||
{
|
||||
// 使能中断操作接口
|
||||
void (*enable)(ul irq_num);
|
||||
// 禁止中断操作接口
|
||||
void (*disable)(ul irq_num);
|
||||
|
||||
// 安装中断操作接口
|
||||
ul (*install)(ul irq_num, void *arg);
|
||||
// 卸载中断操作接口
|
||||
void (*uninstall)(ul irq_num);
|
||||
// 应答中断操作接口
|
||||
void (*ack)(ul irq_num);
|
||||
} hardware_intr_controller;
|
||||
|
||||
// 中断描述结构体
|
||||
typedef struct
|
||||
{
|
||||
hardware_intr_controller *controller;
|
||||
// 中断名
|
||||
char *irq_name;
|
||||
// 中断处理函数的参数
|
||||
ul parameter;
|
||||
// 中断处理函数
|
||||
void (*handler)(ul irq_num, ul parameter, struct pt_regs *regs);
|
||||
|
||||
// 自定义的标志位
|
||||
ul flags;
|
||||
} irq_desc_t;
|
||||
|
||||
|
||||
// 这几个表一定要放在这里,否则在HPET初始化后收到中断,会产生page fault
|
||||
irq_desc_t interrupt_desc[IRQ_NUM] = {0};
|
||||
irq_desc_t local_apic_interrupt_desc[LOCAL_APIC_IRQ_NUM] = {0};
|
||||
irq_desc_t SMP_IPI_desc[SMP_IRQ_NUM] = {0};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 中断注册函数
|
||||
*
|
||||
* @param irq_num 中断向量号
|
||||
* @param arg 传递给中断安装接口的参数
|
||||
* @param handler 中断处理函数
|
||||
* @param paramater 中断处理函数的参数
|
||||
* @param controller 中断控制器结构
|
||||
* @param irq_name 中断名
|
||||
* @return int
|
||||
*/
|
||||
int irq_register(ul irq_num, void *arg, void (*handler)(ul irq_num, ul parameter, struct pt_regs *regs), ul paramater, hardware_intr_controller *controller, char *irq_name);
|
||||
|
||||
/**
|
||||
* @brief 中断注销函数
|
||||
*
|
||||
* @param irq_num 中断向量号
|
||||
* @return int
|
||||
*/
|
||||
int irq_unregister(ul irq_num);
|
||||
|
||||
/**
|
||||
* @brief 初始化中断模块
|
||||
*/
|
||||
void irq_init();
|
||||
#pragma GCC pop_options
|
@ -6,11 +6,15 @@ use alloc::{
|
||||
};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{libs::spinlock::SpinLock, mm::VirtAddr};
|
||||
use crate::{
|
||||
libs::{cpumask::CpuMask, spinlock::SpinLock},
|
||||
mm::VirtAddr,
|
||||
};
|
||||
|
||||
use super::{
|
||||
irqdata::{IrqData, IrqLineStatus},
|
||||
irqdomain::IrqDomain,
|
||||
manage::IrqManager,
|
||||
msi::MsiMsg,
|
||||
};
|
||||
|
||||
@ -41,18 +45,58 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
||||
fn irq_ack(&self, irq: &Arc<IrqData>);
|
||||
|
||||
/// mask an interrupt source
|
||||
fn irq_mask(&self, _irq: &Arc<IrqData>) {}
|
||||
///
|
||||
/// 用于屏蔽中断
|
||||
///
|
||||
/// 如果返回ENOSYS,则表明irq_mask()不支持.
|
||||
///
|
||||
/// 如果返回错误,那么中断的屏蔽状态将不会改变。
|
||||
fn irq_mask(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
/// 指示当前芯片是否实现了`irq_mask_ack`函数
|
||||
fn can_mask_ack(&self) -> bool;
|
||||
|
||||
/// ack and mask an interrupt source
|
||||
fn irq_mask_ack(&self, _irq: &Arc<IrqData>) {}
|
||||
|
||||
/// unmask an interrupt source
|
||||
fn irq_unmask(&self, _irq: &Arc<IrqData>) {}
|
||||
///
|
||||
/// 用于取消屏蔽中断
|
||||
///
|
||||
/// 如果返回ENOSYS,则表明irq_unmask()不支持.
|
||||
fn irq_unmask(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
/// end of interrupt
|
||||
fn irq_eoi(&self, _irq: &Arc<IrqData>) {}
|
||||
|
||||
// todo: set affinity
|
||||
/// 指示当前芯片是否可以设置中断亲和性。
|
||||
fn can_set_affinity(&self) -> bool;
|
||||
|
||||
/// 在SMP机器上设置CPU亲和性。
|
||||
///
|
||||
/// 如果force参数为真,它告诉驱动程序无条件地应用亲和性设置。
|
||||
/// 不需要对提供的亲和性掩码进行完整性检查。这用于CPU热插拔,其中目标CPU尚未在cpu_online_mask中设置。
|
||||
fn irq_set_affinity(
|
||||
&self,
|
||||
_irq: &Arc<IrqData>,
|
||||
_cpu: &CpuMask,
|
||||
_force: bool,
|
||||
) -> Result<IrqChipSetMaskResult, SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
/// retrigger an IRQ to the CPU
|
||||
fn retrigger(&self, _irq: &Arc<IrqData>) {}
|
||||
fn retrigger(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
/// 指示当前芯片是否可以设置中断流类型。
|
||||
///
|
||||
/// 如果返回true,则可以调用irq_set_type()。
|
||||
fn can_set_flow_type(&self) -> bool;
|
||||
|
||||
/// set the flow type of an interrupt
|
||||
///
|
||||
@ -62,7 +106,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
||||
&self,
|
||||
_irq: &Arc<IrqData>,
|
||||
_flow_type: IrqLineStatus,
|
||||
) -> Result<(), SystemError> {
|
||||
) -> Result<IrqChipSetMaskResult, SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
@ -108,6 +152,8 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
||||
fn irq_release_resources(&self, _irq: &Arc<IrqData>) {}
|
||||
|
||||
/// optional to compose message content for MSI
|
||||
///
|
||||
/// 组装MSI消息并返回到msg中
|
||||
fn irq_compose_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &mut MsiMsg) {}
|
||||
|
||||
/// optional to write message content for MSI
|
||||
@ -163,7 +209,10 @@ pub enum IrqChipState {
|
||||
LineLevel,
|
||||
}
|
||||
|
||||
pub trait IrqChipData: Sync + Send + Any + Debug {}
|
||||
/// 中断芯片的数据(per-irq的)
|
||||
pub trait IrqChipData: Sync + Send + Any + Debug {
|
||||
fn as_any_ref(&self) -> &dyn Any;
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// 定义 IrqGcFlags 位标志
|
||||
@ -240,10 +289,23 @@ pub struct IrqChipType {
|
||||
// todo https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#1024
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum IrqChipSetMaskResult {
|
||||
/// core updates mask ok.
|
||||
SetMaskOk,
|
||||
/// core updates mask ok. No change.
|
||||
SetMaskOkNoChange,
|
||||
/// core updates mask ok. Done.(same as SetMaskOk)
|
||||
///
|
||||
/// 支持堆叠irq芯片的特殊代码, 表示跳过所有子irq芯片。
|
||||
SetMaskOkDone,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// IrqChip specific flags
|
||||
pub struct IrqChipFlags: u32 {
|
||||
/// 在调用chip.irq_set_type()之前屏蔽
|
||||
/// 在调用chip.irq_set_type()之前屏蔽中断
|
||||
const IRQCHIP_SET_TYPE_MASKED = 1 << 0;
|
||||
/// 只有在irq被处理时才发出irq_eoi()
|
||||
const IRQCHIP_EOI_IF_HANDLED = 1 << 1;
|
||||
@ -269,3 +331,40 @@ bitflags! {
|
||||
const IRQCHIP_IMMUTABLE = 1 << 11;
|
||||
}
|
||||
}
|
||||
|
||||
impl IrqManager {
|
||||
/// Acknowledge the parent interrupt
|
||||
#[allow(dead_code)]
|
||||
pub fn irq_chip_ack_parent(&self, irq_data: &Arc<IrqData>) {
|
||||
let parent_data = irq_data.parent_data().map(|p| p.upgrade()).flatten();
|
||||
|
||||
if let Some(parent_data) = parent_data {
|
||||
let parent_chip = parent_data.chip_info_read_irqsave().chip();
|
||||
parent_chip.irq_ack(&parent_data);
|
||||
}
|
||||
}
|
||||
|
||||
/// 在硬件中重新触发中断
|
||||
///
|
||||
/// 遍历中断域的层次结构,并检查是否存在一个硬件重新触发函数。如果存在则调用它
|
||||
pub fn irq_chip_retrigger_hierarchy(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||
let mut data: Option<Arc<IrqData>> = Some(irq_data.clone());
|
||||
loop {
|
||||
if let Some(d) = data {
|
||||
if let Err(e) = d.chip_info_read_irqsave().chip().retrigger(&d) {
|
||||
if e == SystemError::ENOSYS {
|
||||
data = d.parent_data().map(|p| p.upgrade()).flatten();
|
||||
} else {
|
||||
return Err(e);
|
||||
}
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,13 @@
|
||||
use core::{any::Any, fmt::Debug};
|
||||
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use intertrait::CastFromSync;
|
||||
|
||||
use crate::libs::spinlock::SpinLock;
|
||||
use crate::libs::{
|
||||
cpumask::CpuMask,
|
||||
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
};
|
||||
|
||||
use super::{
|
||||
irqchip::{IrqChip, IrqChipData},
|
||||
@ -22,6 +27,8 @@ pub struct IrqData {
|
||||
/// 中断号, 用于表示软件逻辑视角的中断号,全局唯一
|
||||
irq: IrqNumber,
|
||||
inner: SpinLock<InnerIrqData>,
|
||||
|
||||
chip_info: RwLock<InnerIrqChipInfo>,
|
||||
}
|
||||
|
||||
impl IrqData {
|
||||
@ -36,25 +43,28 @@ impl IrqData {
|
||||
inner: SpinLock::new(InnerIrqData {
|
||||
hwirq,
|
||||
common_data,
|
||||
chip,
|
||||
chip_data: None,
|
||||
|
||||
domain: None,
|
||||
parent_data: None,
|
||||
}),
|
||||
chip_info: RwLock::new(InnerIrqChipInfo {
|
||||
chip: Some(chip),
|
||||
chip_data: None,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn irqd_set(&self, status: IrqStatus) {
|
||||
// clone是为了释放inner锁
|
||||
let common_data = self.inner.lock().common_data.clone();
|
||||
common_data.irqd_set(status);
|
||||
let common_data = self.inner.lock_irqsave().common_data.clone();
|
||||
common_data.insert_status(status);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn irqd_clear(&self, status: IrqStatus) {
|
||||
// clone是为了释放inner锁
|
||||
let common_data = self.inner.lock().common_data.clone();
|
||||
common_data.irqd_clear(status);
|
||||
let common_data = self.inner.lock_irqsave().common_data.clone();
|
||||
common_data.clear_status(status);
|
||||
}
|
||||
|
||||
pub fn irq(&self) -> IrqNumber {
|
||||
@ -65,17 +75,13 @@ impl IrqData {
|
||||
self.inner.lock_irqsave().hwirq
|
||||
}
|
||||
|
||||
pub fn chip(&self) -> Arc<dyn IrqChip> {
|
||||
self.inner.lock_irqsave().chip.clone()
|
||||
}
|
||||
|
||||
/// 是否为电平触发
|
||||
pub fn is_level_type(&self) -> bool {
|
||||
self.inner
|
||||
.lock_irqsave()
|
||||
.common_data
|
||||
.inner
|
||||
.lock()
|
||||
.lock_irqsave()
|
||||
.state
|
||||
.is_level_type()
|
||||
}
|
||||
@ -85,29 +91,95 @@ impl IrqData {
|
||||
.lock_irqsave()
|
||||
.common_data
|
||||
.inner
|
||||
.lock()
|
||||
.lock_irqsave()
|
||||
.state
|
||||
.is_wakeup_set()
|
||||
}
|
||||
|
||||
pub fn common_data(&self) -> Arc<IrqCommonData> {
|
||||
self.inner.lock_irqsave().common_data.clone()
|
||||
}
|
||||
|
||||
pub fn domain(&self) -> Option<Arc<IrqDomain>> {
|
||||
self.inner.lock_irqsave().domain.clone()
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> SpinLockGuard<InnerIrqData> {
|
||||
self.inner.lock_irqsave()
|
||||
}
|
||||
|
||||
pub fn chip_info_read(&self) -> RwLockReadGuard<InnerIrqChipInfo> {
|
||||
self.chip_info.read()
|
||||
}
|
||||
|
||||
pub fn chip_info_read_irqsave(&self) -> RwLockReadGuard<InnerIrqChipInfo> {
|
||||
self.chip_info.read_irqsave()
|
||||
}
|
||||
|
||||
pub fn chip_info_write_irqsave(&self) -> RwLockWriteGuard<InnerIrqChipInfo> {
|
||||
self.chip_info.write_irqsave()
|
||||
}
|
||||
|
||||
pub fn parent_data(&self) -> Option<Weak<IrqData>> {
|
||||
self.inner.lock_irqsave().parent_data.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct InnerIrqData {
|
||||
pub struct InnerIrqData {
|
||||
/// 硬件中断号, 用于表示在某个IrqDomain中的中断号
|
||||
hwirq: HardwareIrqNumber,
|
||||
/// 涉及的所有irqchip之间共享的数据
|
||||
common_data: Arc<IrqCommonData>,
|
||||
/// 绑定到的中断芯片
|
||||
chip: Arc<dyn IrqChip>,
|
||||
/// 中断芯片的私有数据(与当前irq相关)
|
||||
chip_data: Option<Arc<dyn IrqChipData>>,
|
||||
|
||||
/// 中断域
|
||||
domain: Option<Arc<IrqDomain>>,
|
||||
/// 中断的父中断(如果具有中断域继承的话)
|
||||
parent_data: Option<Weak<IrqData>>,
|
||||
}
|
||||
|
||||
impl InnerIrqData {
|
||||
pub fn set_hwirq(&mut self, hwirq: HardwareIrqNumber) {
|
||||
self.hwirq = hwirq;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn domain(&self) -> Option<Arc<IrqDomain>> {
|
||||
self.domain.clone()
|
||||
}
|
||||
|
||||
pub fn set_domain(&mut self, domain: Option<Arc<IrqDomain>>) {
|
||||
self.domain = domain;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InnerIrqChipInfo {
|
||||
/// 绑定到的中断芯片
|
||||
chip: Option<Arc<dyn IrqChip>>,
|
||||
/// 中断芯片的私有数据(与当前irq相关)
|
||||
chip_data: Option<Arc<dyn IrqChipData>>,
|
||||
}
|
||||
|
||||
impl InnerIrqChipInfo {
|
||||
pub fn set_chip(&mut self, chip: Option<Arc<dyn IrqChip>>) {
|
||||
self.chip = chip;
|
||||
}
|
||||
|
||||
pub fn set_chip_data(&mut self, chip_data: Option<Arc<dyn IrqChipData>>) {
|
||||
self.chip_data = chip_data;
|
||||
}
|
||||
|
||||
pub fn chip(&self) -> Arc<dyn IrqChip> {
|
||||
self.chip.clone().unwrap()
|
||||
}
|
||||
|
||||
pub fn chip_data(&self) -> Option<Arc<dyn IrqChipData>> {
|
||||
self.chip_data.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// per irq data shared by all irqchips
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#147
|
||||
@ -122,19 +194,100 @@ impl IrqCommonData {
|
||||
state: IrqStatus::empty(),
|
||||
handler_data: None,
|
||||
msi_desc: None,
|
||||
affinity: CpuMask::new(),
|
||||
};
|
||||
return IrqCommonData {
|
||||
inner: SpinLock::new(inner),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn irqd_set(&self, status: IrqStatus) {
|
||||
self.inner.lock_irqsave().irqd_set(status);
|
||||
pub fn insert_status(&self, status: IrqStatus) {
|
||||
self.inner.lock_irqsave().irqd_insert(status);
|
||||
}
|
||||
|
||||
pub fn irqd_clear(&self, status: IrqStatus) {
|
||||
pub fn clear_status(&self, status: IrqStatus) {
|
||||
self.inner.lock_irqsave().irqd_clear(status);
|
||||
}
|
||||
|
||||
pub fn clear_managed_shutdown(&self) {
|
||||
self.inner
|
||||
.lock_irqsave()
|
||||
.state
|
||||
.remove(IrqStatus::IRQD_MANAGED_SHUTDOWN);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn masked(&self) -> bool {
|
||||
self.inner.lock_irqsave().state.masked()
|
||||
}
|
||||
|
||||
pub fn set_masked(&self) {
|
||||
self.inner
|
||||
.lock_irqsave()
|
||||
.state
|
||||
.insert(IrqStatus::IRQD_IRQ_MASKED);
|
||||
}
|
||||
|
||||
pub fn clear_masked(&self) {
|
||||
self.clear_status(IrqStatus::IRQD_IRQ_MASKED);
|
||||
}
|
||||
|
||||
pub fn set_inprogress(&self) {
|
||||
self.inner
|
||||
.lock_irqsave()
|
||||
.state
|
||||
.insert(IrqStatus::IRQD_IRQ_INPROGRESS);
|
||||
}
|
||||
|
||||
pub fn clear_inprogress(&self) {
|
||||
self.inner
|
||||
.lock_irqsave()
|
||||
.state
|
||||
.remove(IrqStatus::IRQD_IRQ_INPROGRESS);
|
||||
}
|
||||
|
||||
pub fn disabled(&self) -> bool {
|
||||
self.inner.lock_irqsave().state.disabled()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn set_disabled(&self) {
|
||||
self.inner
|
||||
.lock_irqsave()
|
||||
.state
|
||||
.insert(IrqStatus::IRQD_IRQ_DISABLED);
|
||||
}
|
||||
|
||||
pub fn clear_disabled(&self) {
|
||||
self.clear_status(IrqStatus::IRQD_IRQ_DISABLED);
|
||||
}
|
||||
|
||||
pub fn status(&self) -> IrqStatus {
|
||||
self.inner.lock_irqsave().state
|
||||
}
|
||||
|
||||
pub fn trigger_type(&self) -> IrqLineStatus {
|
||||
self.inner.lock_irqsave().state.trigger_type()
|
||||
}
|
||||
|
||||
pub fn set_trigger_type(&self, trigger: IrqLineStatus) {
|
||||
self.inner.lock_irqsave().state.set_trigger_type(trigger);
|
||||
}
|
||||
|
||||
pub fn set_started(&self) {
|
||||
self.inner
|
||||
.lock_irqsave()
|
||||
.state
|
||||
.insert(IrqStatus::IRQD_IRQ_STARTED);
|
||||
}
|
||||
|
||||
pub fn affinity(&self) -> CpuMask {
|
||||
self.inner.lock_irqsave().affinity.clone()
|
||||
}
|
||||
|
||||
pub fn set_affinity(&self, affinity: CpuMask) {
|
||||
self.inner.lock_irqsave().affinity = affinity;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -145,11 +298,11 @@ struct InnerIrqCommonData {
|
||||
/// per-IRQ data for the irq_chip methods
|
||||
handler_data: Option<Arc<dyn IrqHandlerData>>,
|
||||
msi_desc: Option<Arc<MsiDesc>>,
|
||||
// todo: affinity
|
||||
affinity: CpuMask,
|
||||
}
|
||||
|
||||
impl InnerIrqCommonData {
|
||||
pub fn irqd_set(&mut self, status: IrqStatus) {
|
||||
pub fn irqd_insert(&mut self, status: IrqStatus) {
|
||||
self.state.insert(status);
|
||||
}
|
||||
|
||||
@ -158,7 +311,8 @@ impl InnerIrqCommonData {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IrqHandlerData: Send + Sync + Any + Debug {}
|
||||
/// 中断处理函数传入的数据
|
||||
pub trait IrqHandlerData: Send + Sync + Any + Debug + CastFromSync {}
|
||||
|
||||
bitflags! {
|
||||
/// 中断线状态
|
||||
@ -219,12 +373,45 @@ bitflags! {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
impl IrqLineStatus {
|
||||
pub const fn trigger_bits(&self) -> u32 {
|
||||
self.bits & Self::IRQ_TYPE_SENSE_MASK.bits
|
||||
}
|
||||
|
||||
pub fn trigger_type(&self) -> Self {
|
||||
*self & Self::IRQ_TYPE_SENSE_MASK
|
||||
}
|
||||
|
||||
pub fn is_level_type(&self) -> bool {
|
||||
self.contains(Self::IRQ_LEVEL)
|
||||
}
|
||||
|
||||
/// 是否为高电平触发
|
||||
///
|
||||
/// ## 返回
|
||||
///
|
||||
/// - 如果不是电平触发类型,则返回None
|
||||
/// - 如果是电平触发类型,则返回Some(bool),当为true时表示高电平触发
|
||||
pub fn is_level_high(&self) -> Option<bool> {
|
||||
if !self.is_level_type() {
|
||||
return None;
|
||||
}
|
||||
return Some(self.contains(Self::IRQ_TYPE_LEVEL_HIGH));
|
||||
}
|
||||
}
|
||||
bitflags! {
|
||||
/// 中断状态(存储在IrqCommonData)
|
||||
///
|
||||
/// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irq.h#227
|
||||
pub struct IrqStatus: u32 {
|
||||
const IRQD_TRIGGER_NONE = IrqLineStatus::IRQ_TYPE_NONE.bits();
|
||||
const IRQD_TRIGGER_RISING = IrqLineStatus::IRQ_TYPE_EDGE_RISING.bits();
|
||||
const IRQD_TRIGGER_FALLING = IrqLineStatus::IRQ_TYPE_EDGE_FALLING.bits();
|
||||
const IRQD_TRIGGER_HIGH = IrqLineStatus::IRQ_TYPE_LEVEL_HIGH.bits();
|
||||
const IRQD_TRIGGER_LOW = IrqLineStatus::IRQ_TYPE_LEVEL_LOW.bits();
|
||||
|
||||
/// 触发类型位的掩码
|
||||
const IRQD_TRIGGER_MASK = 0xf;
|
||||
/// 亲和性设置待处理
|
||||
@ -261,7 +448,7 @@ bitflags! {
|
||||
const IRQD_MANAGED_SHUTDOWN = 1 << 23;
|
||||
/// IRQ只允许单个亲和性目标
|
||||
const IRQD_SINGLE_TARGET = 1 << 24;
|
||||
/// 预期的触发器已设置
|
||||
/// 默认的触发器已设置
|
||||
const IRQD_DEFAULT_TRIGGER_SET = 1 << 25;
|
||||
/// 可以使用保留模式
|
||||
const IRQD_CAN_RESERVE = 1 << 26;
|
||||
@ -294,6 +481,14 @@ impl IrqStatus {
|
||||
self.contains(Self::IRQD_AFFINITY_SET)
|
||||
}
|
||||
|
||||
pub fn masked(&self) -> bool {
|
||||
self.contains(Self::IRQD_IRQ_MASKED)
|
||||
}
|
||||
|
||||
pub fn disabled(&self) -> bool {
|
||||
self.contains(Self::IRQD_IRQ_DISABLED)
|
||||
}
|
||||
|
||||
pub fn mark_affinity_set(&mut self) {
|
||||
self.insert(Self::IRQD_AFFINITY_SET);
|
||||
}
|
||||
@ -353,14 +548,6 @@ impl IrqStatus {
|
||||
self.contains(Self::IRQD_MOVE_PCNTXT)
|
||||
}
|
||||
|
||||
pub const fn is_irq_disabled(&self) -> bool {
|
||||
self.contains(Self::IRQD_IRQ_DISABLED)
|
||||
}
|
||||
|
||||
pub const fn is_irq_masked(&self) -> bool {
|
||||
self.contains(Self::IRQD_IRQ_MASKED)
|
||||
}
|
||||
|
||||
pub const fn is_irq_in_progress(&self) -> bool {
|
||||
self.contains(Self::IRQD_IRQ_INPROGRESS)
|
||||
}
|
||||
@ -377,7 +564,7 @@ impl IrqStatus {
|
||||
self.insert(Self::IRQD_FORWARDED_TO_VCPU);
|
||||
}
|
||||
|
||||
pub const fn is_affinity_managed(&self) -> bool {
|
||||
pub const fn affinity_managed(&self) -> bool {
|
||||
self.contains(Self::IRQD_AFFINITY_MANAGED)
|
||||
}
|
||||
|
||||
@ -432,4 +619,8 @@ impl IrqStatus {
|
||||
pub const fn is_affinity_on_activate(&self) -> bool {
|
||||
self.contains(Self::IRQD_AFFINITY_ON_ACTIVATE)
|
||||
}
|
||||
|
||||
pub const fn started(&self) -> bool {
|
||||
self.contains(Self::IRQD_IRQ_STARTED)
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,8 @@
|
||||
use core::{any::Any, fmt::Debug};
|
||||
use core::{
|
||||
any::Any,
|
||||
fmt::Debug,
|
||||
sync::atomic::{AtomicI64, Ordering},
|
||||
};
|
||||
|
||||
use alloc::{
|
||||
collections::{btree_map, BTreeMap},
|
||||
@ -9,7 +13,7 @@ use alloc::{
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::CurrentIrqArch,
|
||||
arch::{interrupt::TrapFrame, CurrentIrqArch},
|
||||
driver::base::{
|
||||
device::DeviceId,
|
||||
kobject::{KObjType, KObject, KObjectState, LockedKObjectState},
|
||||
@ -17,23 +21,48 @@ use crate::{
|
||||
},
|
||||
filesystem::kernfs::KernFSInode,
|
||||
libs::{
|
||||
rwlock::{RwLockReadGuard, RwLockWriteGuard},
|
||||
mutex::{Mutex, MutexGuard},
|
||||
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
process::ProcessControlBlock,
|
||||
sched::completion::Completion,
|
||||
};
|
||||
|
||||
use super::{
|
||||
dummychip::no_irq_chip,
|
||||
handle::bad_irq_handler,
|
||||
irqdata::{IrqCommonData, IrqData, IrqStatus},
|
||||
irqdata::{IrqCommonData, IrqData, IrqHandlerData, IrqLineStatus, IrqStatus},
|
||||
sysfs::{irq_sysfs_del, IrqKObjType},
|
||||
HardwareIrqNumber, InterruptArch, IrqNumber,
|
||||
};
|
||||
|
||||
/// 中断流处理程序
|
||||
pub trait IrqFlowHandler: Debug + Send + Sync {
|
||||
fn handle(&self, irq_desc: &Arc<IrqDesc>);
|
||||
pub trait IrqFlowHandler: Debug + Send + Sync + Any {
|
||||
fn handle(&self, irq_desc: &Arc<IrqDesc>, trap_frame: &mut TrapFrame);
|
||||
}
|
||||
|
||||
/// 中断处理程序
|
||||
pub trait IrqHandler: Debug + Send + Sync + Any {
|
||||
fn handle(
|
||||
&self,
|
||||
irq: IrqNumber,
|
||||
static_data: Option<&dyn IrqHandlerData>,
|
||||
dynamic_data: Option<Arc<dyn IrqHandlerData>>,
|
||||
) -> Result<IrqReturn, SystemError>;
|
||||
}
|
||||
|
||||
/// 中断处理函数返回值
|
||||
///
|
||||
/// 用于指示中断处理函数是否处理了中断
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum IrqReturn {
|
||||
/// 中断未被处理
|
||||
NotHandled,
|
||||
/// 中断已被处理
|
||||
Handled,
|
||||
/// 中断已被处理,并且需要唤醒中断线程
|
||||
WakeThread,
|
||||
}
|
||||
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdesc.h#55
|
||||
@ -41,9 +70,12 @@ pub trait IrqFlowHandler: Debug + Send + Sync {
|
||||
pub struct IrqDesc {
|
||||
inner: SpinLock<InnerIrqDesc>,
|
||||
|
||||
handler: SpinLock<Option<&'static dyn IrqFlowHandler>>,
|
||||
|
||||
handler: RwLock<Option<&'static dyn IrqFlowHandler>>,
|
||||
/// 一个用于串行化 request_irq()和free_irq() 的互斥锁
|
||||
request_mutex: Mutex<()>,
|
||||
kobj_state: LockedKObjectState,
|
||||
/// 当前描述符内正在运行的中断线程数
|
||||
threads_active: AtomicI64,
|
||||
}
|
||||
|
||||
impl IrqDesc {
|
||||
@ -59,13 +91,14 @@ impl IrqDesc {
|
||||
));
|
||||
|
||||
irq_data.irqd_set(IrqStatus::IRQD_IRQ_DISABLED);
|
||||
common_data.irqd_set(IrqStatus::IRQD_IRQ_MASKED);
|
||||
common_data.insert_status(IrqStatus::IRQD_IRQ_MASKED);
|
||||
|
||||
let irq_desc = IrqDesc {
|
||||
inner: SpinLock::new(InnerIrqDesc {
|
||||
common_data,
|
||||
irq_data,
|
||||
desc_internal_state: IrqDescState::empty(),
|
||||
line_status: IrqLineStatus::empty(),
|
||||
actions: Vec::new(),
|
||||
name,
|
||||
parent_irq: None,
|
||||
@ -75,8 +108,10 @@ impl IrqDesc {
|
||||
kset: None,
|
||||
parent_kobj: None,
|
||||
}),
|
||||
handler: SpinLock::new(None),
|
||||
request_mutex: Mutex::new(()),
|
||||
handler: RwLock::new(None),
|
||||
kobj_state: LockedKObjectState::new(Some(KObjectState::INITIALIZED)),
|
||||
threads_active: AtomicI64::new(0),
|
||||
};
|
||||
|
||||
irq_desc.set_handler(bad_irq_handler());
|
||||
@ -85,12 +120,36 @@ impl IrqDesc {
|
||||
return Arc::new(irq_desc);
|
||||
}
|
||||
|
||||
pub fn set_handler(&self, handler: &'static dyn IrqFlowHandler) {
|
||||
let mut guard = self.handler.lock_irqsave();
|
||||
*guard = Some(handler);
|
||||
/// 返回当前活跃的中断线程数量
|
||||
#[allow(dead_code)]
|
||||
pub fn threads_active(&self) -> i64 {
|
||||
self.threads_active.load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
fn inner(&self) -> SpinLockGuard<InnerIrqDesc> {
|
||||
/// 增加当前活跃的中断线程数量, 返回增加前的值
|
||||
pub fn inc_threads_active(&self) -> i64 {
|
||||
self.threads_active.fetch_add(1, Ordering::SeqCst)
|
||||
}
|
||||
|
||||
/// 减少当前活跃的中断线程数量, 返回减少前的值
|
||||
#[allow(dead_code)]
|
||||
pub fn dec_threads_active(&self) -> i64 {
|
||||
self.threads_active.fetch_sub(1, Ordering::SeqCst)
|
||||
}
|
||||
|
||||
pub fn set_handler(&self, handler: &'static dyn IrqFlowHandler) {
|
||||
self.chip_bus_lock();
|
||||
let mut guard = self.handler.write_irqsave();
|
||||
*guard = Some(handler);
|
||||
self.chip_bus_sync_unlock();
|
||||
}
|
||||
|
||||
pub fn handler(&self) -> Option<&'static dyn IrqFlowHandler> {
|
||||
let guard = self.handler.read_irqsave();
|
||||
*guard
|
||||
}
|
||||
|
||||
pub fn inner(&self) -> SpinLockGuard<InnerIrqDesc> {
|
||||
self.inner.lock_irqsave()
|
||||
}
|
||||
|
||||
@ -98,6 +157,11 @@ impl IrqDesc {
|
||||
self.inner().actions.clone()
|
||||
}
|
||||
|
||||
/// 对中断请求过程加锁
|
||||
pub fn request_mutex_lock(&self) -> MutexGuard<()> {
|
||||
self.request_mutex.lock()
|
||||
}
|
||||
|
||||
pub fn irq(&self) -> IrqNumber {
|
||||
self.inner().irq_data.irq()
|
||||
}
|
||||
@ -133,11 +197,115 @@ impl IrqDesc {
|
||||
pub fn name(&self) -> Option<String> {
|
||||
self.inner().name.clone()
|
||||
}
|
||||
|
||||
pub fn can_request(&self) -> bool {
|
||||
self.inner().can_request()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn set_norequest(&self) {
|
||||
self.inner().set_norequest();
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn clear_norequest(&self) {
|
||||
self.inner().clear_norequest();
|
||||
}
|
||||
|
||||
pub fn nested_thread(&self) -> bool {
|
||||
self.inner().nested_thread()
|
||||
}
|
||||
|
||||
/// 中断是否可以线程化
|
||||
pub fn can_thread(&self) -> bool {
|
||||
!self
|
||||
.inner()
|
||||
.line_status
|
||||
.contains(IrqLineStatus::IRQ_NOTHREAD)
|
||||
}
|
||||
|
||||
pub fn chip_bus_lock(&self) {
|
||||
let irq_data = self.inner().irq_data.clone();
|
||||
irq_data
|
||||
.chip_info_read_irqsave()
|
||||
.chip()
|
||||
.irq_bus_lock(&irq_data)
|
||||
.ok();
|
||||
}
|
||||
|
||||
/// 同步释放低速总线锁
|
||||
///
|
||||
/// ## 锁
|
||||
///
|
||||
/// 进入此函数时,必须持有低速总线锁,并且desc的inner锁和irqdata的inner锁
|
||||
/// 必须已经释放。否则将死锁。
|
||||
pub fn chip_bus_sync_unlock(&self) {
|
||||
let irq_data = self.inner().irq_data.clone();
|
||||
irq_data
|
||||
.chip_info_write_irqsave()
|
||||
.chip()
|
||||
.irq_bus_sync_unlock(&irq_data)
|
||||
.ok();
|
||||
}
|
||||
|
||||
pub fn modify_status(&self, clear: IrqLineStatus, set: IrqLineStatus) {
|
||||
let mut desc_guard = self.inner();
|
||||
desc_guard.line_status.remove(clear);
|
||||
desc_guard.line_status.insert(set);
|
||||
|
||||
let mut trigger = desc_guard.common_data().trigger_type();
|
||||
|
||||
desc_guard.common_data().clear_status(
|
||||
IrqStatus::IRQD_NO_BALANCING
|
||||
| IrqStatus::IRQD_PER_CPU
|
||||
| IrqStatus::IRQD_TRIGGER_MASK
|
||||
| IrqStatus::IRQD_LEVEL
|
||||
| IrqStatus::IRQD_MOVE_PCNTXT,
|
||||
);
|
||||
|
||||
if desc_guard
|
||||
.line_status
|
||||
.contains(IrqLineStatus::IRQ_NO_BALANCING)
|
||||
{
|
||||
desc_guard
|
||||
.common_data()
|
||||
.insert_status(IrqStatus::IRQD_NO_BALANCING);
|
||||
}
|
||||
|
||||
if desc_guard.line_status.contains(IrqLineStatus::IRQ_PER_CPU) {
|
||||
desc_guard
|
||||
.common_data()
|
||||
.insert_status(IrqStatus::IRQD_PER_CPU);
|
||||
}
|
||||
|
||||
if desc_guard
|
||||
.line_status
|
||||
.contains(IrqLineStatus::IRQ_MOVE_PCNTXT)
|
||||
{
|
||||
desc_guard
|
||||
.common_data()
|
||||
.insert_status(IrqStatus::IRQD_MOVE_PCNTXT);
|
||||
}
|
||||
|
||||
if desc_guard.line_status.is_level_type() {
|
||||
desc_guard
|
||||
.common_data()
|
||||
.insert_status(IrqStatus::IRQD_LEVEL);
|
||||
}
|
||||
|
||||
let tmp = desc_guard.line_status.trigger_type();
|
||||
|
||||
if tmp != IrqLineStatus::IRQ_TYPE_NONE {
|
||||
trigger = tmp;
|
||||
}
|
||||
|
||||
desc_guard.common_data().set_trigger_type(trigger);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct InnerIrqDesc {
|
||||
pub struct InnerIrqDesc {
|
||||
/// per irq and chip data passed down to chip functions
|
||||
common_data: Arc<IrqCommonData>,
|
||||
irq_data: Arc<IrqData>,
|
||||
@ -149,10 +317,134 @@ struct InnerIrqDesc {
|
||||
/// nested wake enables
|
||||
wake_depth: u32,
|
||||
desc_internal_state: IrqDescState,
|
||||
/// 中断线的状态
|
||||
line_status: IrqLineStatus,
|
||||
|
||||
kern_inode: Option<Arc<KernFSInode>>,
|
||||
kset: Option<Arc<KSet>>,
|
||||
parent_kobj: Option<Weak<dyn KObject>>,
|
||||
// wait_for_threads: EventWaitQueue
|
||||
}
|
||||
|
||||
impl InnerIrqDesc {
|
||||
pub fn name(&self) -> Option<&String> {
|
||||
self.name.as_ref()
|
||||
}
|
||||
|
||||
pub fn can_request(&self) -> bool {
|
||||
!self.line_status.contains(IrqLineStatus::IRQ_NOREQUEST)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn set_norequest(&mut self) {
|
||||
self.line_status.insert(IrqLineStatus::IRQ_NOREQUEST);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn clear_norequest(&mut self) {
|
||||
self.line_status.remove(IrqLineStatus::IRQ_NOREQUEST);
|
||||
}
|
||||
|
||||
pub fn nested_thread(&self) -> bool {
|
||||
self.line_status.contains(IrqLineStatus::IRQ_NESTED_THREAD)
|
||||
}
|
||||
|
||||
pub fn line_status_set_per_cpu(&mut self) {
|
||||
self.line_status.insert(IrqLineStatus::IRQ_PER_CPU);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn line_status_clear_per_cpu(&mut self) {
|
||||
self.line_status.remove(IrqLineStatus::IRQ_PER_CPU);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn line_status(&self) -> &IrqLineStatus {
|
||||
&self.line_status
|
||||
}
|
||||
|
||||
pub fn line_status_set_no_debug(&mut self) {
|
||||
self.line_status.insert(IrqLineStatus::IRQ_NO_BALANCING);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn line_status_clear_no_debug(&mut self) {
|
||||
self.line_status.remove(IrqLineStatus::IRQ_NO_BALANCING);
|
||||
}
|
||||
|
||||
pub fn can_autoenable(&self) -> bool {
|
||||
!self.line_status.contains(IrqLineStatus::IRQ_NOAUTOEN)
|
||||
}
|
||||
|
||||
pub fn can_thread(&self) -> bool {
|
||||
!self.line_status.contains(IrqLineStatus::IRQ_NOTHREAD)
|
||||
}
|
||||
|
||||
/// 中断是否可以设置CPU亲和性
|
||||
pub fn can_set_affinity(&self) -> bool {
|
||||
if self.common_data.status().can_balance() == false
|
||||
|| self
|
||||
.irq_data()
|
||||
.chip_info_read_irqsave()
|
||||
.chip()
|
||||
.can_set_affinity()
|
||||
== false
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pub fn actions(&self) -> &Vec<Arc<IrqAction>> {
|
||||
&self.actions
|
||||
}
|
||||
|
||||
pub fn add_action(&mut self, action: Arc<IrqAction>) {
|
||||
self.actions.push(action);
|
||||
}
|
||||
|
||||
pub fn internal_state(&self) -> &IrqDescState {
|
||||
&self.desc_internal_state
|
||||
}
|
||||
|
||||
pub(super) fn internal_state_mut(&mut self) -> &mut IrqDescState {
|
||||
&mut self.desc_internal_state
|
||||
}
|
||||
|
||||
pub fn irq_data(&self) -> &Arc<IrqData> {
|
||||
&self.irq_data
|
||||
}
|
||||
|
||||
pub fn common_data(&self) -> &Arc<IrqCommonData> {
|
||||
&self.common_data
|
||||
}
|
||||
|
||||
pub fn depth(&self) -> u32 {
|
||||
self.depth
|
||||
}
|
||||
|
||||
pub fn wake_depth(&self) -> u32 {
|
||||
self.wake_depth
|
||||
}
|
||||
|
||||
pub fn set_depth(&mut self, depth: u32) {
|
||||
self.depth = depth;
|
||||
}
|
||||
|
||||
pub fn set_trigger_type(&mut self, trigger: IrqLineStatus) {
|
||||
self.line_status.remove(IrqLineStatus::IRQ_TYPE_SENSE_MASK);
|
||||
self.line_status
|
||||
.insert(trigger & IrqLineStatus::IRQ_TYPE_SENSE_MASK);
|
||||
}
|
||||
|
||||
pub fn clear_level(&mut self) {
|
||||
self.line_status.remove(IrqLineStatus::IRQ_LEVEL);
|
||||
}
|
||||
|
||||
pub fn set_level(&mut self) {
|
||||
self.line_status.insert(IrqLineStatus::IRQ_LEVEL);
|
||||
}
|
||||
}
|
||||
|
||||
impl KObject for IrqDesc {
|
||||
@ -211,7 +503,7 @@ impl KObject for IrqDesc {
|
||||
|
||||
bitflags! {
|
||||
/// Bit masks for desc->desc_internal_state
|
||||
struct IrqDescState: u32 {
|
||||
pub struct IrqDescState: u32 {
|
||||
/// autodetection in progress
|
||||
const IRQS_AUTODETECT = 0x00000001;
|
||||
/// was disabled due to spurious interrupt detection
|
||||
@ -241,6 +533,8 @@ bitflags! {
|
||||
#[derive(Debug)]
|
||||
pub struct IrqAction {
|
||||
inner: SpinLock<InnerIrqAction>,
|
||||
/// 用于等待线程被创建的完成量
|
||||
thread_completion: Completion,
|
||||
}
|
||||
|
||||
impl IrqAction {
|
||||
@ -248,42 +542,45 @@ impl IrqAction {
|
||||
pub fn new(
|
||||
irq: IrqNumber,
|
||||
name: String,
|
||||
handler: Option<&'static dyn IrqFlowHandler>,
|
||||
handler: Option<&'static dyn IrqHandler>,
|
||||
thread_fn: Option<&'static dyn IrqHandler>,
|
||||
) -> Arc<Self> {
|
||||
let action = IrqAction {
|
||||
let action: IrqAction = IrqAction {
|
||||
inner: SpinLock::new(InnerIrqAction {
|
||||
dev_id: None,
|
||||
handler,
|
||||
thread_fn: None,
|
||||
thread_fn,
|
||||
thread: None,
|
||||
secondary: None,
|
||||
irq,
|
||||
flags: IrqHandleFlags::empty(),
|
||||
name,
|
||||
thread_flags: ThreadedHandlerFlags::empty(),
|
||||
}),
|
||||
thread_completion: Completion::new(),
|
||||
};
|
||||
|
||||
return Arc::new(action);
|
||||
}
|
||||
|
||||
pub fn name(&self) -> String {
|
||||
self.inner().name.clone()
|
||||
pub fn inner(&self) -> SpinLockGuard<InnerIrqAction> {
|
||||
self.inner.lock_irqsave()
|
||||
}
|
||||
|
||||
fn inner(&self) -> SpinLockGuard<InnerIrqAction> {
|
||||
self.inner.lock_irqsave()
|
||||
pub fn thread_completion(&self) -> &Completion {
|
||||
&self.thread_completion
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct InnerIrqAction {
|
||||
pub struct InnerIrqAction {
|
||||
/// cookie to identify the device
|
||||
dev_id: Option<DeviceId>,
|
||||
dev_id: Option<Arc<DeviceId>>,
|
||||
/// 中断处理程序
|
||||
handler: Option<&'static dyn IrqFlowHandler>,
|
||||
handler: Option<&'static dyn IrqHandler>,
|
||||
/// interrupt handler function for threaded interrupts
|
||||
thread_fn: Option<&'static dyn IrqFlowHandler>,
|
||||
thread_fn: Option<&'static dyn IrqHandler>,
|
||||
/// thread pointer for threaded interrupts
|
||||
thread: Option<Arc<ProcessControlBlock>>,
|
||||
/// pointer to secondary irqaction (force threading)
|
||||
@ -291,14 +588,122 @@ struct InnerIrqAction {
|
||||
/// 中断号
|
||||
irq: IrqNumber,
|
||||
flags: IrqHandleFlags,
|
||||
/// 中断线程的标志
|
||||
thread_flags: ThreadedHandlerFlags,
|
||||
/// name of the device
|
||||
name: String,
|
||||
}
|
||||
|
||||
impl InnerIrqAction {
|
||||
pub fn dev_id(&self) -> &Option<Arc<DeviceId>> {
|
||||
&self.dev_id
|
||||
}
|
||||
|
||||
pub fn dev_id_mut(&mut self) -> &mut Option<Arc<DeviceId>> {
|
||||
&mut self.dev_id
|
||||
}
|
||||
|
||||
pub fn handler(&self) -> Option<&'static dyn IrqHandler> {
|
||||
self.handler
|
||||
}
|
||||
|
||||
pub fn set_handler(&mut self, handler: Option<&'static dyn IrqHandler>) {
|
||||
self.handler = handler;
|
||||
}
|
||||
|
||||
pub fn thread_fn(&self) -> Option<&'static dyn IrqHandler> {
|
||||
self.thread_fn
|
||||
}
|
||||
|
||||
pub fn thread(&self) -> Option<Arc<ProcessControlBlock>> {
|
||||
self.thread.clone()
|
||||
}
|
||||
|
||||
pub fn set_thread(&mut self, thread: Option<Arc<ProcessControlBlock>>) {
|
||||
self.thread = thread;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn thread_flags(&self) -> &ThreadedHandlerFlags {
|
||||
&self.thread_flags
|
||||
}
|
||||
|
||||
pub fn thread_flags_mut(&mut self) -> &mut ThreadedHandlerFlags {
|
||||
&mut self.thread_flags
|
||||
}
|
||||
|
||||
pub fn secondary(&self) -> Option<Arc<IrqAction>> {
|
||||
self.secondary.clone()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn irq(&self) -> IrqNumber {
|
||||
self.irq
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn set_irq(&mut self, irq: IrqNumber) {
|
||||
self.irq = irq;
|
||||
}
|
||||
|
||||
pub fn flags(&self) -> &IrqHandleFlags {
|
||||
&self.flags
|
||||
}
|
||||
|
||||
pub fn flags_mut(&mut self) -> &mut IrqHandleFlags {
|
||||
&mut self.flags
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &String {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// 这些标志由线程处理程序使用
|
||||
pub struct ThreadedHandlerFlags: u32 {
|
||||
/// IRQTF_RUNTHREAD - 表示应运行中断处理程序线程
|
||||
const IRQTF_RUNTHREAD = 1 << 0;
|
||||
/// IRQTF_WARNED - 已打印警告 "IRQ_WAKE_THREAD w/o thread_fn"
|
||||
const IRQTF_WARNED = 1 << 1;
|
||||
/// IRQTF_AFFINITY - 请求irq线程调整亲和性
|
||||
const IRQTF_AFFINITY = 1 << 2;
|
||||
/// IRQTF_FORCED_THREAD - irq操作被强制线程化
|
||||
const IRQTF_FORCED_THREAD = 1 << 3;
|
||||
/// IRQTF_READY - 表示irq线程已准备就绪
|
||||
const IRQTF_READY = 1 << 4;
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements the `ThreadedHandlerFlags` structure.
|
||||
impl ThreadedHandlerFlags {
|
||||
/// 在 `ThreadedHandlerFlags` 结构中测试并设置特定的位。
|
||||
///
|
||||
/// # 参数
|
||||
///
|
||||
/// * `bit` - 要测试并设置的位。
|
||||
///
|
||||
/// # 返回
|
||||
///
|
||||
/// 如果操作前该位已被设置,则返回 `true`,否则返回 `false`。
|
||||
pub fn test_and_set_bit(&mut self, bit: ThreadedHandlerFlags) -> bool {
|
||||
let res = (self.bits & bit.bits) != 0;
|
||||
self.bits |= bit.bits;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// 定义IrqFlags位标志
|
||||
bitflags! {
|
||||
/// 这些标志仅由内核在中断处理例程中使用。
|
||||
pub struct IrqHandleFlags: u32 {
|
||||
|
||||
const IRQF_TRIGGER_NONE = IrqLineStatus::IRQ_TYPE_NONE.bits();
|
||||
const IRQF_TRIGGER_RISING = IrqLineStatus::IRQ_TYPE_EDGE_RISING.bits();
|
||||
const IRQF_TRIGGER_FALLING = IrqLineStatus::IRQ_TYPE_EDGE_FALLING.bits();
|
||||
const IRQF_TRIGGER_HIGH = IrqLineStatus::IRQ_TYPE_LEVEL_HIGH.bits();
|
||||
const IRQF_TRIGGER_LOW = IrqLineStatus::IRQ_TYPE_LEVEL_LOW.bits();
|
||||
const IRQF_TRIGGER_MASK = Self::IRQF_TRIGGER_HIGH.bits | Self::IRQF_TRIGGER_LOW.bits | Self::IRQF_TRIGGER_RISING.bits | Self::IRQF_TRIGGER_FALLING.bits;
|
||||
/// IRQF_SHARED - 允许多个设备共享中断
|
||||
const IRQF_SHARED = 0x00000080;
|
||||
/// IRQF_PROBE_SHARED - 当预期出现共享不匹配时,由调用者设置
|
||||
@ -331,6 +736,28 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
impl IrqHandleFlags {
|
||||
/// 检查是否指定了触发类型
|
||||
#[inline(always)]
|
||||
pub fn trigger_type_specified(&self) -> bool {
|
||||
(self.bits & Self::IRQF_TRIGGER_MASK.bits) != 0
|
||||
}
|
||||
|
||||
/// 插入触发类型
|
||||
pub fn insert_trigger_type(&mut self, trigger: IrqLineStatus) {
|
||||
self.bits |= trigger.trigger_bits() & IrqHandleFlags::IRQF_TRIGGER_MASK.bits;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn remove_trigger_type(&mut self, trigger: IrqLineStatus) {
|
||||
self.bits &= !(trigger.trigger_bits() & IrqHandleFlags::IRQF_TRIGGER_MASK.bits);
|
||||
}
|
||||
|
||||
pub fn trigger_type(&self) -> IrqLineStatus {
|
||||
IrqLineStatus::from_bits_truncate(self.bits & IrqHandleFlags::IRQF_TRIGGER_MASK.bits)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub(super) fn early_irq_init() -> Result<(), SystemError> {
|
||||
let irqcnt = CurrentIrqArch::probe_total_irq_num();
|
||||
@ -351,11 +778,11 @@ static mut IRQ_DESC_MANAGER: Option<IrqDescManager> = None;
|
||||
|
||||
/// 获取中断描述符管理器的引用
|
||||
#[inline(always)]
|
||||
pub(super) fn irq_desc_manager() -> &'static IrqDescManager {
|
||||
pub fn irq_desc_manager() -> &'static IrqDescManager {
|
||||
return unsafe { IRQ_DESC_MANAGER.as_ref().unwrap() };
|
||||
}
|
||||
|
||||
pub(super) struct IrqDescManager {
|
||||
pub struct IrqDescManager {
|
||||
irq_descs: BTreeMap<IrqNumber, Arc<IrqDesc>>,
|
||||
}
|
||||
|
||||
@ -367,7 +794,6 @@ impl IrqDescManager {
|
||||
}
|
||||
|
||||
/// 查找中断描述符
|
||||
#[allow(dead_code)]
|
||||
pub fn lookup(&self, irq: IrqNumber) -> Option<Arc<IrqDesc>> {
|
||||
self.irq_descs.get(&irq).map(|desc| desc.clone())
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use core::fmt::Debug;
|
||||
|
||||
use alloc::{
|
||||
string::String,
|
||||
string::{String, ToString},
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
@ -10,14 +10,274 @@ use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::{base::device::Device, open_firmware::device_node::DeviceNode},
|
||||
exception::{irqdata::IrqLineStatus, irqdesc::irq_desc_manager, manage::irq_manager},
|
||||
libs::{rwlock::RwLock, spinlock::SpinLock},
|
||||
};
|
||||
|
||||
use super::{
|
||||
irqchip::{IrqChipGeneric, IrqGcFlags},
|
||||
irqdata::IrqData,
|
||||
HardwareIrqNumber, IrqNumber,
|
||||
};
|
||||
|
||||
static mut IRQ_DOMAIN_MANAGER: Option<Arc<IrqDomainManager>> = None;
|
||||
|
||||
/// 获取中断域管理器的引用
|
||||
#[inline(always)]
|
||||
pub fn irq_domain_manager() -> &'static Arc<IrqDomainManager> {
|
||||
unsafe { IRQ_DOMAIN_MANAGER.as_ref().unwrap() }
|
||||
}
|
||||
|
||||
pub(super) fn irq_domain_manager_init() {
|
||||
unsafe {
|
||||
IRQ_DOMAIN_MANAGER = Some(Arc::new(IrqDomainManager::new()));
|
||||
}
|
||||
}
|
||||
/// 中断域管理器
|
||||
pub struct IrqDomainManager {
|
||||
domains: SpinLock<Vec<Arc<IrqDomain>>>,
|
||||
inner: RwLock<InnerIrqDomainManager>,
|
||||
}
|
||||
|
||||
impl IrqDomainManager {
|
||||
pub fn new() -> IrqDomainManager {
|
||||
IrqDomainManager {
|
||||
domains: SpinLock::new(Vec::new()),
|
||||
inner: RwLock::new(InnerIrqDomainManager {
|
||||
default_domain: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// 创建一个新的irqdomain, 并将其添加到irqdomain管理器中
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `name` - 中断域的名字
|
||||
/// - `ops` - 中断域的操作
|
||||
/// - `first_irq` - 起始软件中断号
|
||||
/// - `first_hwirq` - 起始硬件中断号
|
||||
/// - `irq_size` - 中断号的数量
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdomain.c?fi=__irq_domain_add#139
|
||||
pub fn create_and_add(
|
||||
&self,
|
||||
name: String,
|
||||
ops: &'static dyn IrqDomainOps,
|
||||
first_irq: IrqNumber,
|
||||
first_hwirq: HardwareIrqNumber,
|
||||
irq_size: u32,
|
||||
) -> Option<Arc<IrqDomain>> {
|
||||
let domain = IrqDomain::new(
|
||||
None,
|
||||
Some(name),
|
||||
ops,
|
||||
IrqDomainFlags::NAME_ALLOCATED,
|
||||
IrqDomainBusToken::Any,
|
||||
first_irq + irq_size,
|
||||
first_hwirq + irq_size,
|
||||
)?;
|
||||
|
||||
self.add_domain(domain.clone());
|
||||
|
||||
self.domain_associate_many(&domain, first_irq, first_hwirq, irq_size);
|
||||
|
||||
return Some(domain);
|
||||
}
|
||||
|
||||
fn add_domain(&self, domain: Arc<IrqDomain>) {
|
||||
self.domains.lock_irqsave().push(domain);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn remove_domain(&self, domain: &Arc<IrqDomain>) {
|
||||
let mut domains = self.domains.lock_irqsave();
|
||||
let index = domains
|
||||
.iter()
|
||||
.position(|x| Arc::ptr_eq(x, domain))
|
||||
.expect("domain not found");
|
||||
domains.remove(index);
|
||||
}
|
||||
|
||||
/// 获取默认的中断域
|
||||
#[allow(dead_code)]
|
||||
pub fn default_domain(&self) -> Option<Arc<IrqDomain>> {
|
||||
self.inner.read().default_domain.clone()
|
||||
}
|
||||
|
||||
/// 设置默认的中断域
|
||||
///
|
||||
/// 在创建IRQ映射的时候,如果没有指定中断域,就会使用默认的中断域
|
||||
pub fn set_default_domain(&self, domain: Arc<IrqDomain>) {
|
||||
self.inner.write_irqsave().default_domain = Some(domain);
|
||||
}
|
||||
|
||||
/// 将指定范围的硬件中断号与软件中断号一一对应的关联起来
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `domain` - 中断域
|
||||
/// - `first_irq` - 起始软件中断号
|
||||
/// - `first_hwirq` - 起始硬件中断号
|
||||
/// - `count` - 数量
|
||||
pub fn domain_associate_many(
|
||||
&self,
|
||||
domain: &Arc<IrqDomain>,
|
||||
first_irq: IrqNumber,
|
||||
first_hwirq: HardwareIrqNumber,
|
||||
count: u32,
|
||||
) {
|
||||
for i in 0..count {
|
||||
if let Err(e) = self.domain_associate(domain, first_irq + i, first_hwirq + i) {
|
||||
kwarn!("domain associate failed: {:?}, domain '{:?}' didn't like hwirq {} to virq {} mapping.", e, domain.name(), (first_hwirq + i).data(), (first_irq + i).data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 将一个硬件中断号与一个软件中断号关联起来
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/irqdomain.c#562
|
||||
pub fn domain_associate(
|
||||
&self,
|
||||
domain: &Arc<IrqDomain>,
|
||||
irq: IrqNumber,
|
||||
hwirq: HardwareIrqNumber,
|
||||
) -> Result<(), SystemError> {
|
||||
if hwirq >= domain.revmap.read_irqsave().hwirq_max {
|
||||
kwarn!(
|
||||
"hwirq {} is out of range for domain {:?}",
|
||||
hwirq.data(),
|
||||
domain.name()
|
||||
);
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
let irq_data = irq_desc_manager()
|
||||
.lookup(irq)
|
||||
.ok_or_else(|| {
|
||||
kwarn!("irq_desc not found for irq {}", irq.data());
|
||||
SystemError::EINVAL
|
||||
})?
|
||||
.irq_data();
|
||||
if irq_data.domain().is_some() {
|
||||
kwarn!(
|
||||
"irq {} is already associated with domain {:?}",
|
||||
irq.data(),
|
||||
irq_data.domain().unwrap().name()
|
||||
);
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let mut irq_data_guard = irq_data.inner();
|
||||
irq_data_guard.set_hwirq(hwirq);
|
||||
irq_data_guard.set_domain(Some(domain.clone()));
|
||||
drop(irq_data_guard);
|
||||
let r = domain.ops.map(&domain, hwirq, irq);
|
||||
if let Err(e) = r {
|
||||
if e != SystemError::ENOSYS {
|
||||
if e != SystemError::EPERM {
|
||||
kinfo!("domain associate failed: {:?}, domain '{:?}' didn't like hwirq {} to virq {} mapping.", e, domain.name(), hwirq.data(), irq.data());
|
||||
}
|
||||
let mut irq_data_guard = irq_data.inner();
|
||||
irq_data_guard.set_domain(None);
|
||||
irq_data_guard.set_hwirq(HardwareIrqNumber::new(0));
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
|
||||
if domain.name().is_none() {
|
||||
let chip = irq_data.chip_info_read_irqsave().chip();
|
||||
domain.set_name(chip.name().to_string());
|
||||
}
|
||||
|
||||
self.irq_domain_set_mapping(&domain, hwirq, irq_data);
|
||||
|
||||
irq_manager().irq_clear_status_flags(irq, IrqLineStatus::IRQ_NOREQUEST)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn irq_domain_set_mapping(
|
||||
&self,
|
||||
domain: &Arc<IrqDomain>,
|
||||
hwirq: HardwareIrqNumber,
|
||||
irq_data: Arc<IrqData>,
|
||||
) {
|
||||
if domain.no_map() {
|
||||
return;
|
||||
}
|
||||
|
||||
domain.revmap.write_irqsave().insert(hwirq, irq_data);
|
||||
}
|
||||
/// 递归调用 domain_ops->activate 以激活中断
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - irq_data: 与中断关联的最外层 irq_data
|
||||
/// - reserve: 如果为true,则仅预留一个中断向量,而不是分配一个
|
||||
///
|
||||
/// 这是调用 domain_ops->activate 以编程中断控制器的第二步,以便中断实际上可以被传递。
|
||||
pub fn activate_irq(&self, irq_data: &Arc<IrqData>, reserve: bool) -> Result<(), SystemError> {
|
||||
let mut r = Ok(());
|
||||
if !irq_data.common_data().status().is_activated() {
|
||||
r = self.do_activate_irq(Some(irq_data.clone()), reserve);
|
||||
}
|
||||
|
||||
if !r.is_ok() {
|
||||
irq_data.common_data().status().set_activated();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn do_activate_irq(
|
||||
&self,
|
||||
irq_data: Option<Arc<IrqData>>,
|
||||
reserve: bool,
|
||||
) -> Result<(), SystemError> {
|
||||
let mut r = Ok(());
|
||||
|
||||
if irq_data.is_some() && irq_data.as_ref().unwrap().domain().is_some() {
|
||||
let domain = irq_data.as_ref().unwrap().domain().unwrap();
|
||||
|
||||
let irq_data = irq_data.unwrap();
|
||||
|
||||
let parent_data = irq_data.parent_data().map(|x| x.upgrade()).flatten();
|
||||
if let Some(parent_data) = parent_data.clone() {
|
||||
r = self.do_activate_irq(Some(parent_data), reserve);
|
||||
}
|
||||
|
||||
if r.is_err() {
|
||||
let tmpr = domain.ops.activate(&domain, &irq_data, reserve);
|
||||
if let Err(e) = tmpr {
|
||||
if e != SystemError::ENOSYS && parent_data.is_some() {
|
||||
self.do_deactivate_irq(parent_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
fn do_deactivate_irq(&self, irq_data: Option<Arc<IrqData>>) {
|
||||
if let Some(irq_data) = irq_data {
|
||||
if let Some(domain) = irq_data.domain() {
|
||||
domain.ops.deactivate(&domain, &irq_data);
|
||||
let pp = irq_data.parent_data().map(|x| x.upgrade()).flatten();
|
||||
|
||||
if pp.is_some() {
|
||||
self.do_deactivate_irq(pp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct InnerIrqDomainManager {
|
||||
default_domain: Option<Arc<IrqDomain>>,
|
||||
}
|
||||
|
||||
/// 中断域
|
||||
///
|
||||
/// 用于把硬件中断号翻译为软件中断号的映射的对象
|
||||
@ -28,7 +288,7 @@ use super::{
|
||||
pub struct IrqDomain {
|
||||
/// 中断域的名字 (二选一)
|
||||
name: Option<&'static str>,
|
||||
allocated_name: Option<String>,
|
||||
allocated_name: SpinLock<Option<String>>,
|
||||
/// 中断域的操作
|
||||
ops: &'static dyn IrqDomainOps,
|
||||
inner: SpinLock<InnerIrqDomain>,
|
||||
@ -63,6 +323,8 @@ impl IrqDomain {
|
||||
ops: &'static dyn IrqDomainOps,
|
||||
flags: IrqDomainFlags,
|
||||
bus_token: IrqDomainBusToken,
|
||||
irq_max: IrqNumber,
|
||||
hwirq_max: HardwareIrqNumber,
|
||||
) -> Option<Arc<Self>> {
|
||||
if name.is_none() && allocated_name.is_none() {
|
||||
return None;
|
||||
@ -70,7 +332,7 @@ impl IrqDomain {
|
||||
|
||||
let x = IrqDomain {
|
||||
name,
|
||||
allocated_name,
|
||||
allocated_name: SpinLock::new(allocated_name),
|
||||
ops,
|
||||
inner: SpinLock::new(InnerIrqDomain {
|
||||
flags,
|
||||
@ -82,20 +344,67 @@ impl IrqDomain {
|
||||
}),
|
||||
revmap: RwLock::new(IrqDomainRevMap {
|
||||
map: HashMap::new(),
|
||||
hwirq_max: HardwareIrqNumber::new(0),
|
||||
hwirq_max,
|
||||
irq_max,
|
||||
}),
|
||||
};
|
||||
|
||||
return Some(Arc::new(x));
|
||||
}
|
||||
|
||||
/// 中断域是否不对中断号进行转换
|
||||
pub fn no_map(&self) -> bool {
|
||||
self.inner
|
||||
.lock_irqsave()
|
||||
.flags
|
||||
.contains(IrqDomainFlags::NO_MAP)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn set_hwirq_max(&self, hwirq_max: HardwareIrqNumber) {
|
||||
self.revmap.write_irqsave().hwirq_max = hwirq_max;
|
||||
}
|
||||
|
||||
pub fn name(&self) -> Option<String> {
|
||||
if let Some(name) = self.name {
|
||||
return Some(name.to_string());
|
||||
}
|
||||
return self.allocated_name.lock_irqsave().clone();
|
||||
}
|
||||
|
||||
pub fn set_name(&self, name: String) {
|
||||
*self.allocated_name.lock_irqsave() = Some(name);
|
||||
}
|
||||
|
||||
/// The number of mapped interrupts
|
||||
pub fn map_count(&self) -> u32 {
|
||||
self.revmap.read().map.len() as u32
|
||||
}
|
||||
}
|
||||
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/irqdomain.h#190
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
struct IrqDomainRevMap {
|
||||
map: HashMap<HardwareIrqNumber, IrqNumber>,
|
||||
map: HashMap<HardwareIrqNumber, Arc<IrqData>>,
|
||||
hwirq_max: HardwareIrqNumber,
|
||||
irq_max: IrqNumber,
|
||||
}
|
||||
|
||||
impl IrqDomainRevMap {
|
||||
fn insert(&mut self, hwirq: HardwareIrqNumber, irq_data: Arc<IrqData>) {
|
||||
self.map.insert(hwirq, irq_data);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn remove(&mut self, hwirq: HardwareIrqNumber) {
|
||||
self.map.remove(&hwirq);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn lookup(&self, hwirq: HardwareIrqNumber) -> Option<Arc<IrqData>> {
|
||||
self.map.get(&hwirq).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
@ -156,15 +465,30 @@ pub trait IrqDomainOps: Debug + Send + Sync {
|
||||
|
||||
/// 创建或更新一个虚拟中断号与一个硬件中断号之间的映射。
|
||||
/// 对于给定的映射,这只会被调用一次。
|
||||
///
|
||||
/// 如果没有实现这个方法,那么就会返回`ENOSYS`
|
||||
fn map(
|
||||
&self,
|
||||
irq_domain: &Arc<IrqDomain>,
|
||||
hwirq: HardwareIrqNumber,
|
||||
virq: IrqNumber,
|
||||
) -> Result<(), SystemError>;
|
||||
_irq_domain: &Arc<IrqDomain>,
|
||||
_hwirq: HardwareIrqNumber,
|
||||
_virq: IrqNumber,
|
||||
) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
/// 删除一个虚拟中断号与一个硬件中断号之间的映射。
|
||||
fn unmap(&self, irq_domain: &Arc<IrqDomain>, virq: IrqNumber);
|
||||
|
||||
fn activate(
|
||||
&self,
|
||||
_domain: &Arc<IrqDomain>,
|
||||
_irq_data: &Arc<IrqData>,
|
||||
_reserve: bool,
|
||||
) -> Result<(), SystemError> {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
fn deactivate(&self, _domain: &Arc<IrqDomain>, _irq_data: &Arc<IrqData>) {}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
1093
kernel/src/exception/manage.rs
Normal file
1093
kernel/src/exception/manage.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,5 @@
|
||||
use core::ops::Add;
|
||||
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::arch::CurrentIrqArch;
|
||||
@ -10,7 +12,9 @@ pub mod irqchip;
|
||||
pub mod irqdata;
|
||||
pub mod irqdesc;
|
||||
pub mod irqdomain;
|
||||
pub mod manage;
|
||||
pub mod msi;
|
||||
mod resend;
|
||||
pub mod softirq;
|
||||
pub mod sysfs;
|
||||
|
||||
@ -100,6 +104,28 @@ impl Drop for IrqFlagsGuard {
|
||||
// 用于表示软件逻辑视角的中断号,全局唯一
|
||||
int_like!(IrqNumber, u32);
|
||||
|
||||
impl IrqNumber {
|
||||
/// 如果一个(PCI)设备中断没有被连接,我们将设置irqnumber为IRQ_NOTCONNECTED。
|
||||
/// 这导致request_irq()失败,返回-ENOTCONN,这样我们就可以区分这种情况和其他错误返回。
|
||||
pub const IRQ_NOTCONNECTED: IrqNumber = IrqNumber::new(u32::MAX);
|
||||
}
|
||||
|
||||
// 硬件中断号
|
||||
// 用于表示在某个IrqDomain中的中断号
|
||||
int_like!(HardwareIrqNumber, u32);
|
||||
|
||||
impl Add<u32> for HardwareIrqNumber {
|
||||
type Output = HardwareIrqNumber;
|
||||
|
||||
fn add(self, rhs: u32) -> HardwareIrqNumber {
|
||||
HardwareIrqNumber::new(self.0 + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<u32> for IrqNumber {
|
||||
type Output = IrqNumber;
|
||||
|
||||
fn add(self, rhs: u32) -> IrqNumber {
|
||||
IrqNumber::new(self.0 + rhs)
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,14 @@ impl MsiMsg {
|
||||
pub const fn address(&self) -> u64 {
|
||||
(self.address_hi as u64) << 32 | self.address_lo as u64
|
||||
}
|
||||
|
||||
pub const fn new_zeroed() -> Self {
|
||||
MsiMsg {
|
||||
address_lo: 0,
|
||||
address_hi: 0,
|
||||
data: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
91
kernel/src/exception/resend.rs
Normal file
91
kernel/src/exception/resend.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{exception::irqdesc::IrqDescState, libs::spinlock::SpinLockGuard};
|
||||
|
||||
use super::{irqdesc::InnerIrqDesc, manage::IrqManager};
|
||||
|
||||
impl IrqManager {
|
||||
/// 检查状态并重发中断
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `desc_inner_guard`:中断描述符的锁
|
||||
/// - `inject`:是否注入中断
|
||||
pub(super) fn irq_check_and_resend(
|
||||
&self,
|
||||
desc_inner_guard: &mut SpinLockGuard<'_, InnerIrqDesc>,
|
||||
inject: bool,
|
||||
) -> Result<(), SystemError> {
|
||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/resend.c?fi=check_irq_resend#106
|
||||
|
||||
/*
|
||||
* 我们不重新发送电平触发类型的中断。电平触发类型的中断在它们仍然活动时由硬件重新发送。
|
||||
* 清除PENDING bit,以避免suspend/resume过程中的混淆。
|
||||
*/
|
||||
if desc_inner_guard
|
||||
.common_data()
|
||||
.trigger_type()
|
||||
.is_level_type()
|
||||
{
|
||||
desc_inner_guard
|
||||
.internal_state_mut()
|
||||
.remove(IrqDescState::IRQS_PENDING);
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
if desc_inner_guard
|
||||
.internal_state()
|
||||
.contains(IrqDescState::IRQS_REPLAY)
|
||||
{
|
||||
return Err(SystemError::EBUSY);
|
||||
}
|
||||
|
||||
if desc_inner_guard
|
||||
.internal_state()
|
||||
.contains(IrqDescState::IRQS_PENDING)
|
||||
== false
|
||||
&& inject == false
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
desc_inner_guard
|
||||
.internal_state_mut()
|
||||
.remove(IrqDescState::IRQS_PENDING);
|
||||
|
||||
let mut ret = Ok(());
|
||||
if self.try_retrigger(desc_inner_guard).is_err() {
|
||||
// todo: 支持发送到tasklet
|
||||
ret = Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
if ret.is_ok() {
|
||||
desc_inner_guard
|
||||
.internal_state_mut()
|
||||
.insert(IrqDescState::IRQS_REPLAY);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
fn try_retrigger(
|
||||
&self,
|
||||
desc_inner_guard: &SpinLockGuard<'_, InnerIrqDesc>,
|
||||
) -> Result<(), SystemError> {
|
||||
if let Err(e) = desc_inner_guard
|
||||
.irq_data()
|
||||
.chip_info_read_irqsave()
|
||||
.chip()
|
||||
.retrigger(desc_inner_guard.irq_data())
|
||||
{
|
||||
if e != SystemError::ENOSYS {
|
||||
return Err(e);
|
||||
}
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 当前中断控制器不支持重发中断,从父中断控制器重发
|
||||
return self.irq_chip_retrigger_hierarchy(desc_inner_guard.irq_data());
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/**
|
||||
* @file softirq.h
|
||||
* @author fslongjin (longjin@RinGoTek.cn)
|
||||
* @brief 软中断
|
||||
* @version 0.1
|
||||
* @date 2022-04-08
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <common/glib.h>
|
||||
|
||||
// ==================implementation with rust===================
|
||||
extern void rs_softirq_init();
|
||||
extern void rs_raise_softirq(uint32_t sirq_num);
|
||||
extern void rs_unregister_softirq(uint32_t sirq_num);
|
||||
extern void rs_do_softirq();
|
||||
extern void rs_clear_softirq_pending(uint32_t softirq_num);
|
||||
|
||||
// for temporary
|
||||
#define MAX_SOFTIRQ_NUM 64
|
||||
#define TIMER_SIRQ 0 // 时钟软中断号
|
||||
#define VIDEO_REFRESH_SIRQ 1 // 帧缓冲区刷新软中断
|
@ -17,14 +17,14 @@ use crate::{
|
||||
libs::rwlock::RwLock,
|
||||
mm::percpu::{PerCpu, PerCpuVar},
|
||||
process::ProcessManager,
|
||||
smp::core::smp_get_processor_id,
|
||||
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
||||
time::timer::clock,
|
||||
};
|
||||
|
||||
const MAX_SOFTIRQ_NUM: u64 = 64;
|
||||
const MAX_SOFTIRQ_RESTART: i32 = 20;
|
||||
|
||||
static mut __CPU_PENDING: Option<Box<[VecStatus; PerCpu::MAX_CPU_NUM]>> = None;
|
||||
static mut __CPU_PENDING: Option<Box<[VecStatus; PerCpu::MAX_CPU_NUM as usize]>> = None;
|
||||
static mut __SORTIRQ_VECTORS: *mut Softirq = null_mut();
|
||||
|
||||
#[no_mangle]
|
||||
@ -57,9 +57,9 @@ pub fn softirq_vectors() -> &'static mut Softirq {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn cpu_pending(cpu_id: usize) -> &'static mut VecStatus {
|
||||
fn cpu_pending(cpu_id: ProcessorId) -> &'static mut VecStatus {
|
||||
unsafe {
|
||||
return &mut __CPU_PENDING.as_mut().unwrap()[cpu_id];
|
||||
return &mut __CPU_PENDING.as_mut().unwrap()[cpu_id.data() as usize];
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,6 +166,7 @@ impl Softirq {
|
||||
/// @brief 解注册软中断向量
|
||||
///
|
||||
/// @param irq_num 中断向量号码
|
||||
#[allow(dead_code)]
|
||||
pub fn unregister_softirq(&self, softirq_num: SoftirqNumber) {
|
||||
// kdebug!("unregister_softirq softirq_num = {:?}", softirq_num as u64);
|
||||
let mut table_guard = self.table.write_irqsave();
|
||||
@ -176,10 +177,11 @@ impl Softirq {
|
||||
// self.running.lock().set(VecStatus::from(softirq_num), false);
|
||||
// 将对应CPU的pending置0
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
cpu_pending(smp_get_processor_id() as usize).set(VecStatus::from(softirq_num), false);
|
||||
cpu_pending(smp_get_processor_id()).set(VecStatus::from(softirq_num), false);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn do_softirq(&self) {
|
||||
if self.cpu_running_count().get().load(Ordering::SeqCst) >= Self::MAX_RUNNING_PER_CPU {
|
||||
// 当前CPU的软中断嵌套层数已经达到最大值,不再执行
|
||||
@ -194,8 +196,8 @@ impl Softirq {
|
||||
let mut max_restart = MAX_SOFTIRQ_RESTART;
|
||||
loop {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let pending = cpu_pending(cpu_id as usize).bits;
|
||||
cpu_pending(cpu_id as usize).bits = 0;
|
||||
let pending = cpu_pending(cpu_id).bits;
|
||||
cpu_pending(cpu_id).bits = 0;
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
unsafe { CurrentIrqArch::interrupt_enable() };
|
||||
@ -229,7 +231,7 @@ impl Softirq {
|
||||
unsafe { CurrentIrqArch::interrupt_disable() };
|
||||
max_restart -= 1;
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
if cpu_pending(cpu_id as usize).is_empty() {
|
||||
if cpu_pending(cpu_id).is_empty() {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
if clock() < end && max_restart > 0 {
|
||||
continue;
|
||||
@ -245,7 +247,7 @@ impl Softirq {
|
||||
|
||||
pub fn raise_softirq(&self, softirq_num: SoftirqNumber) {
|
||||
let guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
let processor_id = smp_get_processor_id() as usize;
|
||||
let processor_id = smp_get_processor_id();
|
||||
|
||||
cpu_pending(processor_id).insert(VecStatus::from(softirq_num));
|
||||
|
||||
@ -254,9 +256,11 @@ impl Softirq {
|
||||
drop(guard);
|
||||
// kdebug!("raise_softirq exited");
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn clear_softirq_pending(&self, softirq_num: SoftirqNumber) {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
cpu_pending(smp_get_processor_id() as usize).remove(VecStatus::from(softirq_num));
|
||||
cpu_pending(smp_get_processor_id()).remove(VecStatus::from(softirq_num));
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
@ -282,25 +286,6 @@ impl<'a> Drop for RunningCountGuard<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// ======= 以下为给C提供的接口 =======
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_raise_softirq(softirq_num: u32) {
|
||||
softirq_vectors().raise_softirq(SoftirqNumber::from(softirq_num as u64));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_unregister_softirq(softirq_num: u32) {
|
||||
softirq_vectors().unregister_softirq(SoftirqNumber::from(softirq_num as u64));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_do_softirq() {
|
||||
pub fn do_softirq() {
|
||||
softirq_vectors().do_softirq();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_clear_softirq_pending(softirq_num: u32) {
|
||||
unsafe {
|
||||
softirq_vectors().clear_softirq_pending(SoftirqNumber::from(softirq_num as u64));
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,8 @@ impl Attribute for AttrChipName {
|
||||
.arc_any()
|
||||
.downcast::<IrqDesc>()
|
||||
.map_err(|_| SystemError::EINVAL)?;
|
||||
let chip = irq_desc.irq_data().chip();
|
||||
|
||||
let chip = irq_desc.irq_data().chip_info_read_irqsave().chip();
|
||||
let name = chip.name();
|
||||
let len = core::cmp::min(name.len() + 1, buf.len());
|
||||
let name = format!("{}\n", name);
|
||||
@ -301,9 +302,11 @@ impl Attribute for AttrActions {
|
||||
|
||||
for action in actions {
|
||||
if len != 0 {
|
||||
len += sysfs_emit_str(&mut buf[len..], &format!(",{}", action.name())).unwrap();
|
||||
len += sysfs_emit_str(&mut buf[len..], &format!(",{}", action.inner().name()))
|
||||
.unwrap();
|
||||
} else {
|
||||
len += sysfs_emit_str(&mut buf[len..], &format!("{}", action.name())).unwrap();
|
||||
len +=
|
||||
sysfs_emit_str(&mut buf[len..], &format!("{}", action.inner().name())).unwrap();
|
||||
}
|
||||
|
||||
if len >= buf.len() {
|
||||
|
@ -157,7 +157,7 @@ impl ProcFSInode {
|
||||
let state = sched_info_guard.inner_lock_read_irqsave().state();
|
||||
let cpu_id = sched_info_guard
|
||||
.on_cpu()
|
||||
.map(|cpu| cpu as i32)
|
||||
.map(|cpu| cpu.data() as i32)
|
||||
.unwrap_or(-1);
|
||||
|
||||
let priority = sched_info_guard.priority();
|
||||
|
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* @file VFS.h
|
||||
* @author fslongjin (longjin@RinGoTek.cn)
|
||||
* @brief 虚拟文件系统
|
||||
* @version 0.1
|
||||
* @date 2022-04-20
|
||||
*
|
||||
* @copyright Copyright (c) 2022
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct vfs_file_operations_t
|
||||
{
|
||||
long (*open)(void *not_used, void *not_used1);
|
||||
long (*close)(void *not_used, void *not_used1);
|
||||
long (*read)(void *not_used1, char *buf, int64_t count, long *position);
|
||||
long (*write)(void *not_used1, char *buf, int64_t count, long *position);
|
||||
long (*lseek)(void *not_used1, long offset, long origin);
|
||||
long (*ioctl)(void *not_used, void *not_used1, uint64_t cmd, uint64_t arg);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 初始化vfs
|
||||
*
|
||||
* @return int 错误码
|
||||
*/
|
||||
extern int vfs_init();
|
@ -36,7 +36,5 @@
|
||||
#include <smp/smp.h>
|
||||
#include <time/clocksource.h>
|
||||
#include <time/sleep.h>
|
||||
#include <driver/pci/pci_irq.h>
|
||||
#include <common/errno.h>
|
||||
#include <common/cpu.h>
|
||||
#include <exception/irq.h>
|
||||
|
@ -1,7 +1,8 @@
|
||||
use bitmap::{traits::BitMapOps, AllocBitmap};
|
||||
|
||||
use crate::mm::percpu::PerCpu;
|
||||
use crate::{mm::percpu::PerCpu, smp::cpu::ProcessorId};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CpuMask {
|
||||
bmp: AllocBitmap,
|
||||
}
|
||||
@ -9,40 +10,62 @@ pub struct CpuMask {
|
||||
#[allow(dead_code)]
|
||||
impl CpuMask {
|
||||
pub fn new() -> Self {
|
||||
let bmp = AllocBitmap::new(PerCpu::MAX_CPU_NUM);
|
||||
let bmp = AllocBitmap::new(PerCpu::MAX_CPU_NUM as usize);
|
||||
Self { bmp }
|
||||
}
|
||||
|
||||
/// 获取CpuMask中的第一个cpu
|
||||
pub fn first(&self) -> Option<usize> {
|
||||
self.bmp.first_index()
|
||||
pub fn first(&self) -> Option<ProcessorId> {
|
||||
self.bmp
|
||||
.first_index()
|
||||
.map(|index| ProcessorId::new(index as u32))
|
||||
}
|
||||
|
||||
/// 获取CpuMask中第一个未被置位的cpu
|
||||
pub fn first_zero(&self) -> Option<usize> {
|
||||
self.bmp.first_false_index()
|
||||
pub fn first_zero(&self) -> Option<ProcessorId> {
|
||||
self.bmp
|
||||
.first_false_index()
|
||||
.map(|index| ProcessorId::new(index as u32))
|
||||
}
|
||||
|
||||
/// 获取CpuMask中的最后一个被置位的cpu
|
||||
pub fn last(&self) -> Option<usize> {
|
||||
self.bmp.last_index()
|
||||
pub fn last(&self) -> Option<ProcessorId> {
|
||||
self.bmp
|
||||
.last_index()
|
||||
.map(|index| ProcessorId::new(index as u32))
|
||||
}
|
||||
|
||||
/// 获取指定cpu之后第一个为1的位的cpu
|
||||
pub fn next_index(&self, cpu: usize) -> Option<usize> {
|
||||
self.bmp.next_index(cpu)
|
||||
pub fn next_index(&self, cpu: ProcessorId) -> Option<ProcessorId> {
|
||||
self.bmp
|
||||
.next_index(cpu.data() as usize)
|
||||
.map(|index| ProcessorId::new(index as u32))
|
||||
}
|
||||
|
||||
/// 获取指定cpu之后第一个为未被置位的cpu
|
||||
pub fn next_zero_index(&self, cpu: usize) -> Option<usize> {
|
||||
self.bmp.next_false_index(cpu)
|
||||
pub fn next_zero_index(&self, cpu: ProcessorId) -> Option<ProcessorId> {
|
||||
self.bmp
|
||||
.next_false_index(cpu.data() as usize)
|
||||
.map(|index| ProcessorId::new(index as u32))
|
||||
}
|
||||
|
||||
pub fn set(&mut self, cpu: ProcessorId, value: bool) -> Option<bool> {
|
||||
self.bmp.set(cpu.data() as usize, value)
|
||||
}
|
||||
|
||||
pub fn get(&self, cpu: ProcessorId) -> Option<bool> {
|
||||
self.bmp.get(cpu.data() as usize)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.bmp.is_empty()
|
||||
}
|
||||
|
||||
/// 迭代所有被置位的cpu
|
||||
pub fn iter_cpu(&self) -> CpuMaskIter {
|
||||
CpuMaskIter {
|
||||
mask: self,
|
||||
index: 0,
|
||||
index: ProcessorId::new(0),
|
||||
set: true,
|
||||
}
|
||||
}
|
||||
@ -51,7 +74,7 @@ impl CpuMask {
|
||||
pub fn iter_zero_cpu(&self) -> CpuMaskIter {
|
||||
CpuMaskIter {
|
||||
mask: self,
|
||||
index: 0,
|
||||
index: ProcessorId::new(0),
|
||||
set: false,
|
||||
}
|
||||
}
|
||||
@ -59,15 +82,15 @@ impl CpuMask {
|
||||
|
||||
pub struct CpuMaskIter<'a> {
|
||||
mask: &'a CpuMask,
|
||||
index: usize,
|
||||
index: ProcessorId,
|
||||
set: bool,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for CpuMaskIter<'a> {
|
||||
type Item = usize;
|
||||
type Item = ProcessorId;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.index == 0 {
|
||||
fn next(&mut self) -> Option<ProcessorId> {
|
||||
if self.index.data() == 0 {
|
||||
if self.set {
|
||||
self.index = self.mask.first()?;
|
||||
} else {
|
||||
@ -83,3 +106,11 @@ impl<'a> Iterator for CpuMaskIter<'a> {
|
||||
Some(self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for CpuMask {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("CpuMask")
|
||||
.field("bmp", &format!("size: {}", self.bmp.size()))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@
|
||||
#[macro_export]
|
||||
macro_rules! int_like {
|
||||
($new_type_name:ident, $backing_type: ident) => {
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy, Hash)]
|
||||
pub struct $new_type_name($backing_type);
|
||||
|
||||
impl $new_type_name {
|
||||
|
@ -1029,7 +1029,7 @@ pub fn textui_putchar(
|
||||
if unsafe { TEXTUI_IS_INIT } {
|
||||
return textui_framework()
|
||||
.current_window
|
||||
.lock()
|
||||
.lock_irqsave()
|
||||
.textui_putchar_window(
|
||||
character,
|
||||
fr_color,
|
||||
@ -1061,7 +1061,7 @@ pub fn textui_putstr(
|
||||
None
|
||||
};
|
||||
|
||||
let mut guard = window.as_ref().map(|w| w.lock());
|
||||
let mut guard = window.as_ref().map(|w| w.lock_irqsave());
|
||||
|
||||
for character in string.chars() {
|
||||
if unsafe { TEXTUI_IS_INIT } {
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![allow(dead_code)]
|
||||
// #![allow(dead_code)]
|
||||
use core::intrinsics::unlikely;
|
||||
|
||||
use alloc::{collections::LinkedList, sync::Arc, vec::Vec};
|
||||
@ -25,6 +25,7 @@ struct InnerWaitQueue {
|
||||
#[derive(Debug)]
|
||||
pub struct WaitQueue(SpinLock<InnerWaitQueue>);
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl WaitQueue {
|
||||
pub const INIT: WaitQueue = WaitQueue(SpinLock::new(InnerWaitQueue::INIT));
|
||||
|
||||
@ -275,6 +276,7 @@ pub struct EventWaitQueue {
|
||||
wait_list: SpinLock<Vec<(u64, Arc<ProcessControlBlock>)>>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl EventWaitQueue {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
|
@ -8,9 +8,11 @@ use crate::{
|
||||
},
|
||||
exception::InterruptArch,
|
||||
libs::align::page_align_up,
|
||||
mm::allocator::page_frame::PageFrameCount,
|
||||
mm::{MMArch, MemoryManagementArch},
|
||||
smp::core::smp_get_processor_id,
|
||||
mm::{allocator::page_frame::PageFrameCount, MMArch, MemoryManagementArch},
|
||||
smp::{
|
||||
core::smp_get_processor_id,
|
||||
cpu::{AtomicProcessorId, ProcessorId},
|
||||
},
|
||||
};
|
||||
use core::{
|
||||
ops::Deref,
|
||||
@ -18,10 +20,11 @@ use core::{
|
||||
};
|
||||
|
||||
/// 标志当前没有处理器持有内核映射器的锁
|
||||
/// 之所以需要这个标志,是因为AtomicUsize::new(0)会把0当作一个处理器的id
|
||||
const KERNEL_MAPPER_NO_PROCESSOR: usize = !0;
|
||||
/// 之所以需要这个标志,是因为 AtomicProcessorId::new(0) 会把0当作一个处理器的id
|
||||
const KERNEL_MAPPER_NO_PROCESSOR: ProcessorId = ProcessorId::INVALID;
|
||||
/// 当前持有内核映射器锁的处理器
|
||||
static KERNEL_MAPPER_LOCK_OWNER: AtomicUsize = AtomicUsize::new(KERNEL_MAPPER_NO_PROCESSOR);
|
||||
static KERNEL_MAPPER_LOCK_OWNER: AtomicProcessorId =
|
||||
AtomicProcessorId::new(KERNEL_MAPPER_NO_PROCESSOR);
|
||||
/// 内核映射器的锁计数器
|
||||
static KERNEL_MAPPER_LOCK_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
@ -33,7 +36,7 @@ pub struct KernelMapper {
|
||||
}
|
||||
|
||||
impl KernelMapper {
|
||||
fn lock_cpu(cpuid: usize, mapper: PageMapper) -> Self {
|
||||
fn lock_cpu(cpuid: ProcessorId, mapper: PageMapper) -> Self {
|
||||
loop {
|
||||
match KERNEL_MAPPER_LOCK_OWNER.compare_exchange_weak(
|
||||
KERNEL_MAPPER_NO_PROCESSOR,
|
||||
@ -61,7 +64,7 @@ impl KernelMapper {
|
||||
/// @brief 锁定内核映射器, 并返回一个内核映射器对象
|
||||
#[inline(always)]
|
||||
pub fn lock() -> Self {
|
||||
let cpuid = smp_get_processor_id() as usize;
|
||||
let cpuid = smp_get_processor_id();
|
||||
let mapper = unsafe { PageMapper::current(PageTableKind::Kernel, LockedFrameAllocator) };
|
||||
return Self::lock_cpu(cpuid, mapper);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use core::sync::atomic::AtomicUsize;
|
||||
use core::sync::atomic::AtomicU32;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
@ -11,13 +11,13 @@ use crate::{
|
||||
///
|
||||
/// todo: 待smp模块重构后,从smp模块获取CPU数量。
|
||||
/// 目前由于smp模块初始化时机较晚,导致大部分内核模块无法在早期初始化PerCpu变量。
|
||||
const CPU_NUM: AtomicUsize = AtomicUsize::new(PerCpu::MAX_CPU_NUM);
|
||||
const CPU_NUM: AtomicU32 = AtomicU32::new(PerCpu::MAX_CPU_NUM);
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PerCpu;
|
||||
|
||||
impl PerCpu {
|
||||
pub const MAX_CPU_NUM: usize = 128;
|
||||
pub const MAX_CPU_NUM: u32 = 128;
|
||||
/// # 初始化PerCpu
|
||||
///
|
||||
/// 该函数应该在内核初始化时调用一次。
|
||||
@ -28,7 +28,7 @@ impl PerCpu {
|
||||
if CPU_NUM.load(core::sync::atomic::Ordering::SeqCst) != 0 {
|
||||
panic!("PerCpu::init() called twice");
|
||||
}
|
||||
let cpus = unsafe { smp_get_total_cpu() } as usize;
|
||||
let cpus = unsafe { smp_get_total_cpu() };
|
||||
assert!(cpus > 0, "PerCpu::init(): smp_get_total_cpu() returned 0");
|
||||
CPU_NUM.store(cpus, core::sync::atomic::Ordering::SeqCst);
|
||||
}
|
||||
@ -62,7 +62,7 @@ impl<T> PerCpuVar<T> {
|
||||
panic!("PerCpu::init() not called");
|
||||
}
|
||||
|
||||
if data.len() != cpu_num {
|
||||
if data.len() != cpu_num.try_into().unwrap() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@ -76,12 +76,12 @@ impl<T> PerCpuVar<T> {
|
||||
|
||||
pub fn get(&self) -> &T {
|
||||
let cpu_id = smp_get_processor_id();
|
||||
&self.inner[cpu_id as usize]
|
||||
&self.inner[cpu_id.data() as usize]
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self) -> &mut T {
|
||||
let cpu_id = smp_get_processor_id();
|
||||
&mut self.inner[cpu_id as usize]
|
||||
&mut self.inner[cpu_id.data() as usize]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ unsafe extern "C" fn rs_get_idle_stack_top(cpu_id: u32) -> usize {
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn rs_current_pcb_cpuid() -> u32 {
|
||||
return smp_get_processor_id();
|
||||
return smp_get_processor_id().data();
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -8,7 +8,7 @@ use alloc::{sync::Arc, vec::Vec};
|
||||
use crate::{
|
||||
mm::{percpu::PerCpu, VirtAddr, INITIAL_PROCESS_ADDRESS_SPACE},
|
||||
process::KernelStack,
|
||||
smp::core::smp_get_processor_id,
|
||||
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
||||
};
|
||||
|
||||
use super::{ProcessControlBlock, ProcessManager};
|
||||
@ -27,10 +27,10 @@ impl ProcessManager {
|
||||
}
|
||||
|
||||
assert!(
|
||||
smp_get_processor_id() == 0,
|
||||
smp_get_processor_id() == ProcessorId::new(0),
|
||||
"Idle process must be initialized on the first processor"
|
||||
);
|
||||
let mut v: Vec<Arc<ProcessControlBlock>> = Vec::with_capacity(PerCpu::MAX_CPU_NUM);
|
||||
let mut v: Vec<Arc<ProcessControlBlock>> = Vec::with_capacity(PerCpu::MAX_CPU_NUM as usize);
|
||||
|
||||
for i in 0..PerCpu::MAX_CPU_NUM {
|
||||
let kstack = if unlikely(i == 0) {
|
||||
@ -57,7 +57,7 @@ impl ProcessManager {
|
||||
};
|
||||
|
||||
assert!(idle_pcb.sched_info().on_cpu().is_none());
|
||||
idle_pcb.sched_info().set_on_cpu(Some(i as u32));
|
||||
idle_pcb.sched_info().set_on_cpu(Some(ProcessorId::new(i)));
|
||||
v.push(idle_pcb);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{sched::sched, CurrentIrqArch},
|
||||
exception::InterruptArch,
|
||||
exception::{irqdesc::IrqAction, InterruptArch},
|
||||
init::initial_kthread::initial_kernel_thread,
|
||||
kdebug, kinfo,
|
||||
libs::{once::Once, spinlock::SpinLock},
|
||||
@ -87,15 +87,31 @@ impl KernelThreadPcbPrivate {
|
||||
#[allow(dead_code)]
|
||||
pub enum KernelThreadClosure {
|
||||
UsizeClosure((Box<dyn Fn(usize) -> i32 + Send + Sync>, usize)),
|
||||
StaticUsizeClosure((&'static dyn Fn(usize) -> i32, usize)),
|
||||
EmptyClosure((Box<dyn Fn() -> i32 + Send + Sync>, ())),
|
||||
StaticEmptyClosure((&'static dyn Fn() -> i32, ())),
|
||||
IrqThread(
|
||||
(
|
||||
&'static dyn Fn(Arc<IrqAction>) -> Result<(), SystemError>,
|
||||
Arc<IrqAction>,
|
||||
),
|
||||
),
|
||||
// 添加其他类型入参的闭包,返回值必须是i32
|
||||
}
|
||||
|
||||
unsafe impl Send for KernelThreadClosure {}
|
||||
unsafe impl Sync for KernelThreadClosure {}
|
||||
|
||||
impl KernelThreadClosure {
|
||||
pub fn run(self) -> i32 {
|
||||
match self {
|
||||
Self::UsizeClosure((func, arg)) => func(arg),
|
||||
Self::EmptyClosure((func, _arg)) => func(),
|
||||
Self::StaticUsizeClosure((func, arg)) => func(arg),
|
||||
Self::StaticEmptyClosure((func, _arg)) => func(),
|
||||
Self::IrqThread((func, arg)) => {
|
||||
func(arg).map(|_| 0).unwrap_or_else(|e| e.to_posix_errno())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
use core::{
|
||||
hash::{Hash, Hasher},
|
||||
hash::Hash,
|
||||
hint::spin_loop,
|
||||
intrinsics::{likely, unlikely},
|
||||
mem::ManuallyDrop,
|
||||
sync::atomic::{compiler_fence, AtomicBool, AtomicI32, AtomicIsize, AtomicUsize, Ordering},
|
||||
sync::atomic::{compiler_fence, AtomicBool, AtomicIsize, AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use alloc::{
|
||||
@ -48,7 +48,10 @@ use crate::{
|
||||
core::{sched_enqueue, CPU_EXECUTING},
|
||||
SchedPolicy, SchedPriority,
|
||||
},
|
||||
smp::kick_cpu,
|
||||
smp::{
|
||||
cpu::{AtomicProcessorId, ProcessorId},
|
||||
kick_cpu,
|
||||
},
|
||||
syscall::{user_access::clear_user, Syscall},
|
||||
};
|
||||
|
||||
@ -446,12 +449,6 @@ pub unsafe extern "C" fn switch_finish_hook() {
|
||||
|
||||
int_like!(Pid, AtomicPid, usize, AtomicUsize);
|
||||
|
||||
impl Hash for Pid {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Pid {
|
||||
pub fn to_string(&self) -> String {
|
||||
self.0.to_string()
|
||||
@ -1019,10 +1016,10 @@ impl ProcessBasicInfo {
|
||||
#[derive(Debug)]
|
||||
pub struct ProcessSchedulerInfo {
|
||||
/// 当前进程所在的cpu
|
||||
on_cpu: AtomicI32,
|
||||
on_cpu: AtomicProcessorId,
|
||||
/// 如果当前进程等待被迁移到另一个cpu核心上(也就是flags中的PF_NEED_MIGRATE被置位),
|
||||
/// 该字段存储要被迁移到的目标处理器核心号
|
||||
migrate_to: AtomicI32,
|
||||
migrate_to: AtomicProcessorId,
|
||||
inner_locked: RwLock<InnerSchedInfo>,
|
||||
/// 进程的调度优先级
|
||||
priority: SchedPriority,
|
||||
@ -1056,14 +1053,11 @@ impl InnerSchedInfo {
|
||||
|
||||
impl ProcessSchedulerInfo {
|
||||
#[inline(never)]
|
||||
pub fn new(on_cpu: Option<u32>) -> Self {
|
||||
let cpu_id = match on_cpu {
|
||||
Some(cpu_id) => cpu_id as i32,
|
||||
None => -1,
|
||||
};
|
||||
pub fn new(on_cpu: Option<ProcessorId>) -> Self {
|
||||
let cpu_id = on_cpu.unwrap_or(ProcessorId::INVALID);
|
||||
return Self {
|
||||
on_cpu: AtomicI32::new(cpu_id),
|
||||
migrate_to: AtomicI32::new(-1),
|
||||
on_cpu: AtomicProcessorId::new(cpu_id),
|
||||
migrate_to: AtomicProcessorId::new(ProcessorId::INVALID),
|
||||
inner_locked: RwLock::new(InnerSchedInfo {
|
||||
state: ProcessState::Blocked(false),
|
||||
sched_policy: SchedPolicy::CFS,
|
||||
@ -1074,37 +1068,38 @@ impl ProcessSchedulerInfo {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn on_cpu(&self) -> Option<u32> {
|
||||
pub fn on_cpu(&self) -> Option<ProcessorId> {
|
||||
let on_cpu = self.on_cpu.load(Ordering::SeqCst);
|
||||
if on_cpu == -1 {
|
||||
if on_cpu == ProcessorId::INVALID {
|
||||
return None;
|
||||
} else {
|
||||
return Some(on_cpu as u32);
|
||||
return Some(on_cpu);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_on_cpu(&self, on_cpu: Option<u32>) {
|
||||
pub fn set_on_cpu(&self, on_cpu: Option<ProcessorId>) {
|
||||
if let Some(cpu_id) = on_cpu {
|
||||
self.on_cpu.store(cpu_id as i32, Ordering::SeqCst);
|
||||
self.on_cpu.store(cpu_id, Ordering::SeqCst);
|
||||
} else {
|
||||
self.on_cpu.store(-1, Ordering::SeqCst);
|
||||
self.on_cpu.store(ProcessorId::INVALID, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn migrate_to(&self) -> Option<u32> {
|
||||
pub fn migrate_to(&self) -> Option<ProcessorId> {
|
||||
let migrate_to = self.migrate_to.load(Ordering::SeqCst);
|
||||
if migrate_to == -1 {
|
||||
if migrate_to == ProcessorId::INVALID {
|
||||
return None;
|
||||
} else {
|
||||
return Some(migrate_to as u32);
|
||||
return Some(migrate_to);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_migrate_to(&self, migrate_to: Option<u32>) {
|
||||
pub fn set_migrate_to(&self, migrate_to: Option<ProcessorId>) {
|
||||
if let Some(data) = migrate_to {
|
||||
self.migrate_to.store(data as i32, Ordering::SeqCst);
|
||||
self.migrate_to.store(data, Ordering::SeqCst);
|
||||
} else {
|
||||
self.migrate_to.store(-1, Ordering::SeqCst)
|
||||
self.migrate_to
|
||||
.store(ProcessorId::INVALID, Ordering::SeqCst)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <common/cpu.h>
|
||||
#include <common/errno.h>
|
||||
#include <common/glib.h>
|
||||
#include <filesystem/vfs/VFS.h>
|
||||
#include <syscall/syscall.h>
|
||||
|
||||
/**
|
||||
|
@ -8,6 +8,22 @@ use crate::{
|
||||
process::{Pid, ProcessManager},
|
||||
};
|
||||
|
||||
use super::{ProcessFlags, __PROCESS_MANAGEMENT_INIT_DONE};
|
||||
|
||||
pub fn current_pcb_flags() -> ProcessFlags {
|
||||
if unsafe { !__PROCESS_MANAGEMENT_INIT_DONE } {
|
||||
return ProcessFlags::empty();
|
||||
}
|
||||
return ProcessManager::current_pcb().flags().clone();
|
||||
}
|
||||
|
||||
pub fn current_pcb_preempt_count() -> usize {
|
||||
if unsafe { !__PROCESS_MANAGEMENT_INIT_DONE } {
|
||||
return 0;
|
||||
}
|
||||
return ProcessManager::current_pcb().preempt_count();
|
||||
}
|
||||
|
||||
/// @brief 初始化pid=1的进程的stdio
|
||||
pub fn stdio_init() -> Result<(), SystemError> {
|
||||
if ProcessManager::current_pcb().pid() != Pid(1) {
|
||||
|
@ -14,7 +14,7 @@ use crate::{
|
||||
process::{
|
||||
ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSchedulerInfo, ProcessState,
|
||||
},
|
||||
smp::core::smp_get_processor_id,
|
||||
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
||||
};
|
||||
|
||||
use super::{
|
||||
@ -150,7 +150,8 @@ impl SchedulerCFS {
|
||||
|
||||
/// @brief 时钟中断到来时,由sched的core模块中的函数,调用本函数,更新CFS进程的可执行时间
|
||||
pub fn timer_update_jiffies(&mut self, sched_info: &ProcessSchedulerInfo) {
|
||||
let current_cpu_queue: &mut CFSQueue = self.cpu_queue[smp_get_processor_id() as usize];
|
||||
let current_cpu_queue: &mut CFSQueue =
|
||||
self.cpu_queue[smp_get_processor_id().data() as usize];
|
||||
// todo: 引入调度周期以及所有进程的优先权进行计算,然后设置进程的可执行时间
|
||||
|
||||
let mut queue = None;
|
||||
@ -180,7 +181,7 @@ impl SchedulerCFS {
|
||||
|
||||
/// @brief 将进程加入cpu的cfs调度队列,并且重设其虚拟运行时间为当前队列的最小值
|
||||
pub fn enqueue_reset_vruntime(&mut self, pcb: Arc<ProcessControlBlock>) {
|
||||
let cpu_queue = &mut self.cpu_queue[pcb.sched_info().on_cpu().unwrap() as usize];
|
||||
let cpu_queue = &mut self.cpu_queue[pcb.sched_info().on_cpu().unwrap().data() as usize];
|
||||
let queue = cpu_queue.locked_queue.lock_irqsave();
|
||||
if queue.len() > 0 {
|
||||
pcb.sched_info()
|
||||
@ -197,8 +198,10 @@ impl SchedulerCFS {
|
||||
self.cpu_queue[cpu_id].idle_pcb = pcb;
|
||||
}
|
||||
/// 获取某个cpu的运行队列中的进程数
|
||||
pub fn get_cfs_queue_len(&mut self, cpu_id: u32) -> usize {
|
||||
let queue = self.cpu_queue[cpu_id as usize].locked_queue.lock_irqsave();
|
||||
pub fn get_cfs_queue_len(&mut self, cpu_id: ProcessorId) -> usize {
|
||||
let queue = self.cpu_queue[cpu_id.data() as usize]
|
||||
.locked_queue
|
||||
.lock_irqsave();
|
||||
return CFSQueue::get_cfs_queue_size(&queue);
|
||||
}
|
||||
}
|
||||
@ -213,7 +216,7 @@ impl Scheduler for SchedulerCFS {
|
||||
.flags()
|
||||
.remove(ProcessFlags::NEED_SCHEDULE);
|
||||
|
||||
let current_cpu_id = smp_get_processor_id() as usize;
|
||||
let current_cpu_id = smp_get_processor_id().data() as usize;
|
||||
|
||||
let current_cpu_queue: &mut CFSQueue = self.cpu_queue[current_cpu_id];
|
||||
|
||||
@ -272,7 +275,7 @@ impl Scheduler for SchedulerCFS {
|
||||
}
|
||||
|
||||
fn enqueue(&mut self, pcb: Arc<ProcessControlBlock>) {
|
||||
let cpu_queue = &mut self.cpu_queue[pcb.sched_info().on_cpu().unwrap() as usize];
|
||||
let cpu_queue = &mut self.cpu_queue[pcb.sched_info().on_cpu().unwrap().data() as usize];
|
||||
|
||||
cpu_queue.enqueue(pcb);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use crate::{
|
||||
kinfo,
|
||||
mm::percpu::PerCpu,
|
||||
process::{AtomicPid, Pid, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState},
|
||||
smp::core::smp_get_processor_id,
|
||||
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
||||
};
|
||||
|
||||
use super::rt::{sched_rt_init, SchedulerRT, __get_rt_scheduler};
|
||||
@ -39,23 +39,23 @@ impl CpuExecuting {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set(&self, cpu_id: u32, pid: Pid) {
|
||||
self.data[cpu_id as usize].store(pid, Ordering::SeqCst);
|
||||
pub fn set(&self, cpu_id: ProcessorId, pid: Pid) {
|
||||
self.data[cpu_id.data() as usize].store(pid, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get(&self, cpu_id: u32) -> Pid {
|
||||
self.data[cpu_id as usize].load(Ordering::SeqCst)
|
||||
pub fn get(&self, cpu_id: ProcessorId) -> Pid {
|
||||
self.data[cpu_id.data() as usize].load(Ordering::SeqCst)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取某个cpu的负载情况,返回当前负载,cpu_id 是获取负载的cpu的id
|
||||
// TODO:将获取负载情况调整为最近一段时间运行进程的数量
|
||||
pub fn get_cpu_loads(cpu_id: u32) -> u32 {
|
||||
pub fn get_cpu_loads(cpu_id: ProcessorId) -> u32 {
|
||||
let cfs_scheduler = __get_cfs_scheduler();
|
||||
let rt_scheduler = __get_rt_scheduler();
|
||||
let len_cfs = cfs_scheduler.get_cfs_queue_len(cpu_id as u32);
|
||||
let len_rt = rt_scheduler.rt_queue_len(cpu_id as u32);
|
||||
let len_cfs = cfs_scheduler.get_cfs_queue_len(cpu_id);
|
||||
let len_rt = rt_scheduler.rt_queue_len(cpu_id);
|
||||
// let load_rt = rt_scheduler.get_load_list_len(cpu_id);
|
||||
// kdebug!("this cpu_id {} is load rt {}", cpu_id, load_rt);
|
||||
|
||||
@ -70,6 +70,7 @@ pub fn loads_balance(pcb: Arc<ProcessControlBlock>) {
|
||||
let mut min_loads_cpu_id = smp_get_processor_id();
|
||||
let mut min_loads = get_cpu_loads(smp_get_processor_id());
|
||||
for cpu_id in 0..cpu_num {
|
||||
let cpu_id = ProcessorId::new(cpu_id);
|
||||
let tmp_cpu_loads = get_cpu_loads(cpu_id);
|
||||
if min_loads - tmp_cpu_loads > 0 {
|
||||
min_loads_cpu_id = cpu_id;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user