Explorar el Código

添加中断 (#370)

* 添加中断

* dhcp更改为全局socketset

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

---------

Co-authored-by: longjin <[email protected]>
YJwu2023 hace 1 año
padre
commit
0dd8ff4332

+ 0 - 1
kernel/Cargo.toml

@@ -16,7 +16,6 @@ bitflags = "1.3.2"
 virtio-drivers = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/virtio-drivers.git", rev = "f1d1cbb" }
 # 一个无锁MPSC队列
 thingbuf = { version = "0.1.3", default-features = false, features = ["alloc"] }
-# smoltcp 0.9.1
 smoltcp = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/smoltcp.git", rev = "9027825", default-features = false, features = ["log", "alloc",  "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6"]}
 # num-traits 0.2.15
 num-traits = { git = "https://git.mirrors.dragonos.org/DragonOS-Community/num-traits.git", rev="1597c1c", default-features = false }

+ 1 - 1
kernel/src/arch/x86_64/msi.rs

@@ -3,7 +3,7 @@ use crate::driver::pci::pci_irq::TriggerMode;
 /// @param processor 目标CPU ID号
 /// @return MSI Message Address
 pub fn ia64_pci_get_arch_msi_message_address(processor: u16) -> u32 {
-    0xfee00000 as u32 | ((processor as u32) << 12)
+    0xfee00000 | ((processor as u32) << 12)
 }
 /// @brief 获得MSI Message Data
 /// @param vector 分配的中断向量号

+ 2 - 3
kernel/src/driver/interrupt/apic/apic.c

@@ -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
     {
         // ==========外部中断控制器========

+ 14 - 14
kernel/src/driver/pci/pci_irq.c

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

+ 20 - 18
kernel/src/driver/pci/pci_irq.rs

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

+ 47 - 4
kernel/src/driver/virtio/transport_pci.rs

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

+ 3 - 1
kernel/src/exception/irq.c

@@ -86,9 +86,10 @@ Build_IRQ(0x34);
 Build_IRQ(0x35);
 Build_IRQ(0x36);
 Build_IRQ(0x37);
+Build_IRQ(0x38);
 
 // 初始化中断数组
-void (*interrupt_table[24])(void) = {
+void (*interrupt_table[25])(void) = {
     IRQ0x20interrupt,
     IRQ0x21interrupt,
     IRQ0x22interrupt,
@@ -113,6 +114,7 @@ void (*interrupt_table[24])(void) = {
     IRQ0x35interrupt,
     IRQ0x36interrupt,
     IRQ0x37interrupt,
+    IRQ0x38interrupt,
 };
 
 /**

+ 3 - 2
kernel/src/exception/irq.h

@@ -16,11 +16,11 @@
 #pragma GCC push_options
 #pragma GCC optimize ("O0")
 
-#define IRQ_NUM 24
+#define IRQ_NUM 25
 #define SMP_IRQ_NUM 10
 #define LOCAL_APIC_IRQ_NUM 50
 
-extern void (*interrupt_table[24])(void);
+extern void (*interrupt_table[25])(void);
 extern void do_IRQ(struct pt_regs *regs, ul number);
 
 
@@ -82,6 +82,7 @@ extern void (*local_apic_interrupt_table[LOCAL_APIC_IRQ_NUM])(void);
 	53	PIRQF
 	54	PIRQG
 	55	PIRQH
+	56  VIRTIO_RECV
 	
 	
 0x80		system call

+ 28 - 8
kernel/src/net/net_core.rs

@@ -31,11 +31,12 @@ impl TimerFunction for NetWorkPollFunc {
 pub fn net_init() -> Result<(), SystemError> {
     dhcp_query()?;
     // Init poll timer function
-    let next_time = next_n_ms_timer_jiffies(5);
-    let timer = Timer::new(Box::new(NetWorkPollFunc), next_time);
-    timer.activate();
+    // let next_time = next_n_ms_timer_jiffies(5);
+    // let timer = Timer::new(Box::new(NetWorkPollFunc), next_time);
+    // timer.activate();
     return Ok(());
 }
+
 fn dhcp_query() -> Result<(), SystemError> {
     let binding = NET_DRIVERS.write();
 
@@ -52,15 +53,14 @@ fn dhcp_query() -> Result<(), SystemError> {
     // IMPORTANT: This should be removed in production.
     dhcp_socket.set_max_lease_duration(Some(smoltcp::time::Duration::from_secs(10)));
 
-    let mut sockets = smoltcp::iface::SocketSet::new(vec![]);
-    let dhcp_handle = sockets.add(dhcp_socket);
+    let dhcp_handle = SOCKET_SET.lock().add(dhcp_socket);
 
     const DHCP_TRY_ROUND: u8 = 10;
     for i in 0..DHCP_TRY_ROUND {
         kdebug!("DHCP try round: {}", i);
-        let _flag = net_face.poll(&mut sockets);
-        let event = sockets.get_mut::<dhcpv4::Socket>(dhcp_handle).poll();
-        // kdebug!("event = {event:?} !!!");
+        net_face.poll(&mut SOCKET_SET.lock()).ok();
+        let mut binding = SOCKET_SET.lock();
+        let event = binding.get_mut::<dhcpv4::Socket>(dhcp_handle).poll();
 
         match event {
             None => {}
@@ -161,3 +161,23 @@ pub fn poll_ifaces_try_lock(times: u16) -> Result<(), SystemError> {
     // 尝试次数用完,返回错误
     return Err(SystemError::EAGAIN_OR_EWOULDBLOCK);
 }
+
+/// 对ifaces进行轮询。
+///
+/// @return 轮询成功,返回Ok(())
+/// @return 加锁超时,返回SystemError::EAGAIN_OR_EWOULDBLOCK
+/// @return 没有网卡,返回SystemError::ENODEV
+pub fn poll_ifaces_try_lock_onetime() -> Result<(), SystemError> {
+    let guard: RwLockReadGuard<BTreeMap<usize, Arc<dyn NetDriver>>> = NET_DRIVERS.read();
+    if guard.len() == 0 {
+        kwarn!("poll_ifaces: No net driver found!");
+        // 没有网卡,返回错误
+        return Err(SystemError::ENODEV);
+    }
+    let mut sockets = SOCKET_SET.try_lock()?;
+    for (_, iface) in guard.iter() {
+        iface.poll(&mut sockets).ok();
+    }
+    SOCKET_WAITQUEUE.wakeup_all(None);
+    return Ok(());
+}

+ 2 - 2
tools/run-qemu.sh

@@ -62,8 +62,8 @@ QEMU_DRIVE="id=disk,file=${QEMU_DISK_IMAGE},if=none"
 
 # ps: 下面这条使用tap的方式,无法dhcp获取到ip,暂时不知道为什么
 # QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -net nic,netdev=nic0 -netdev tap,id=nic0,model=virtio-net-pci,script=qemu/ifup-nat,downscript=qemu/ifdown-nat -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel} -machine q35 "
-QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -nic user,model=virtio-net-pci,hostfwd=tcp::12580-:12580 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel} -machine q35 "
-
+#QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -nic user,model=virtio-net-pci,hostfwd=tcp::12580-:12580 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel} -machine q35 "
+QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -netdev user,id=hostnet0,hostfwd=tcp::12580-:12580 -device virtio-net-pci,vectors=5,netdev=hostnet0,id=net0 -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel} -machine q35 "
 QEMU_ARGUMENT="-d ${QEMU_DISK_IMAGE} -m ${QEMU_MEMORY} -smp ${QEMU_SMP} -boot order=d -monitor ${QEMU_MONITOR} -d ${qemu_trace_std} "
 
 QEMU_ARGUMENT+="-s -S -cpu ${QEMU_CPU_FEATURES} -rtc ${QEMU_RTC_CLOCK} -serial ${QEMU_SERIAL} -drive ${QEMU_DRIVE} ${QEMU_DEVICES}"