|
@@ -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();
|
|
|
}
|