瀏覽代碼

:new: 使能msi的代码

fslongjin 3 年之前
父節點
當前提交
f4cd6f8811
共有 3 個文件被更改,包括 206 次插入12 次删除
  1. 172 8
      kernel/driver/pci/pci.c
  2. 33 3
      kernel/driver/pci/pci.h
  3. 1 1
      run.sh

+ 172 - 8
kernel/driver/pci/pci.c

@@ -25,16 +25,28 @@ static void pci_checkBus(uint8_t bus);
         }                                                             \
     } while (0)
 
+/**
+ * @brief 生成架构相关的msi的message address
+ *
+ */
+#define pci_get_arch_msi_message_address(processor) ((uint64_t)(0xfee00000UL | (processor << 12)))
+
+/**
+ * @brief 生成架构相关的message data
+ *
+ */
+#define pci_get_arch_msi_message_data(vector, processor, edge_trigger, assert) ((uint32_t)((vector & 0xff) | (edge_trigger == 1 ? 0 : (1 << 15)) | (assert == 0 ? 0 : (1 << 14))))
+
 /**
  * @brief 从pci配置空间读取信息
  *
  * @param bus 总线号
  * @param slot 设备号
  * @param func 功能号
- * @param offset 寄存器偏移量
+ * @param offset 字节偏移量
  * @return uint 寄存器值
  */
-uint pci_read_config(uchar bus, uchar slot, uchar func, uchar offset)
+uint32_t pci_read_config(uchar bus, uchar slot, uchar func, uchar offset)
 {
     uint lbus = (uint)bus;
     uint lslot = (uint)slot;
@@ -45,11 +57,34 @@ uint pci_read_config(uchar bus, uchar slot, uchar func, uchar offset)
     io_out32(PORT_PCI_CONFIG_ADDRESS, address);
     // 读取返回的数据
     uint32_t ret = (uint)(io_in32(PORT_PCI_CONFIG_DATA));
-    // kdebug("data=%#010lx", ret);
 
     return ret;
 }
 
