0

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.

0

1 Answer 1

0

You should check out a copy of the PCI spec. The lower bits of each BAR identify whether it is memory or I/O space, plus some other information for memory spaces. If BAR0 is an I/O space at 0x1F0, the register will actually read 0x1F1. You need to remove the lower bits to get the actual I/O port number. The !BAR0 is an overly clever way of providing a default. If BAR0 is 0, then the value will be 0x1F0.

The BIOS allocates the memory and I/O space at boot time. The BARs, through a fairly clever scheme described in the specs, can be used by the BIOS to determine how much memory and I/O space the device wants. It then chops up the available space and assigns the address ranges.

When your system has an operating system, the kernel scans the PCI bus (and the BIOS tables like the DSDT) to determine what devices are present. It then figures out which drivers are needed, reads the BIOS assignments from the BAR registers, and tells the driver what registers were assigned. If you're doing a homemade system, then it's up to you to decide how to handle this, but for PCI devices, the information you need is in those BAR registers.

I/O ports are a leftover from the original 8086. The address space is extremely limited and access is slow, so I/O ports are not used by 21st Century devices. Most devices today use memory-mapping, where the device is mapped into virtual memory and accessed directly. That's what your BAR4 is for. The code above mentions "bus master" -- that's where the device itself uses DMA to transfer blocks directly. That has to be configured by the driver by writing registers, but the transfer itself happens without the CPU.

Sign up to request clarification or add additional context in comments.

3 Comments

Last paragraph starts with two arguable statements. 1) I/O ports are a leftover from the original 8086: Not only x86 uses different pins for IO/MEM accesses, SPARC, IIRC, does the same; 2) I/O ports are not used by 21st Century devices: This is simply not true, there are a lot of modern devices that are using IO ports (on PCI bus), mostly they are UARTs.
(1) SPARC got the idea from x86. (2) UARTs are not 21st Century devices. They were old when Windows was invented.
(1) Proof? No need, they both are not the first ones with that idea, so again, your statement is inaccurate. (2) You haven't clarified you meant invented in 21st Centure, again, simply wrong statement. P.S. I trully like how high-rated people on SO behave, never accepting their inaccuracies or being wrong. :-(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.