mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 22:36:48 +00:00
  实现了具有优秀架构设计的新的内存管理模块,对内核空间和用户空间的内存映射、分配、释放、管理等操作进行了封装,使得内核开发者可以更加方便地进行内存管理。   内存管理模块主要由以下类型的组件组成: - **硬件抽象层(MemoryManagementArch)** - 提供对具体处理器架构的抽象,使得内存管理模块可以在不同的处理器架构上运行 - **页面映射器(PageMapper)**- 提供对虚拟地址和物理地址的映射,以及页表的创建、填写、销毁、权限管理等操作。分为两种类型:内核页表映射器(KernelMapper)和用户页表映射器(位于具体的用户地址空间结构中) - **页面刷新器(PageFlusher)** - 提供对页表的刷新操作(整表刷新、单页刷新、跨核心刷新) - **页帧分配器(FrameAllocator)** - 提供对页帧的分配、释放、管理等操作。具体来说,包括BumpAllocator、BuddyAllocator - **小对象分配器** - 提供对小内存对象的分配、释放、管理等操作。指的是内核里面的SlabAllocator (SlabAllocator的实现目前还没有完成) - **MMIO空间管理器** - 提供对MMIO地址空间的分配、管理操作。(目前这个模块待进一步重构) - **用户地址空间管理机制** - 提供对用户地址空间的管理。 - VMA机制 - 提供对用户地址空间的管理,包括VMA的创建、销毁、权限管理等操作 - 用户映射管理 - 与VMA机制共同作用,管理用户地址空间的映射 - **系统调用层** - 提供对用户空间的内存管理系统调用,包括mmap、munmap、mprotect、mremap等 - **C接口兼容层** - 提供对原有的C代码的接口,是的C代码能够正常运行。 除上面的新增内容以外,其它的更改内容: - 新增二进制加载器,以及elf的解析器 - 解决由于local_irq_save、local_irq_restore函数的汇编不规范导致影响栈行为的bug。 - 解决local_irq_save未关中断的错误。 - 修复sys_gettimeofday对timezone参数的处理的bug --------- Co-authored-by: kong <kongweichao@dragonos.org>