+/**
+ * @brief 向pci配置空间写入信息
+ *
+ * @param bus 总线号
+ * @param slot 设备号
+ * @param func 功能号
+ * @param offset 字节偏移量
+ * @return uint 返回码
+ */
+uint pci_write_config(uchar bus, uchar slot, uchar func, uchar offset, uint32_t data)
+{
+    uint lbus = (uint)bus;
+    uint lslot = (uint)slot;
+    uint lfunc = ((uint)func) & 7;
+
+    // 构造pci配置空间地址
+    uint address = (uint)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xfc) | ((uint)0x80000000));
+    io_out32(PORT_PCI_CONFIG_ADDRESS, address);
+    // 写入数据
+    io_out32(PORT_PCI_CONFIG_DATA, data);
+
+    return 0;
+}
+
 /**
  * @brief 读取type为0x0的pci设备的header
  * 本函数只应被 pci_read_header()调用
@@ -202,7 +237,10 @@ static void pci_read_pci_to_cardbus_bridge_header(struct pci_device_structure_pc
  */
 void *pci_read_header(int *type, uchar bus, uchar slot, uchar func, bool add_to_list)
 {
-    struct pci_device_structure_header_t *common_header = (struct pci_device_structure_header_t *)kmalloc(100, 0);
+    struct pci_device_structure_header_t *common_header = (struct pci_device_structure_header_t *)kmalloc(127, 0);
+    common_header->bus = bus;
+    common_header->device = slot;
+    common_header->func = func;
 
     uint32_t tmp32;
     // 先读取公共header
@@ -266,10 +304,10 @@ void *pci_read_header(int *type, uchar bus, uchar slot, uchar func, bool add_to_
         return ret;
         break;
     default: // 错误的头类型 这里不应该被执行
-        //kerror("PCI->pci_read_header(): Invalid header type.");
+        // kerror("PCI->pci_read_header(): Invalid header type.");
         *type = E_WRONG_HEADER_TYPE;
-        //kerror("vendor id=%#010lx", common_header->Vendor_ID);
-        //kerror("header type = %d", common_header->HeaderType);
+        // kerror("vendor id=%#010lx", common_header->Vendor_ID);
+        // kerror("header type = %d", common_header->HeaderType);
         kfree(common_header);
         return NULL;
         break;
@@ -405,9 +443,135 @@ void pci_init()
     struct pci_device_structure_header_t *ptr = container_of(pci_device_structure_list, struct pci_device_structure_header_t, list);
     for (int i = 0; i < count_device_list; ++i)
     {
-        kinfo("[ pci device %d ] class code = %d\tsubclass=%d", i, ptr->Class_code, ptr->SubClass);
+        if (ptr->HeaderType == 0x0)
+        {
+            if (ptr->Status & 0x10)
+            {
+                kinfo("[ pci device %d ] class code = %d\tsubclass=%d\tstatus=%#010lx\tcap_pointer=%#010lx", i, ptr->Class_code, ptr->SubClass, ptr->Status, ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer);
+                uint32_t tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer);
+                kdebug("cap+0x0 = %#010lx", tmp);
+            }
+            else
+            {
+
+                kinfo("[ pci device %d ] class code = %d\tsubclass=%d\tstatus=%#010lx\t", i, ptr->Class_code, ptr->SubClass, ptr->Status);
+            }
+        }
+        else if (ptr->HeaderType == 0x1)
+        {
+            if (ptr->Status & 0x10)
+            {
+                kinfo("[ pci device %d ] class code = %d\tsubclass=%d\tstatus=%#010lx\tcap_pointer=%#010lx", i, ptr->Class_code, ptr->SubClass, ptr->Status, ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer);
+            }
+            else
+            {
+
+                kinfo("[ pci device %d ] class code = %d\tsubclass=%d\tstatus=%#010lx\t", i, ptr->Class_code, ptr->SubClass, ptr->Status);
+            }
+        }
+        else if (ptr->HeaderType == 0x2)
+        {
+            kinfo("[ pci device %d ] class code = %d\tsubclass=%d\tstatus=%#010lx\t", i, ptr->Class_code, ptr->SubClass, ptr->Status);
+        }
 
         ptr = container_of(list_next(&(ptr->list)), struct pci_device_structure_header_t, list);
     }
     kinfo("PCI bus initialized.")
+}
+
+/**
+ * @brief 启用 Message Signaled Interrupts
+ *
+ * @param header 设备header
+ * @param vector 中断向量号
+ * @param processor 要投递到的处理器
+ * @param edge_trigger 是否边缘触发
+ * @param assert 是否高电平触发
+ *
+ * @return 返回码
+ */
+int pci_enable_msi(void *header, uint8_t vector, uint32_t processor, uint8_t edge_trigger, uint8_t assert)
+{
+    struct pci_device_structure_header_t *ptr = (struct pci_device_structure_header_t *)header;
+    uint32_t cap_ptr;
+    uint32_t tmp;
+    uint16_t message_control;
+    uint64_t message_addr;
+    switch (ptr->HeaderType)
+    {
+    case 0x00: // general device
+        if (!(ptr->Status & 0x10))
+            return E_NOT_SUPPORT_MSI;
+        cap_ptr = ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer;
+
+        tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
+
+        message_control = (tmp >> 16) & 0xffff;
+
+        if (tmp & 0xff != 0x5)
+            return E_NOT_SUPPORT_MSI;
+
+        // 写入message address
+        message_addr = pci_get_arch_msi_message_address(processor); // 获取message address
+        pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x4, (uint32_t)(message_addr & 0xffffffff));
+
+        if (message_control & (1 << 7)) // 64位
+            pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8, (uint32_t)((message_addr >> 32) & 0xffffffff));
+
+        // 写入message data
+        tmp = pci_get_arch_msi_message_data(vector, processor, edge_trigger, assert);
+        if (message_control & (1 << 7)) // 64位
+            pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0xc, tmp);
+        else
+            pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8, tmp);
+
+        // 使能msi
+        tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
+        tmp |= (1 << 16);
+        pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
+
+        break;
+        
+    case 0x01: // pci to pci bridge
+        if (!(ptr->Status & 0x10))
+            return E_NOT_SUPPORT_MSI;
+        cap_ptr = ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer;
+
+        tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
+
+        message_control = (tmp >> 16) & 0xffff;
+
+        if (tmp & 0xff != 0x5)
+            return E_NOT_SUPPORT_MSI;
+
+        // 写入message address
+        message_addr = pci_get_arch_msi_message_address(processor); // 获取message address
+        pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x4, (uint32_t)(message_addr & 0xffffffff));
+
+        if (message_control & (1 << 7)) // 64位
+            pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8, (uint32_t)((message_addr >> 32) & 0xffffffff));
+
+        // 写入message data
+        tmp = pci_get_arch_msi_message_data(vector, processor, edge_trigger, assert);
+        if (message_control & (1 << 7)) // 64位
+            pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0xc, tmp);
+        else
+            pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8, tmp);
+
+        // 使能msi
+        tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
+        tmp |= (1 << 16);
+        pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
+
+        break;
+    case 0x02: // pci to card bus bridge
+        return E_NOT_SUPPORT_MSI;
+        break;
+
+    default: // 不应该到达这里
+        return E_WRONG_HEADER_TYPE;
+        break;
+    }
+
+    return 0;
 }

