mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-21 13:16:35 +00:00
完成中断管理模块重构 (#554)
- 支持中断共享 - 把现有驱动程序移植到新的irq模块 - 使用`ProcessorId`标识处理器id - 尚未实现threaded_irq 性能上,edge irq flow handler里面,对于锁的使用,可能有点问题。为了获取/修改common data还有其他几个结构体的状态,进行了多次加锁和放锁,导致性能降低。这是接下来需要优化的点。
This commit is contained in:
.vscode
build-scripts/kernel_build/src/cfiles/arch
docs/kernel/core_api
kernel
crates
bitmap
src
Makefile
arch
riscv64
x86_64
driver
exception
Makefiledummychip.rshandle.rsinit.rsipi.rsirq.cirq.hirqchip.rsirqdata.rsirqdesc.rsirqdomain.rsmanage.rsmod.rsmsi.rsresend.rssoftirq.hsoftirq.rssysfs.rs
filesystem
include
bindings
libs
mm
process
sched
smp
syscall
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user