From ee49849158706d2f54f1358facca4282895b2162 Mon Sep 17 00:00:00 2001 From: fslongjin Date: Sun, 13 Mar 2022 21:09:38 +0800 Subject: [PATCH] =?UTF-8?q?:new:=20=E5=AE=8C=E6=88=90=E4=BA=86=E7=AE=80?= =?UTF-8?q?=E5=8D=95=E7=9A=84APIC=E4=B8=AD=E6=96=AD=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kernel/driver/acpi/acpi.c | 23 +---- kernel/driver/acpi/acpi.h | 2 +- kernel/driver/interrupt/apic/apic.c | 152 +++++++++++++++++++++++++--- kernel/driver/interrupt/apic/apic.h | 32 ++++++ kernel/mm/mm.c | 3 - kernel/mm/mm.h | 3 +- 6 files changed, 177 insertions(+), 38 deletions(-) diff --git a/kernel/driver/acpi/acpi.c b/kernel/driver/acpi/acpi.c index 2132e559..a3e49abf 100644 --- a/kernel/driver/acpi/acpi.c +++ b/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; } diff --git a/kernel/driver/acpi/acpi.h b/kernel/driver/acpi/acpi.h index 11e62be1..2f689dc5 100644 --- a/kernel/driver/acpi/acpi.h +++ b/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 diff --git a/kernel/driver/interrupt/apic/apic.c b/kernel/driver/interrupt/apic/apic.c index b4d703fd..2dd9d66e 100644 --- a/kernel/driver/interrupt/apic/apic.c +++ b/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(); } \ No newline at end of file diff --git a/kernel/driver/interrupt/apic/apic.h b/kernel/driver/interrupt/apic/apic.h index 0ee39727..b8743eed 100644 --- a/kernel/driver/interrupt/apic/apic.h +++ b/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控制器 * diff --git a/kernel/mm/mm.c b/kernel/mm/mm.c index 7862ea32..d0e5bcc4 100644 --- a/kernel/mm/mm.c +++ b/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(); } \ No newline at end of file diff --git a/kernel/mm/mm.h b/kernel/mm/mm.h index a3354aa6..1eae7a59 100644 --- a/kernel/mm/mm.h +++ b/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)