340 lines
11 KiB
C
340 lines
11 KiB
C
#include "msi.h"
|
||
#include "pci.h"
|
||
#include <common/errno.h>
|
||
#include <mm/mmio.h>
|
||
|
||
/**
|
||
* @brief 生成msi消息
|
||
*
|
||
* @param msi_desc msi描述符
|
||
* @return struct msi_msg_t* msi消息指针(在描述符内)
|
||
*/
|
||
extern struct msi_msg_t *msi_arch_get_msg(struct msi_desc_t *msi_desc);
|
||
|
||
/**
|
||
* @brief 读取msix的capability list
|
||
*
|
||
* @param msi_desc msi描述符
|
||
* @param cap_off capability list的offset
|
||
* @return struct pci_msix_cap_t 对应的capability list
|
||
*/
|
||
static __always_inline struct pci_msix_cap_t __msi_read_msix_cap_list(struct msi_desc_t *msi_desc, uint32_t cap_off)
|
||
{
|
||
struct pci_msix_cap_t cap_list = {0};
|
||
uint32_t dw0;
|
||
dw0 = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off);
|
||
io_lfence();
|
||
cap_list.cap_id = dw0 & 0xff;
|
||
cap_list.next_off = (dw0 >> 8) & 0xff;
|
||
cap_list.msg_ctrl = (dw0 >> 16) & 0xffff;
|
||
|
||
cap_list.dword1 =
|
||
pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x4);
|
||
cap_list.dword2 =
|
||
pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x8);
|
||
return cap_list;
|
||
}
|
||
|
||
static __always_inline struct pci_msi_cap_t __msi_read_cap_list(struct msi_desc_t *msi_desc, uint32_t cap_off)
|
||
{
|
||
struct pci_msi_cap_t cap_list = {0};
|
||
uint32_t dw0;
|
||
dw0 = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off);
|
||
cap_list.cap_id = dw0 & 0xff;
|
||
cap_list.next_off = (dw0 >> 8) & 0xff;
|
||
cap_list.msg_ctrl = (dw0 >> 16) & 0xffff;
|
||
|
||
cap_list.msg_addr_lo =
|
||
pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x4);
|
||
uint16_t msg_data_off = 0xc;
|
||
if (cap_list.msg_ctrl & (1 << 7)) // 64位
|
||
{
|
||
cap_list.msg_addr_hi =
|
||
pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x8);
|
||
}
|
||
else
|
||
{
|
||
cap_list.msg_addr_hi = 0;
|
||
msg_data_off = 0x8;
|
||
}
|
||
|
||
cap_list.msg_data = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func,
|
||
cap_off + msg_data_off) &
|
||
0xffff;
|
||
|
||
cap_list.mask =
|
||
pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x10);
|
||
cap_list.pending =
|
||
pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x14);
|
||
|
||
return cap_list;
|
||
}
|
||
|
||
/**
|
||
* @brief 映射设备的msix表 //MSIX表不再单独映射(To do)
|
||
*
|
||
* @param pci_dev pci设备信息结构体
|
||
* @param msix_cap msix capability list的结构体
|
||
* @return int 错误码
|
||
*/
|
||
static __always_inline int __msix_map_table(struct pci_device_structure_header_t *pci_dev,
|
||
struct pci_msix_cap_t *msix_cap)
|
||
{
|
||
// 计算bar寄存器的offset
|
||
uint32_t bar_off = 0x10 + 4 * (msix_cap->dword1 & 0x7);
|
||
|
||
// msix table相对于bar寄存器中存储的地址的offset
|
||
pci_dev->msix_offset = msix_cap->dword1 & (~0x7);
|
||
pci_dev->msix_table_size = (msix_cap->msg_ctrl & 0x7ff) + 1;
|
||
pci_dev->msix_mmio_size = pci_dev->msix_table_size * 16 + pci_dev->msix_offset;
|
||
|
||
// 申请mmio空间
|
||
mmio_create(pci_dev->msix_mmio_size, VM_IO | VM_DONTCOPY, &pci_dev->msix_mmio_vaddr, &pci_dev->msix_mmio_size);
|
||
pci_dev->msix_mmio_vaddr &= (~0xf);
|
||
uint32_t bar = pci_read_config(pci_dev->bus, pci_dev->device, pci_dev->func, bar_off);
|
||
// kdebug("pci_dev->msix_mmio_vaddr=%#018lx, bar=%#010lx, table offset=%#010lx, table_size=%#010lx, mmio_size=%d",
|
||
// pci_dev->msix_mmio_vaddr, bar, pci_dev->msix_offset, pci_dev->msix_table_size, pci_dev->msix_mmio_size);
|
||
|
||
// 将msix table映射到页表
|
||
rs_map_phys(pci_dev->msix_mmio_vaddr, bar, pci_dev->msix_mmio_size, PAGE_KERNEL_PAGE);
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 将msi_desc中的数据填写到msix表的指定表项处
|
||
*
|
||
* @param pci_dev pci设备结构体
|
||
* @param msi_desc msi描述符
|
||
*/
|
||
static __always_inline void __msix_set_entry(struct msi_desc_t *msi_desc)
|
||
{
|
||
uint64_t *ptr =
|
||
(uint64_t *)(msi_desc->pci_dev->msix_mmio_vaddr + msi_desc->pci_dev->msix_offset + msi_desc->msi_index * 16);
|
||
*ptr = ((uint64_t)(msi_desc->msg.address_hi) << 32) | (msi_desc->msg.address_lo);
|
||
io_mfence();
|
||
++ptr;
|
||
io_mfence();
|
||
*ptr = ((uint64_t)(msi_desc->msg.vector_control) << 32) | (msi_desc->msg.data);
|
||
io_mfence();
|
||
}
|
||
|
||
/**
|
||
* @brief 清空设备的msix table的指定表项
|
||
*
|
||
* @param pci_dev pci设备
|
||
* @param msi_index 表项号
|
||
*/
|
||
static __always_inline void __msix_clear_entry(struct pci_device_structure_header_t *pci_dev, uint16_t msi_index)
|
||
{
|
||
uint64_t *ptr = (uint64_t *)(pci_dev->msix_mmio_vaddr + pci_dev->msix_offset + msi_index * 16);
|
||
*ptr = 0;
|
||
++ptr;
|
||
*ptr = 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 启用 Message Signaled Interrupts
|
||
*
|
||
* @param header 设备header
|
||
* @param vector 中断向量号
|
||
* @param processor 要投递到的处理器
|
||
* @param edge_trigger 是否边缘触发
|
||
* @param assert 是否高电平触发
|
||
*
|
||
* @return 返回码
|
||
*/
|
||
int pci_enable_msi(struct msi_desc_t *msi_desc)
|
||
{
|
||
struct pci_device_structure_header_t *ptr = msi_desc->pci_dev;
|
||
uint32_t cap_ptr;
|
||
uint32_t tmp;
|
||
uint16_t message_control;
|
||
uint64_t message_addr;
|
||
|
||
// 先尝试获取msi-x,若不存在,则获取msi capability
|
||
if (msi_desc->pci.msi_attribute.is_msix)
|
||
{
|
||
cap_ptr = pci_enumerate_capability_list(ptr, 0x11);
|
||
if (((int32_t)cap_ptr) < 0)
|
||
{
|
||
cap_ptr = pci_enumerate_capability_list(ptr, 0x05);
|
||
if (((int32_t)cap_ptr) < 0)
|
||
return -ENOSYS;
|
||
msi_desc->pci.msi_attribute.is_msix = 0;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
cap_ptr = pci_enumerate_capability_list(ptr, 0x05);
|
||
if (((int32_t)cap_ptr) < 0)
|
||
return -ENOSYS;
|
||
msi_desc->pci.msi_attribute.is_msix = 0;
|
||
}
|
||
// 获取msi消息
|
||
msi_arch_get_msg(msi_desc);
|
||
|
||
if (msi_desc->pci.msi_attribute.is_msix) // MSI-X
|
||
{
|
||
kdebug("is msix");
|
||
// 读取msix的信息
|
||
struct pci_msix_cap_t cap = __msi_read_msix_cap_list(msi_desc, cap_ptr);
|
||
// 映射msix table
|
||
__msix_map_table(msi_desc->pci_dev, &cap);
|
||
io_mfence();
|
||
// 设置msix的中断
|
||
__msix_set_entry(msi_desc);
|
||
io_mfence();
|
||
|
||
// todo: disable intx
|
||
// 使能msi-x
|
||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||
tmp |= (1U << 31);
|
||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
|
||
}
|
||
else
|
||
{
|
||
kdebug("is msi");
|
||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||
message_control = (tmp >> 16) & 0xffff;
|
||
|
||
// 写入message address
|
||
message_addr = ((((uint64_t)msi_desc->msg.address_hi) << 32) | msi_desc->msg.address_lo); // 获取message address
|
||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x4, (uint32_t)(message_addr & 0xffffffff));
|
||
|
||
if (message_control & (1 << 7)) // 64位
|
||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8,
|
||
(uint32_t)((message_addr >> 32) & 0xffffffff));
|
||
|
||
// 写入message data
|
||
|
||
tmp = msi_desc->msg.data;
|
||
if (message_control & (1 << 7)) // 64位
|
||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0xc, tmp);
|
||
else
|
||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8, tmp);
|
||
|
||
// 使能msi
|
||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||
tmp |= (1 << 16);
|
||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* @brief 在已配置好msi寄存器的设备上,使能msi
|
||
*
|
||
* @param header 设备头部
|
||
* @return int 返回码
|
||
*/
|
||
int pci_start_msi(void *header)
|
||
{
|
||
struct pci_device_structure_header_t *ptr = (struct pci_device_structure_header_t *)header;
|
||
uint32_t cap_ptr;
|
||
uint32_t tmp;
|
||
|
||
switch (ptr->HeaderType)
|
||
{
|
||
case 0x00: // general device
|
||
if (!(ptr->Status & 0x10))
|
||
return -ENOSYS;
|
||
cap_ptr = ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer;
|
||
|
||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||
|
||
if (tmp & 0xff != 0x5)
|
||
return -ENOSYS;
|
||
|
||
// 使能msi
|
||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||
tmp |= (1 << 16);
|
||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
|
||
|
||
break;
|
||
|
||
case 0x01: // pci to pci bridge
|
||
if (!(ptr->Status & 0x10))
|
||
return -ENOSYS;
|
||
cap_ptr = ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer;
|
||
|
||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||
|
||
if (tmp & 0xff != 0x5)
|
||
return -ENOSYS;
|
||
|
||
// 使能msi
|
||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||
tmp |= (1 << 16);
|
||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
|
||
|
||
break;
|
||
case 0x02: // pci to card bus bridge
|
||
return -ENOSYS;
|
||
break;
|
||
|
||
default: // 不应该到达这里
|
||
return -EINVAL;
|
||
break;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
/**
|
||
* @brief 禁用指定设备的msi
|
||
*
|
||
* @param header pci header
|
||
* @return int
|
||
*/
|
||
int pci_disable_msi(void *header)
|
||
{
|
||
struct pci_device_structure_header_t *ptr = (struct pci_device_structure_header_t *)header;
|
||
uint32_t cap_ptr;
|
||
uint32_t tmp;
|
||
|
||
switch (ptr->HeaderType)
|
||
{
|
||
case 0x00: // general device
|
||
if (!(ptr->Status & 0x10))
|
||
return -ENOSYS;
|
||
cap_ptr = ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer;
|
||
|
||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||
|
||
if (tmp & 0xff != 0x5)
|
||
return -ENOSYS;
|
||
|
||
// 禁用msi
|
||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||
tmp &= (~(1 << 16));
|
||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
|
||
|
||
break;
|
||
|
||
case 0x01: // pci to pci bridge
|
||
if (!(ptr->Status & 0x10))
|
||
return -ENOSYS;
|
||
cap_ptr = ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer;
|
||
|
||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||
|
||
if (tmp & 0xff != 0x5)
|
||
return -ENOSYS;
|
||
|
||
// 禁用msi
|
||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||
tmp &= (~(1 << 16));
|
||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
|
||
|
||
break;
|
||
case 0x02: // pci to card bus bridge
|
||
return -ENOSYS;
|
||
break;
|
||
|
||
default: // 不应该到达这里
|
||
return -EINVAL;
|
||
break;
|
||
}
|
||
|
||
return 0;
|
||
} |