浏览代码

修复ecam无法获取MCFG table的问题 (#241)

YJwu2023 2 年之前
父节点
当前提交
5c1e552cc7
共有 5 个文件被更改,包括 70 次插入17 次删除
  1. 3 3
      kernel/src/arch/mod.rs
  2. 3 3
      kernel/src/arch/x86_64/pci/pci.rs
  3. 63 9
      kernel/src/driver/pci/pci.rs
  4. 0 1
      kernel/src/driver/virtio/virtio.rs
  5. 1 1
      tools/run-qemu.sh

+ 3 - 3
kernel/src/arch/mod.rs

@@ -3,7 +3,7 @@ pub mod x86_64;
 pub use self::x86_64::pci::pci::X86_64PciArch as PciArch;
 #[cfg(target_arch = "x86_64")]
 pub use self::x86_64::*; //公开x86_64架构下的函数,使外界接口统一
-use crate::driver::pci::pci::{BusDeviceFunction, PciError, PciRoot, SegmentGroupNumber};
+use crate::driver::pci::pci::{BusDeviceFunction, PciAddr, PciError, PciRoot, SegmentGroupNumber};
 /// TraitPciArch Pci架构相关函数,任何架构都应独立实现trait里的函数
 pub trait TraitPciArch {
     /// @brief 读取寄存器值,x86_64架构通过读取两个特定io端口实现
@@ -18,8 +18,8 @@ pub trait TraitPciArch {
     fn write_config(bus_device_function: &BusDeviceFunction, offset: u8, data: u32);
     /// @brief PCI域地址到存储器域地址的转换,x86_64架构为一一对应
     /// @param address PCI域地址
-    /// @return  Result<usize, PciError> 转换结果或出错原因
-    fn address_pci_to_address_memory(address: usize) -> Result<usize, PciError>;
+    /// @return usize 转换结果
+    fn address_pci_to_physical(pci_address: PciAddr) -> usize;
     /// @brief 获取Segement的root地址,x86_64架构为acpi mcfg表中读取
     /// @param segement 组id
     /// @return  Result<PciRoot, PciError> 转换结果或出错原因

+ 3 - 3
kernel/src/arch/x86_64/pci/pci.rs

@@ -1,7 +1,7 @@
 use crate::arch::TraitPciArch;
 use crate::driver::acpi::acpi::mcfg_find_segment;
 use crate::driver::pci::pci::{
-    BusDeviceFunction, PciError, PciRoot, SegmentGroupNumber, PORT_PCI_CONFIG_ADDRESS,
+    BusDeviceFunction, PciAddr, PciError, PciRoot, SegmentGroupNumber, PORT_PCI_CONFIG_ADDRESS,
     PORT_PCI_CONFIG_DATA,
 };
 use crate::include::bindings::bindings::{
@@ -40,8 +40,8 @@ impl TraitPciArch for X86_64PciArch {
         }
     }
 
-    fn address_pci_to_address_memory(address: usize) -> Result<usize, PciError> {
-        Ok(address)
+    fn address_pci_to_physical(pci_address: PciAddr) -> usize {
+        return pci_address.data();
     }
 
     fn ecam_root(segement: SegmentGroupNumber) -> Result<PciRoot, PciError> {

+ 63 - 9
kernel/src/driver/pci/pci.rs

@@ -11,10 +11,12 @@ use crate::{kdebug, kerror, kinfo, kwarn};
 use alloc::vec::Vec;
 use alloc::{boxed::Box, collections::LinkedList};
 use bitflags::bitflags;
+
 use core::{
     convert::TryFrom,
-    fmt::{self, Display, Formatter},
+    fmt::{self, Debug, Display, Formatter},
 };
+
 // PCI_DEVICE_LINKEDLIST 添加了读写锁的全局链表,里面存储了检索到的PCI设备结构体
 // PCI_ROOT_0 Segment为0的全局PciRoot
 lazy_static! {
@@ -29,6 +31,40 @@ lazy_static! {
         }
     };
 }
+/// PCI域地址
+#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
+#[repr(transparent)]
+pub struct PciAddr(usize);
+
+impl PciAddr {
+    #[inline(always)]
+    pub const fn new(address: usize) -> Self {
+        Self(address)
+    }
+
+    /// @brief 获取PCI域地址的值
+    #[inline(always)]
+    pub fn data(&self) -> usize {
+        self.0
+    }
+
+    /// @brief 将PCI域地址加上一个偏移量
+    #[inline(always)]
+    pub fn add(self, offset: usize) -> Self {
+        Self(self.0 + offset)
+    }
+
+    /// @brief 判断PCI域地址是否按照指定要求对齐
+    #[inline(always)]
+    pub fn check_aligned(&self, align: usize) -> bool {
+        return self.0 & (align - 1) == 0;
+    }
+}
+impl Debug for PciAddr {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "PciAddr({:#x})", self.0)
+    }
+}
 
 /// 添加了读写锁的链表,存储PCI设备结构体
 pub struct PciDeviceLinkedList {
@@ -489,7 +525,7 @@ impl Display for PciRoot {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         write!(
                 f,
-                "PCI Root with segement:{}, bus begin at {}, bus end at {}, physical address at {},mapped at {:#x}",
+                "PCI Root with segement:{}, bus begin at {}, bus end at {}, physical address at {:#x},mapped at {:#x}",
                 self.segement_group_number, self.bus_begin, self.bus_end, self.physical_address_base, self.mmio_base.unwrap() as usize
             )
     }
@@ -506,13 +542,14 @@ impl PciRoot {
     /// @brief  完成物理地址到虚拟地址的映射,并将虚拟地址加入mmio_base变量
     /// @return 返回错误或Ok(0)
     fn map(&mut self) -> Result<u8, PciError> {
-        let bus_number = self.bus_end - self.bus_begin + 1;
-        let bus_number_double = (bus_number + 1) / 2;
+        //kdebug!("bus_begin={},bus_end={}", self.bus_begin,self.bus_end);
+        let bus_number = (self.bus_end - self.bus_begin) as u32 + 1;
+        let bus_number_double = (bus_number - 1) / 2 + 1; //一个bus占据1MB空间,计算全部bus占据空间相对于2MB空间的个数
         let mut virtaddress: u64 = 0;
         let vaddr_ptr = &mut virtaddress as *mut u64;
         let mut virtsize: u64 = 0;
         let virtsize_ptr = &mut virtsize as *mut u64;
-        let size = bus_number_double as u32 * PAGE_2M_SIZE;
+        let size = bus_number_double * PAGE_2M_SIZE;
         unsafe {
             let initial_mm_ptr = &mut initial_mm as *mut mm_struct;
             if let Err(_) =
@@ -978,7 +1015,19 @@ fn pci_check_bus(bus: u8) -> Result<u8, PciError> {
 #[no_mangle]
 pub extern "C" fn rs_pci_init() {
     pci_init();
-    //kdebug!("{}",PCI_ROOT_0.unwrap());
+    if PCI_ROOT_0.is_some() {
+        kdebug!("{}", PCI_ROOT_0.unwrap());
+        //以下为ecam的读取寄存器值测试,经测试可正常读取
+        // let bus_device_function = BusDeviceFunction {
+        //     bus: 0,
+        //     device: 2,
+        //     function: 0,
+        // };
+        // kdebug!(
+        //     "Ecam read virtio-net device status={:#x}",
+        //     (PCI_ROOT_0.unwrap().read_config(bus_device_function, 4)>>16) as u16
+        // );
+    }
 }
 /// @brief pci初始化函数
 pub fn pci_init() {
@@ -996,7 +1045,7 @@ pub fn pci_init() {
         let common_header = box_pci_device.common_header();
         match box_pci_device.header_type() {
             HeaderType::Standard if common_header.status & 0x10 != 0 => {
-                kinfo!("Found pci standard device with class code ={} subclass={} status={:#x} cap_pointer={:#x}  vendor={:#x}, device id={:#x}", common_header.class_code, common_header.subclass, common_header.status, box_pci_device.as_standard_device().unwrap().capabilities_pointer,common_header.vendor_id, common_header.device_id);
+                kinfo!("Found pci standard device with class code ={} subclass={} status={:#x} cap_pointer={:#x}  vendor={:#x}, device id={:#x},bdf={}", common_header.class_code, common_header.subclass, common_header.status, box_pci_device.as_standard_device().unwrap().capabilities_pointer,common_header.vendor_id, common_header.device_id,common_header.bus_device_function);
             }
             HeaderType::Standard => {
                 kinfo!(
@@ -1055,7 +1104,11 @@ impl BusDeviceFunction {
 ///实现BusDeviceFunction的Display trait,使其可以直接输出
 impl Display for BusDeviceFunction {
     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
-        write!(f, "{:02x}:{:02x}.{}", self.bus, self.device, self.function)
+        write!(
+            f,
+            "bus {} device {} function{}",
+            self.bus, self.device, self.function
+        )
     }
 }
 /// The location allowed for a memory BAR.
@@ -1267,7 +1320,8 @@ pub fn pci_bar_init(
                 address |= u64::from(address_top) << 32;
                 bar_index_ignore = bar_index + 1; //下个bar跳过,因为64位的memory bar覆盖了两个bar
             }
-            //kdebug!("address={:#x},size={:#x}",address,size);
+            let pci_address = PciAddr::new(address as usize);
+            address = PciArch::address_pci_to_physical(pci_address) as u64; //PCI总线域物理地址转换为存储器域物理地址
             unsafe {
                 let vaddr_ptr = &mut virtaddress as *mut u64;
                 let mut virtsize: u64 = 0;

+ 0 - 1
kernel/src/driver/virtio/virtio.rs

@@ -9,7 +9,6 @@ use crate::libs::rwlock::RwLockWriteGuard;
 use crate::{kdebug, kerror, kwarn};
 use alloc::{boxed::Box, collections::LinkedList};
 use virtio_drivers::transport::{DeviceType, Transport};
-
 const NETWORK_CLASS: u8 = 0x2;
 const ETHERNET_SUBCLASS: u8 = 0x0;
 

+ 1 - 1
tools/run-qemu.sh

@@ -29,7 +29,7 @@ QEMU_RTC_CLOCK="clock=host,base=localtime"
 QEMU_SERIAL="file:../serial_opt.txt"
 QEMU_DRIVE="id=disk,file=${QEMU_DISK_IMAGE},if=none"
 
-QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -nic user,model=virtio-net-pci -usb -device qemu-xhci,id=xhci,p2=8,p3=4 -machine accel=${qemu_accel}"
+QEMU_DEVICES="-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0 -nic user,model=virtio-net-pci  -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} "