完成中断管理模块重构 (#554)

- 支持中断共享
- 把现有驱动程序移植到新的irq模块
- 使用`ProcessorId`标识处理器id
- 尚未实现threaded_irq

性能上,edge irq flow handler里面,对于锁的使用,可能有点问题。为了获取/修改common data还有其他几个结构体的状态,进行了多次加锁和放锁,导致性能降低。这是接下来需要优化的点。
This commit is contained in:
LoGin
2024-03-03 16:31:08 +08:00
committed by GitHub
parent 44d051e586
commit e28411791f
108 changed files with 4504 additions and 2203 deletions

View File

@ -1,10 +0,0 @@
SRC = $(wildcard *.c)
OBJ = $(SRC:.c=.o)
CFLAGS += -I .
.PHONY: all
all: $(OBJ)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@

View File

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

View File

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

View File

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

View File

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