While developing an ATA PIO driver, I followed these tutorials: PCI IDE Controller and ATA PIO Mode. I successfully implemented a simple, minimal driver in QEMU for i386. However, I decided to refactor it to make the driver more robust.
Now, I'm having difficulty understanding the proper initialization process for the driver. My previous implementation hardcoded the primary ATA ports and only supported the master drive. The OSDev wiki, however, suggests dynamically detecting port addresses instead of relying on these hardcoded, compatibility-mapped values.
I have written a similar function to the one provided on the OSDev wiki (see code below), but my version does not include the bitwise operation because I don't fully understand it. Could someone explain what this operation is doing and why it is important?
Example code from 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
What is the purpose of the bitwise operation (& 0xFFFFFFFC) in this code, and why is it necessary for proper initialization? Additionally, how does the (!BAR0) multiplication work in this context?
I was trying to understand how processor-mapped I/O works and the differences between Programmed I/O (PIO) and Direct Memory Access (DMA). I would also like an explanation of how a driver detects the correct I/O ports through PCI.