瀏覽代碼

:new: 完成了简单的APIC中断处理功能

fslongjin 3 年之前
父節點
當前提交
ee49849158
共有 6 個文件被更改,包括 177 次插入38 次删除
  1. 3 20
      kernel/driver/acpi/acpi.c
  2. 1 1
      kernel/driver/acpi/acpi.h
  3. 139 13
      kernel/driver/interrupt/apic/apic.c
  4. 32 0
      kernel/driver/interrupt/apic/apic.h
  5. 0 3
      kernel/mm/mm.c
  6. 2 1
      kernel/mm/mm.h

+ 3 - 20
kernel/driver/acpi/acpi.c

@@ -47,7 +47,7 @@ void acpi_iter_SDT(bool (*_fun)(const struct acpi_system_description_table_heade
  * @brief 获取MADT信息 Multiple APIC Description Table
  *
  * @param _iter_data 要被迭代的信息的结构体
- * @param _data 返回信息的结构体指针
+ * @param _data 返回的MADT的虚拟地址
  * @param count 返回数组的长度
  * @return true
  * @return false
@@ -57,26 +57,9 @@ bool acpi_get_MADT(const struct acpi_system_description_table_header_t *_iter_da
     if (!(_iter_data->Signature[0] == 'A' && _iter_data->Signature[1] == 'P' && _iter_data->Signature[2] == 'I' && _iter_data->Signature[3] == 'C'))
         return false;
     //*(struct acpi_Multiple_APIC_Description_Table_t *)_data = *(struct acpi_Multiple_APIC_Description_Table_t *)_iter_data;
+    // 返回MADT的虚拟地址
     *(ul*)_data = _iter_data;
-    kdebug("_iter_data = %#018lx", (ul)_iter_data);
-    kdebug("_data = %#018lx", (ul)_data);
-    //_data = _iter_data;
-    /*
-    void *ent = (void *)(_iter_data) + sizeof(struct acpi_Multiple_APIC_Description_Table_t);
-    struct apic_Interrupt_Controller_Structure_header_t *header;
-    for (int i = 0; i < 17; ++i)
-    {
-        header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
-        kdebug("[ %d ] type=%d, length=%d", i, header->type, header->length);
-        if (header->type == 1)
-        {
-            struct acpi_IO_APIC_Structure_t *t = (struct acpi_IO_APIC_Structure_t *)ent;
-            kdebug("IO apic addr = %#018lx", t->IO_APIC_Address);
-        }
-
-        ent += header->length;
-    }
-    */
+    
     return true;
 }
 

+ 1 - 1
kernel/driver/acpi/acpi.h

@@ -151,7 +151,7 @@ void acpi_iter_SDT(bool (*_fun)(const struct acpi_system_description_table_heade
  * @brief 获取MADT信息 Multiple APIC Description Table
  *
  * @param _iter_data 要被迭代的信息的结构体
- * @param _data 返回信息的结构体指针
+ * @param _data 返回的MADT的虚拟地址
  * @param count 返回数组的长度
  * @return true
  * @return false

+ 139 - 13
kernel/driver/interrupt/apic/apic.c

@@ -15,21 +15,14 @@ uint local_apic_version;
 uint local_apic_max_LVT_entries;
 
 static struct acpi_Multiple_APIC_Description_Table_t *madt;
-
+static struct acpi_IO_APIC_Structure_t *io_apic_ICS;
 /**
  * @brief 初始化io_apic
  *
  */
 void apic_io_apic_init()
 {
-    // 初始化中断门, 中断使用第二个ist
-    for (int i = 32; i <= 55; ++i)
-        set_intr_gate(i, 2, interrupt_table[i - 32]);
 
-    // 屏蔽类8259A芯片
-    io_out8(0x21, 0xff);
-    io_out8(0xa1, 0xff);
-    kdebug("8259A Masked.");
     ul madt_addr;
     kdebug("madt_addr = %#018lx", (ul)madt_addr);
     acpi_iter_SDT(acpi_get_MADT, &madt_addr);
@@ -38,22 +31,78 @@ void apic_io_apic_init()
     kdebug("MADT->local intr controller addr=%#018lx", madt->Local_Interrupt_Controller_Address);
     kdebug("MADT->length= %d bytes", madt->header.Length);
 
+    // 寻找io apic的ICS
     void *ent = (void *)(madt_addr) + sizeof(struct acpi_Multiple_APIC_Description_Table_t);
-    struct apic_Interrupt_Controller_Structure_header_t *header;
-    for (int i = 0; i < 17; ++i)
+    struct apic_Interrupt_Controller_Structure_header_t *header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
+    while (header->length > 2)
     {
         header = (struct apic_Interrupt_Controller_Structure_header_t *)ent;
-        kdebug("[ %d ] type=%d, length=%d", i, header->type, header->length);
         if (header->type == 1)
         {
             struct acpi_IO_APIC_Structure_t *t = (struct acpi_IO_APIC_Structure_t *)ent;
             kdebug("IO apic addr = %#018lx", t->IO_APIC_Address);
+            io_apic_ICS = t;
+            break;
         }
 
         ent += header->length;
     }
-    apic_local_apic_init();
-    sti();
+    kdebug("Global_System_Interrupt_Base=%d", io_apic_ICS->Global_System_Interrupt_Base);
+
+    apic_ioapic_map.addr_phys = io_apic_ICS->IO_APIC_Address;
+    apic_ioapic_map.virtual_index_addr = (unsigned char *)APIC_IO_APIC_VIRT_BASE_ADDR;
+    apic_ioapic_map.virtual_data_addr = (uint *)(APIC_IO_APIC_VIRT_BASE_ADDR + 0x10);
+    apic_ioapic_map.virtual_EOI_addr = (uint *)(APIC_IO_APIC_VIRT_BASE_ADDR + 0x40);
+
+    // 填写页表,完成地址映射
+    mm_map_phys_addr(apic_ioapic_map.virtual_index_addr, apic_ioapic_map.addr_phys, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
+
+    // 设置IO APIC ID 为0x0f000000
+    *apic_ioapic_map.virtual_index_addr = 0x00;
+    io_mfence();
+    *apic_ioapic_map.virtual_data_addr = 0x0f000000;
+    io_mfence();
+
+    kdebug("IOAPIC Version:%#010x", ((*apic_ioapic_map.virtual_data_addr) >> 24) & 0xf);
+    io_mfence();
+
+    // 获取IO APIC Version
+    *apic_ioapic_map.virtual_index_addr = 0x01;
+    io_mfence();
+    kdebug("IO APIC Version=%d, Max Redirection Entries=%d", *apic_ioapic_map.virtual_data_addr & 0xff, (((*apic_ioapic_map.virtual_data_addr) >> 16) & 0xff) + 1);
+
+    // 初始化RTE表项,将所有RTE表项屏蔽
+    for (int i = 0x10; i < 0x40; i += 2)
+    {
+        // 以0x20位起始中断向量号,初始化RTE
+        apic_ioapic_write_rte(i, 0x10020 + ((i - 0x10) >> 1));
+    }
+
+    // 开启键盘中断,中断向量号为0x21,物理模式,投递至BSP处理器
+    apic_ioapic_write_rte(0x12, 0x21);
+    // 不需要手动启动IO APIC,只要初始化了RTE寄存器之后,io apic就会自动启用了。
+    // 而且不是每台电脑都有RCBA寄存器,因此不需要手动启用IO APIC
+    /*
+           // get RCBA address
+           io_out32(0xcf8, 0x8000f8f0);
+           uint x = io_in32(0xcfc);
+           uint *p;
+           printk_color(RED, BLACK, "Get RCBA Address:%#010x\n", x);
+           x = x & 0xffffc000UL;
+           printk_color(RED, BLACK, "Get RCBA Address:%#010x\n", x);
+
+           // get OIC address
+           if (x > 0xfec00000 && x < 0xfee00000)
+           {
+               p = (unsigned int *)(x + 0x31feUL+SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE);
+           }
+
+           // enable IOAPIC
+           x = (*p & 0xffffff00) | 0x100;
+           io_mfence();
+           *p = x;
+           io_mfence();
+           */
 }
 
 /**
@@ -203,6 +252,9 @@ void apic_local_apic_init()
                          "rdmsr  \n\t"
                          : "=a"(eax), "=d"(edx)::"memory");
     kdebug("LVT_PPR=%#010x", eax);
+
+    // 映射Local APIC 寄存器地址
+    mm_map_phys_addr(APIC_LOCAL_APIC_VIRT_BASE_ADDR, 0xfee00000, PAGE_2M_SIZE, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
 }
 
 /**
@@ -211,7 +263,23 @@ void apic_local_apic_init()
  */
 void apic_init()
 {
+    // 初始化中断门, 中断使用第二个ist
+    for (int i = 32; i <= 55; ++i)
+        set_intr_gate(i, 2, interrupt_table[i - 32]);
+
+    // 屏蔽类8259A芯片
+    io_out8(0x21, 0xff);
+    io_out8(0xa1, 0xff);
+    kdebug("8259A Masked.");
+
+    // enable IMCR
+    io_out8(0x22, 0x70);
+    io_out8(0x23, 0x01);
+
+    apic_local_apic_init();
+
     apic_io_apic_init();
+    sti();
 }
 /**
  * @brief 中断服务程序
@@ -221,4 +289,62 @@ void apic_init()
  */
 void do_IRQ(struct pt_regs *rsp, ul number)
 {
+    unsigned char x = io_in8(0x60);
+    printk_color(BLUE, WHITE, "(IRQ:%#04x)\tkey code:%#04x\n", number, x);
+
+    // 向EOI寄存器写入0x00表示结束中断
+    io_mfence();
+    uint *eoi = (uint *)(APIC_LOCAL_APIC_VIRT_BASE_ADDR + LOCAL_APIC_OFFSET_Local_APIC_EOI);
+    *eoi = 0x00;
+    io_mfence();
+}
+
+/**
+ * @brief 读取RTE寄存器
+ * 由于RTE位宽为64位而IO window寄存器只有32位,因此需要两次读取
+ * @param index 索引值
+ * @return ul
+ */
+ul apic_read_ioapic_rte(unsigned char index)
+{
+    // 由于处理器的乱序执行的问题,需要加入内存屏障以保证结果的正确性。
+    ul ret;
+    // 先读取高32bit
+    *apic_ioapic_map.virtual_index_addr = index + 1;
+    io_mfence();
+
+    ret = *apic_ioapic_map.virtual_data_addr;
+    ret <<= 32;
+    io_mfence();
+
+    // 读取低32bit
+    *apic_ioapic_map.virtual_index_addr = index;
+    io_mfence();
+    ret |= *apic_ioapic_map.virtual_data_addr;
+    io_mfence();
+
+    return ret;
+}
+
+/**
+ * @brief 写入RTE寄存器
+ *
+ * @param index 索引值
+ * @param value 要写入的值
+ */
+void apic_ioapic_write_rte(unsigned char index, ul value)
+{
+    // 先写入低32bit
+    *apic_ioapic_map.virtual_index_addr = index;
+    io_mfence();
+
+    *apic_ioapic_map.virtual_data_addr = value & 0xffffffff;
+    io_mfence();
+    // 再写入高32bit
+    value >>= 32;
+    io_mfence();
+    *apic_ioapic_map.virtual_index_addr = index + 1;
+    io_mfence();
+    *apic_ioapic_map.virtual_data_addr = value & 0xffffffff;
+    io_mfence();
 }

+ 32 - 0
kernel/driver/interrupt/apic/apic.h

@@ -3,6 +3,21 @@
 #include "../../../common/asm.h"
 #include"../../../process/ptrace.h"
 #include"../../../exception/irq.h"
+#include "../../../mm/mm.h"
+
+#define APIC_IO_APIC_VIRT_BASE_ADDR SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + IO_APIC_MAPPING_OFFSET
+#define APIC_LOCAL_APIC_VIRT_BASE_ADDR SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + LOCAL_APIC_MAPPING_OFFSET
+
+// ======== local apic 寄存器地址偏移量表 =======
+#define LOCAL_APIC_OFFSET_Local_APIC_ID 0x20
+#define LOCAL_APIC_OFFSET_Local_APIC_Version 0x30
+#define LOCAL_APIC_OFFSET_Local_APIC_TPR 0x80
+#define LOCAL_APIC_OFFSET_Local_APIC_APR 0x90
+#define LOCAL_APIC_OFFSET_Local_APIC_PPR 0xa0
+#define LOCAL_APIC_OFFSET_Local_APIC_EOI 0xb0
+#define LOCAL_APIC_OFFSET_Local_APIC_RRD 0xc0
+#define LOCAL_APIC_OFFSET_Local_APIC_LDR 0xd0
+#define LOCAL_APIC_OFFSET_Local_APIC_DFR 0xe0
 
 struct apic_IO_APIC_map
 {
@@ -24,6 +39,23 @@ struct apic_IO_APIC_map
  */
 void do_IRQ(struct pt_regs* rsp, ul number);
 
+
+/**
+ * @brief 读取RTE寄存器
+ * 
+ * @param index 索引值
+ * @return ul 
+ */
+ul apic_ioapic_read_rte(unsigned char index);
+
+/**
+ * @brief 写入RTE寄存器
+ * 
+ * @param index 索引值
+ * @param value 要写入的值
+ */
+void apic_ioapic_write_rte(unsigned char index, ul value);
+
 /**
  * @brief 初始化apic控制器
  * 

+ 0 - 3
kernel/mm/mm.c

@@ -557,7 +557,6 @@ void mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flag
 
     ul *tmp1;
     // 初始化2M物理页
-    int js = 0;
     for (ul i = 0; i < (length); i += PAGE_2M_SIZE)
     {
         // 计算当前2M物理页对应的pdt的页表项的物理地址
@@ -565,9 +564,7 @@ void mm_map_phys_addr(ul virt_addr_start, ul phys_addr_start, ul length, ul flag
 
         // 页面写穿,禁止缓存
         set_pdt(tmp1, mk_pdt((ul)phys_addr_start + i, flags));
-        ++js;
     }
-    kdebug("js=%d", js);
 
     flush_tlb();
 }

+ 2 - 1
kernel/mm/mm.h

@@ -39,7 +39,8 @@
 #define SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE 0xffff800000000000UL
 #define FRAME_BUFFER_MAPPING_OFFSET 0x3000000UL
 #define ACPI_RSDT_MAPPING_OFFSET 0x7000000UL
-#define IO_APIC_MAPPING_OFFSET 0x8000000UL
+#define IO_APIC_MAPPING_OFFSET 0xfec00000UL
+#define LOCAL_APIC_MAPPING_OFFSET 0xfee00000UL
 // ===== 内存区域属性 =====
 // DMA区域
 #define ZONE_DMA (1 << 0)