添加中断 (#370)

* 添加中断

* dhcp更改为全局socketset

* 解决异常中断的问题,使得能够使用中断来处理网卡数据

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>
This commit is contained in:
YJwu2023
2023-09-21 23:23:57 +08:00
committed by GitHub
parent 6b4e7a2972
commit 0dd8ff4332
10 changed files with 120 additions and 54 deletions

View File

@ -14,7 +14,7 @@
#pragma GCC push_options
#pragma GCC optimize("O0")
// 导出定义在irq.c中的中段门表
extern void (*interrupt_table[24])(void);
extern void (*interrupt_table[25])(void);
extern uint32_t rs_current_pcb_preempt_count();
extern uint32_t rs_current_pcb_pid();
extern uint32_t rs_current_pcb_flags();
@ -363,7 +363,7 @@ int apic_init()
cli();
kinfo("Initializing APIC...");
// 初始化中断门, 中断使用rsp0防止在软中断时发生嵌套然后处理器重新加载导致数据被抹掉
for (int i = 32; i <= 55; ++i)
for (int i = 32; i <= 56; ++i)
set_intr_gate(i, 0, interrupt_table[i - 32]);
// 设置local apic中断门
@ -413,7 +413,6 @@ int apic_init()
*/
void do_IRQ(struct pt_regs *rsp, ul number)
{
if (number < 0x80 && number >= 32) // 以0x80为界限低于0x80的是外部中断控制器高于0x80的是Local APIC
{
// ==========外部中断控制器========

View File

@ -8,19 +8,15 @@
// 现在pci设备的中断由自己进行控制这些不执行内容的函数是为了适配旧的中断处理机制
void pci_irq_enable(ul irq_num)
{
}
void pci_irq_disable(ul irq_num)
{
}
ul pci_irq_install(ul, void*)
{
}
void pci_irq_uninstall(ul irq_num)
{
}
/// @brief 与本操作系统的中断机制进行交互把中断处理函数等注册到中断结构体中被rust调用
/// @param irq_num 要进行注册的中断号
@ -28,27 +24,27 @@ void pci_irq_uninstall(ul irq_num)
/// @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))
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);
// kerror("irq install for pci irq: invalid irq num: %ld.", irq_num);
return EINVAL;
}
if(p->irq_name!=NULL)
if (p->irq_name != NULL)
{
return EAGAIN;
}
hardware_intr_controller* pci_interrupt_controller =
(hardware_intr_controller*)kmalloc(sizeof(hardware_intr_controller), 0);
if (pci_interrupt_controller) {
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;
@ -56,8 +52,12 @@ uint16_t c_irq_install(ul irq_num,void (*pci_irq_handler)(ul irq_num, ul paramet
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 *)kmalloc(namelen, 0);
p->irq_name = (char *)kzalloc(namelen, 0);
memset(p->irq_name, 0, namelen);
strncpy(p->irq_name, irq_name, namelen);
p->parameter = parameter;
@ -80,12 +80,12 @@ void c_irq_uninstall(ul irq_num)
{
kerror("irq install for pci irq: invalid irq num: %ld.", irq_num);
}
if(p->irq_name != NULL)
if (p->irq_name != NULL)
{
kfree(p->irq_name);
p->irq_name = NULL;
}
if(p->controller != NULL)
if (p->controller != NULL)
{
kfree(p->controller);
p->controller = NULL;

View File

@ -12,15 +12,16 @@ use crate::arch::{PciArch, TraitPciArch};
use crate::include::bindings::bindings::{
c_irq_install, c_irq_uninstall, pt_regs, ul, EAGAIN, EINVAL,
};
use crate::kdebug;
use crate::libs::volatile::{volread, volwrite, Volatile, VolatileReadable, VolatileWritable};
/// MSIX表的一项
#[repr(C)]
struct MsixEntry {
vector_control: Volatile<u32>,
msg_data: Volatile<u32>,
msg_upper_addr: Volatile<u32>,
msg_addr: Volatile<u32>,
msg_upper_addr: Volatile<u32>,
msg_data: Volatile<u32>,
vector_control: Volatile<u32>,
}
/// Pending表的一项
#[repr(C)]
@ -66,17 +67,17 @@ pub enum IrqType {
// PCI设备install中断时需要传递的参数
#[derive(Clone, Debug)]
pub struct IrqMsg {
irq_common_message: IrqCommonMsg,
irq_specific_message: IrqSpecificMsg,
pub irq_common_message: IrqCommonMsg,
pub irq_specific_message: IrqSpecificMsg,
}
// 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则调用传入的函数进行回复
pub irq_index: u16, //要install的中断号在PCI设备中的irq_vector的index
pub irq_name: CString, //中断名字
pub irq_parameter: u16, //中断额外参数,可传入中断处理函数
pub irq_hander: unsafe extern "C" fn(irq_num: ul, parameter: ul, regs: *mut pt_regs), // 中断处理函数
pub irq_ack: Option<unsafe extern "C" fn(irq_num: ul)>, // 中断的ack可为None,若为None则中断处理中会正常通知中断结束不为None则调用传入的函数进行回复
}
// PCI设备install中断时需要传递的特有参数Msi代表MSI与MSIX
#[derive(Clone, Debug)]
@ -88,7 +89,7 @@ pub enum IrqSpecificMsg {
},
}
impl IrqSpecificMsg {
fn msi_default() -> Self {
pub fn msi_default() -> Self {
IrqSpecificMsg::Msi {
processor: 0,
trigger_mode: TriggerMode::EdgeTrigger,
@ -122,16 +123,16 @@ pub trait PciInterrupt: PciDeviceStructure {
if flag.contains(IRQ::PCI_IRQ_MSIX) {
if let Some(cap_offset) = self.msix_capability_offset() {
let data =
PciArch::read_config(&self.common_header().bus_device_function, cap_offset + 4);
let irq_max_num = ((data >> 16) & 0x07ff) as u16;
PciArch::read_config(&self.common_header().bus_device_function, cap_offset);
let irq_max_num = ((data >> 16) & 0x7ff) as u16 + 1;
let data =
PciArch::read_config(&self.common_header().bus_device_function, cap_offset + 4);
let msix_table_bar = (data & 0x01) as u8;
let msix_table_offset = data & 0xfffe;
let msix_table_bar = (data & 0x07) as u8;
let msix_table_offset = data & (!0x07);
let data =
PciArch::read_config(&self.common_header().bus_device_function, cap_offset + 8);
let pending_table_bar = (data & 0x01) as u8;
let pending_table_offset = data & 0xfffe;
let pending_table_bar = (data & 0x07) as u8;
let pending_table_offset = data & (!0x07);
*self.irq_type_mut()? = IrqType::Msix {
msix_table_bar,
msix_table_offset,
@ -503,12 +504,13 @@ pub trait PciInterrupt: PciDeviceStructure {
.bar()
.ok_or(PciError::PciIrqError(PciIrqError::PciBarNotInited))?;
let msix_bar = pcistandardbar.get_bar(msix_table_bar)?;
let vaddr = msix_bar
let vaddr: crate::mm::VirtAddr = msix_bar
.virtual_address()
.ok_or(PciError::PciIrqError(PciIrqError::BarGetVaddrFailed))?
+ msix_table_offset as usize
+ msg.irq_common_message.irq_index as usize * size_of::<MsixEntry>();
let msix_entry = NonNull::new(vaddr.data() as *mut MsixEntry).unwrap();
kdebug!("msg_data: {:?}, msix_addr: {:?}", msg_data, msg_address);
unsafe {
volwrite!(msix_entry, vector_control, 0);
volwrite!(msix_entry, msg_data, msg_data);

View File

@ -5,10 +5,15 @@ use crate::driver::pci::pci::{
PciStandardDeviceBar, PCI_CAP_ID_VNDR,
};
use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqMsg, IrqSpecificMsg, PciInterrupt, IRQ};
use crate::include::bindings::bindings::pt_regs;
use crate::kdebug;
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::ffi::CString;
use core::{
fmt::{self, Display, Formatter},
mem::{align_of, size_of},
@ -53,6 +58,12 @@ const VIRTIO_PCI_CAP_ISR_CFG: u8 = 3;
/// Device specific configuration.
const VIRTIO_PCI_CAP_DEVICE_CFG: u8 = 4;
/// Virtio设备接收中断的设备号
const VIRTIO_RECV_VECTOR: u16 = 56;
/// Virtio设备接收中断的设备号的表项号
const VIRTIO_RECV_VECTOR_INDEX: u16 = 0;
// 接收的queue
const QUEUE_RECEIVE: u16 = 0;
///@brief device id 转换为设备类型
///@param pci_device_iddevice_id
///@return DeviceType 对应的设备类型
@ -89,6 +100,11 @@ pub struct PciTransport {
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();
}
impl PciTransport {
/// Construct a new PCI VirtIO device driver for the given device function on the given PCI
/// root controller.
@ -111,6 +127,30 @@ impl PciTransport {
let mut device_cfg = None;
device.bar_ioremap().unwrap()?;
device.enable_master();
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);
standard_device
.irq_init(IRQ::PCI_IRQ_MSIX)
.expect("IRQ init failed");
// 中断相关信息
let msg = IrqMsg {
irq_common_message: IrqCommonMsg {
irq_index: 0,
irq_name: CString::new(
"Virtio_Recv_
IRQ",
)
.expect("CString::new failed"),
irq_parameter: 0,
irq_hander: virtio_irq_hander,
irq_ack: None,
},
irq_specific_message: IrqSpecificMsg::msi_default(),
};
standard_device.irq_install(msg)?;
standard_device.irq_enable(true)?;
//device_capability为迭代器遍历其相当于遍历所有的cap空间
for capability in device.capabilities().unwrap() {
if capability.id != PCI_CAP_ID_VNDR {
@ -268,16 +308,19 @@ impl Transport for PciTransport {
) {
// Safe because the common config pointer is valid and we checked in get_bar_region that it
// was aligned.
// kdebug!("queue_select={}",queue);
// kdebug!("queue_size={}",size as u16);
// kdebug!("queue_desc={:#x}",descriptors as u64);
// kdebug!("driver_area={:#x}",driver_area);
unsafe {
volwrite!(self.common_cfg, queue_select, queue);
volwrite!(self.common_cfg, queue_size, size as u16);
volwrite!(self.common_cfg, queue_desc, descriptors as u64);
volwrite!(self.common_cfg, queue_driver, driver_area as u64);
volwrite!(self.common_cfg, queue_device, device_area as u64);
if queue == QUEUE_RECEIVE {
volwrite!(self.common_cfg, queue_msix_vector, VIRTIO_RECV_VECTOR_INDEX);
let vector = volread!(self.common_cfg, queue_msix_vector);
if vector != VIRTIO_RECV_VECTOR_INDEX {
panic!("Vector set failed");
}
}
volwrite!(self.common_cfg, queue_enable, 1);
}
}