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

This commit is contained in:
fslongjin 2022-03-13 21:09:38 +08:00
parent 9cb628c3b9
commit ee49849158
6 changed files with 177 additions and 38 deletions

View File

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

View File

@ -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

View File

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

View File

@ -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控制器
*

View File

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

View File

@ -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)