diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 5a53daa7..5ab1a8b2 100644 --- a/kernel/Cargo.toml +++ b/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 } diff --git a/kernel/src/arch/x86_64/msi.rs b/kernel/src/arch/x86_64/msi.rs index fd72007e..5f24e063 100644 --- a/kernel/src/arch/x86_64/msi.rs +++ b/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 分配的中断向量号 diff --git a/kernel/src/driver/interrupt/apic/apic.c b/kernel/src/driver/interrupt/apic/apic.c index fa403fc5..48438fc3 100644 --- a/kernel/src/driver/interrupt/apic/apic.c +++ b/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 { // ==========外部中断控制器======== diff --git a/kernel/src/driver/pci/pci_irq.c b/kernel/src/driver/pci/pci_irq.c index 4b527ce8..5778ba96 100644 --- a/kernel/src/driver/pci/pci_irq.c +++ b/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; diff --git a/kernel/src/driver/pci/pci_irq.rs b/kernel/src/driver/pci/pci_irq.rs index 823cfb84..6c6d978e 100644 --- a/kernel/src/driver/pci/pci_irq.rs +++ b/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, - msg_data: Volatile, - msg_upper_addr: Volatile, msg_addr: Volatile, + msg_upper_addr: Volatile, + msg_data: Volatile, + vector_control: Volatile, } /// 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, // 中断的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, // 中断的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::(); 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); diff --git a/kernel/src/driver/virtio/transport_pci.rs b/kernel/src/driver/virtio/transport_pci.rs index 13785428..6a88aa71 100644 --- a/kernel/src/driver/virtio/transport_pci.rs +++ b/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>, } +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); } } diff --git a/kernel/src/exception/irq.c b/kernel/src/exception/irq.c index 80d454c4..148b8bda 100644 --- a/kernel/src/exception/irq.c +++ b/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, }; /** diff --git a/kernel/src/exception/irq.h b/kernel/src/exception/irq.h index f733c6ae..2e50dda4 100644 --- a/kernel/src/exception/irq.h +++ b/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 diff --git a/kernel/src/net/net_core.rs b/kernel/src/net/net_core.rs index 37a278e2..ae28be88 100644 --- a/kernel/src/net/net_core.rs +++ b/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::(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::(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>> = 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(()); +} diff --git a/tools/run-qemu.sh b/tools/run-qemu.sh index 7594bda5..38247449 100644 --- a/tools/run-qemu.sh +++ b/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}"