mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
🆕 完成了简单的APIC中断处理功能
This commit is contained in:
parent
9cb628c3b9
commit
ee49849158
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
@ -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控制器
|
||||
*
|
||||
|
@ -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();
|
||||
}
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user