+ 33 - 3
kernel/driver/pci/pci.h

@@ -8,6 +8,7 @@
 
 #define E_DEVICE_INVALID -1
 #define E_WRONG_HEADER_TYPE -2
+#define E_NOT_SUPPORT_MSI -3    // 设备不支持msi
 
 // pci设备结构信息的链表
 struct List * pci_device_structure_list = NULL;
@@ -22,6 +23,11 @@ void pci_init();
 struct pci_device_structure_header_t
 {
     struct List list;
+    // ==== 以下三个变量表示该结构体所处的位置
+    uint8_t bus;
+    uint8_t device;
+    uint8_t func;
+
     uint16_t Vendor_ID; // 供应商ID 0xffff是一个无效值,在读取访问不存在的设备的配置空间寄存器时返回
     uint16_t Device_ID; // 设备ID,标志特定设备
 
@@ -166,10 +172,21 @@ struct pci_device_structure_pci_to_cardbus_bridge_t
  * @param bus 总线号
  * @param slot 插槽号
  * @param func 功能号
- * @param offset 寄存器偏移量
+ * @param offset 字节偏移量
  * @return uint 寄存器值
  */
-uint pci_read_config(uchar bus, uchar slot, uchar func, uchar offset);
+uint32_t pci_read_config(uchar bus, uchar slot, uchar func, uchar offset);
+
+/**
+ * @brief 向pci配置空间写入信息
+ *
+ * @param bus 总线号
+ * @param slot 设备号
+ * @param func 功能号
+ * @param offset 字节偏移量
+ * @return uint 寄存器值
+ */
+uint pci_write_config(uchar bus, uchar slot, uchar func, uchar offset, uint32_t data);
 
 /**
  * @brief 读取pci设备标头
@@ -186,4 +203,17 @@ void* pci_read_header(int *type, uchar bus, uchar slot, uchar func, bool add_to_
  * @brief 扫描所有pci总线上的所有设备
  * 
  */
-void pci_checkAllBuses();
+void pci_checkAllBuses();
+
+/**
+ * @brief 启用 Message Signaled Interrupts
+ * 
+ * @param header 设备header
+ * @param vector 中断向量号
+ * @param processor 要投递到的处理器
+ * @param edge_trigger 是否边缘触发
+ * @param assert 是否高电平触发
+ * 
+ * @return 返回码
+ */
+int pci_enable_msi(void * header, uint8_t vector, uint32_t processor, uint8_t edge_trigger, uint8_t assert);

+ 1 - 1
run.sh

@@ -94,7 +94,7 @@ if [ $flag_can_run -eq 1 ]; then
     else
         qemu-system-x86_64 -cdrom ${iso} -m 512M \
         -monitor telnet::2333,server,nowait -serial stdio -s -cpu IvyBridge --enable-kvm \
-         -drive id=disk,file=bin/disk.img,if=none \
+        -drive id=disk,file=bin/disk.img,if=none \
         -device ahci,id=ahci \
         -device ide-hd,drive=disk,bus=ahci.0    \
         -usb