Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Question About x86 I/O Port Addresses and IN/OUT Instructions

As I know it, this is a simplified view of PC bus system (it excludes the bridges I'm aware of it).

As in this image: x86 Bus Simplified View

and we have an address space of 65536 bytes (0000-FFFF) in modern x86 CPUs as far as I know. These are I/O addresses. In x86 IN and OUT instructions are used to communicate with devices through I/O ports.

Considering PCs (x86 cpus) the following are my questions:

  1. Can I add a device to this I/O bus without using PCI or any other bus? I mean a direct communication with IN/OUT. If yes how are I/O addresses assigned? Don't they conflict?

  2. If my CPU supports PCI and I²C (yes some do!), how does the CPU differentiate between their I/O addresses? How does it know that an I/O address belongs to PCI or I²C.

(btw I don't know if I²C addresses are just logical and not about I/O ports but this is another question I also need the answer of)

like image 715
Tom Milberg Avatar asked Jun 18 '19 20:06

Tom Milberg


People also ask

What does out do in assembly language?

The outs instruction transfers a string from the memory byte or word pointed to by the ES:source index to the port addressed in the DX register. Load the desired port number into the DX register and the desired source address into the SI or ESI index register before executing the outs instruction.

What assembly language does Intel use?

Assembly programming targeted specifically towards Intel 32 bit processors is known as x86 assembly. It should be noted that in addition to Intel processors, there may be other processors that use the same instruction set, AMD for instance.


1 Answers

1) Can I add a device to this I/O bus without using PCI or any other bus?

In theory; yes. However, for modern systems there's no shared/common bus (it's "point to point links" now); and memory controllers and PCI hosts are all built into the same chip as the CPUs which means that (unless you're an employee of a CPU vendor like Intel) you'll have to deal with high-speed serial links (Quick-path, Hyper-transport, PCIe or DMI) which aren't cheap or easy to interface to (in other words, it's not like the 1980s where you have a nice and slow ISA bus to hook into).

If yes how are I/O addresses assigned? Don't they conflict?

Legacy devices use fixed IO ports that were assigned by history/compatibility. Everything else is assigned dynamically by a kind of "IO port range allocator" (built into the firmware and/or operating system) that configures BARs ("Base Address Range" registers) in PCI configuration space. There were some (now deprecated/non-existent) alternatives - manually assigned by physical jumpers or dip switches on ISA cards, an ISA "plug and play" spec that mostly got replaced by PCI before many devices supported it, and features that existed in other kinds of buses (MCA and EISA) for dynamic resource assignment. Of course most modern devices don't use IO ports at all (and use memory mapped registers instead).

2-) If my CPU supports PCI and I²C (yes some do!), how does the cpu differentiate between their I/O addresses? How does it know that an I/O address belongs to PCI or I²C.

For I²C, there'd probably be a pair of registers somewhere (either in the IO port address space or the physical address space) for sending and receiving a byte to/from the I²C bus. Everything on the I²C bus will be accessed through those 2 registers, and nothing on the I²C bus will have access to anything that isn't on the I²C bus (including not having any access to any IO ports and not having any access to any physical addresses).

Mostly (like ethernet, video, USB, ...) you have a controller (that has registers the CPU can access directly) that controls something that the CPU can't access directly (LAN, signals to the monitor, USB devices plugged into a USB bus, ...).

(Simplified) Example

Let's assume that (because of an out dx,al instruction) the CPU sends a message on a shared bus or a link that says "command = WRITE, space = IO port space, address = 0x1234, size = 1 byte, data = 0x56". This message might be intercepted by a PCI host controller, which looks at the details (which address in which address space) and decides to forward the message to an "PCI to LPC bridge" device on a PCI bus. When the "PCI to LPC bridge" gets the message it might look at the details (which address in which address space) and realize it corresponds to an I²C bus controller and forward it to the I²C bus controller. The I²C bus controller might decode the message and send the byte 0x56 (from the "data" part of the message) on the I²C bus. Then, maybe a device that's listening on the I²C bus sees that 0x56 byte and responds by sending the byte 0x78 back over the I²C bus to the I²C bus controller, where the controller stores the value 0x78 in an internal buffer register.

Next; (because of an in al,dx instruction) the CPU might send another message that says "command = READ, space = IO port space, address = 0x1234, size = 1 byte". This message would follow the same path as the previous one (because the address and address space is the same) and end up at the I²C bus controller. The I²C bus controller might decode the message and realize the message is asking to read from the I²C bus controller's internal buffer register (which holds the value 0x78 from before); so the I²C bus controller sends back the message "command = READ_REPLY, space = IO port space, address = 0x1234, size = 1 byte, data = 0x78". This reply message would go back to the CPU (using the same path again, but in the opposite direction - e.g. to PCI to LPC bridge, then to PCI host controller, then to CPU). When the CPU gets the reply it can complete the original instruction that caused it (e.g. set al to the value that was in the "READ_reply" message to complete the in al,dx instruction).

The point here is that CPU can't send anything directly to a device on the I²C bus (a CPU can only talk to the I²C bus controller); and no device on the I²C bus can send anything directly to the CPU either (they can only talk to the I²C bus controller too). Nothing on the I²C bus needs to know anything about IO ports; and nothing on the CPU's bus/links need to know anything about bytes on the I²C bus.

Also; the CPU is just sending and receiving messages. It has no idea what happens to them after they're sent, and doesn't know how (e.g.) a "command = READ" message will be forwarded by what to where, and doesn't know which device will send back a "command = READ_REPLY" message. The routing mostly depends on logic at each step in the path that the message takes. For example, the PCI host controller might be configured to forward all messages for IO port accesses in the range 0x0000 to 0x2000 to a PCI bus, and the PCI to LPC bridge might be configured to forward all messages for IO port accesses in the range 0x1234 to 0x1235 to the I²C bus controller.

like image 165
Brendan Avatar answered Nov 15 '22 20:11

Brendan