我正在为自制操作系统开发网络驱动程序 (RTL8139),但在将值写入 PCI 配置空间寄存器时遇到问题。
我想更改中断线的值(偏移量 0x3c)以获取另一个 IRQ 编号并启用命令寄存器(偏移量 0x04)的总线主机(设置位 2)。
当我读回这些值时,我看到我的值被正确写入。但不是使用新的 IRQ 编号(在我的情况下为 6),而是使用旧值(11)。
DMA 的总线主控器也无法正常工作(我想发送的数据包大小正确(由 IO-Port 设置)但它们没有内容(所有值都只有 0,收发缓冲区在物理内存上并且具有非零值) .在我仔细检查物理地址后,这总是与我的代码一样工作。我需要这个让网络控制器访问我的物理内存,我的接收/收发缓冲区所在的位置。(RTL8139需要总线主控)
我是否必须做其他事情来确认我对 PCI 设备的更改?
作为模拟器,我使用 qemu。
对于读/写,我编写了以下函数:
uint16_t pci_read_word(uint16_t bus, uint16_t slot, uint16_t func, uint16_t offset)
{
uint64_t address;
uint64_t lbus = (uint64_t)bus;
uint64_t lslot = (uint64_t)slot;
uint64_t lfunc = (uint64_t)func;
uint16_t tmp = 0;
address = (uint64_t)((lbus << 16) | (lslot << 11) |
(lfunc << 8) | (offset & 0xfc) | ((uint32_t)0x80000000));
outportl (0xCF8, address);
tmp = (uint16_t)((inportl (0xCFC) >> ((offset & 2) * 8)) & 0xffff);
return (tmp);
}
uint16_t pci_write_word(uint16_t bus, uint16_t slot, uint16_t func, uint16_t offset, uint16_t data)
{
uint64_t address;
uint64_t lbus = (uint64_t)bus;
uint64_t lslot = (uint64_t)slot;
uint64_t lfunc = (uint64_t)func;
uint32_t tmp = 0;
address = (uint64_t)((lbus << 16) | (lslot << 11) |
(lfunc << 8) | (offset & 0xfc) | ((uint32_t)0x80000000));
outportl (0xCF8, address);
tmp = (inportl (0xCFC));
tmp &= ~(0xFFFF << ((offset & 0x2)*8)); // reset the word at the offset
tmp |= data << ((offset & 0x2)*8); // write the data at the offset
outportl (0xCF8, address); // set address again just to be sure
outportl(0xCFC,tmp); // write data
return pci_read_word(bus,slot,func,offset); // read back data;
}
我希望有人能帮助我。