mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-22 02:53:23 +00:00
添加中断 (#370)
* 添加中断 * dhcp更改为全局socketset * 解决异常中断的问题,使得能够使用中断来处理网卡数据 --------- Co-authored-by: longjin <longjin@RinGoTek.cn>
This commit is contained in:
@ -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
|
||||
{
|
||||
// ==========外部中断控制器========
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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_id,device_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);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user