理解IDE驱动初始化的问题

问题描述 投票:0回答:1

在开发 ATA PIO 驱动程序时,我遵循了以下教程:PCI IDE 控制器ATA PIO 模式。我成功地在 QEMU 中为 i386 实现了一个简单、最小的驱动程序。然而,我决定重构它以使驱动程序更加健壮。

现在,我很难理解驱动程序的正确初始化过程。我之前的实现对主 ATA 端口进行了硬编码,并且仅支持主驱动器。然而,OSDev wiki 建议动态检测端口地址,而不是依赖这些硬编码的兼容性映射值。

我已经编写了一个与 OSDev wiki 上提供的函数类似的函数(请参阅下面的代码),但我的版本不包含按位运算,因为我不完全理解它。有人可以解释一下这个操作是做什么的以及为什么它很重要吗?

来自 OSDev 的示例代码:

void ide_initialize(unsigned int BAR0, unsigned int BAR1, unsigned int BAR2, unsigned int BAR3, unsigned int BAR4) {

   int j, k, count = 0;

   // 1- Detect I/O Ports which interface IDE Controller:
   channels[ATA_PRIMARY  ].base  = (BAR0 & 0xFFFFFFFC) + 0x1F0 * (!BAR0);
   channels[ATA_PRIMARY  ].ctrl  = (BAR1 & 0xFFFFFFFC) + 0x3F6 * (!BAR1);
   channels[ATA_SECONDARY].base  = (BAR2 & 0xFFFFFFFC) + 0x170 * (!BAR2);
   channels[ATA_SECONDARY].ctrl  = (BAR3 & 0xFFFFFFFC) + 0x376 * (!BAR3);
   channels[ATA_PRIMARY  ].bmide = (BAR4 & 0xFFFFFFFC) + 0; // Bus Master IDE
   channels[ATA_SECONDARY].bmide = (BAR4 & 0xFFFFFFFC) + 8; // Bus Master IDE

此代码中按位运算 (

& 0xFFFFFFFC
) 的目的是什么?为什么需要正确初始化?另外,
(!BAR0)
乘法在这种情况下是如何工作的?

我试图了解处理器映射 I/O 的工作原理以及编程 I/O (PIO) 和直接内存访问 (DMA) 之间的差异。我还想了解驱动程序如何通过 PCI 检测正确的 I/O 端口。

x86 ide driver pci ata
1个回答
0
投票

您应该查看 PCI 规范的副本。每个BAR的低位标识它是内存还是I/O空间,以及内存空间的一些其他信息。您需要删除它们才能获得实际的 I/O 端口号。 !BAR0 是提供默认值的一种过于聪明的方式。如果 BAR0 为 0,则该值为 0x1F0。

BIOS 在启动时分配内存和 I/O 空间。 通过规范中描述的相当巧妙的方案,BAR 可以由 BIOS 用来确定设备需要多少内存和 I/O 空间。 然后它会分割可用空间并分配地址范围。

当您的系统有操作系统时,内核会扫描 PCI 总线(以及 DSDT 等 BIOS 表)以确定存在哪些设备。 然后它找出需要哪些驱动程序,从 BAR 寄存器读取 BIOS 分配,并告诉驱动程序分配了哪些寄存器。 如果您正在做一个自制系统,那么由您决定如何处理这个问题,但对于 PCI 设备,您需要的信息位于那些 BAR 寄存器中。

I/O端口是原始8086的遗留物。地址空间极其有限,访问速度很慢,因此21世纪的设备不使用I/O端口。 如今大多数设备都使用内存映射,将设备映射到虚拟内存并直接访问。 这就是 BAR4 的用途。 上面的代码提到了“总线主控”——设备本身使用 DMA 直接传输块。 这必须由驱动程序通过写入寄存器进行配置,但传输本身无需 CPU 即可进行。

© www.soinside.com 2019 - 2024. All rights reserved.