How does an OS find a peripheral's assigned address(es)?

875 views Asked by At

OK, here's what I mean:

Let's say you want to write your own bootable code.

Further, your code is going to be really simple.

So simple, in fact, that it only consists of a single instruction.

Your bootable code is going to write a byte or word or double word or whatever to a register or RAM location on a peripheral device, not main RAM or a CPU register.

How do you find out what address(es) have been assigned to that peripheral memory location by the BIOS / UEFI?

Here's a more concrete example:

My bootable code's first and only instruction will write the number 11H to a register located on the sound card.

If the BIOS / UEFI initialization code did its job properly, that sound card register should be mapped into the CPU's memory space and/or IO space.

I need to find that address to accomplish that write.

How do I find it?

This is what real operating systems must do at some point.

When you open control panel / device manager in Windows, you see all the memory ranges for peripherals listed there.

At some point, Windows must have queried the BIOS /UEFI to find this data.

Again, how is this done?

EDIT:

Here is my attempt at writing this bootable assembly program:

    BITS    16
    ORG     100h
start:
    ;I want to write a byte into a register on the sound card or NIC or 
    ;whatever. So, I'm using a move instruction to accomplish that where X 
    ;is the register's memory mapped or IO mapped address.
    mov X,11h
times 510 - ($ - $$)  db 0
dw 0xaa55

What number do I put in for X? How do I find the address of this peripheral's register?

1

There are 1 answers

0
prl On

If you want to do this with one instruction, you can just get the address for the device from the Windows device manager. But if you want to do it the "proper" way, you need to scan the PCI bus to find the device you want to program, and then read the Base Address Registers (BARs) of the device to find its MMIO ranges. This is what Windows does; it doesn't query the BIOS.

To find the device that you want to access, scan the PCI bus looking for the device. Devices are addressed on the PCI bus by their "BDF" (short for Bus/ Device/ Function). Devices are identified by a Vendor ID and a Device ID assigned by the vendor.

Read offset 0 and 2 of each BDF to get the Vendor ID and Device ID. When you have found the device you want to program, read the correct 32-bit BAR value at an offset between 10h and 24h. You need to know which BAR contains the register you want to program, which is specific to the device you are using.

This article describes how to access PCI config space and has sample code in C showing how to scan the PCI bus. http://wiki.osdev.org/PCI