Page 1 of 1

Outb?

Posted: Thu Nov 13, 2008 2:36 pm
by samoz
Hey guys, I've been working through some different tutorials and trying to actually understand what they are doing, rather than just copying them.

One thing I don't understand is the outb instruction that is in the James Molloy tutorials.

I looked in the Intel manuals at the Out(couldn't find Outb) command, but didn't really understand why/how you would use this command. Is there any more documentation or could anyone explain it?

Thanks!

Re: Outb?

Posted: Thu Nov 13, 2008 2:44 pm
by CodeCat
First of all, you know the mov instruction? It moves data around, normally from register to memory or back. The out instruction does exactly the same, except that it moves data from a register to I/O memory rather than to regular memory. Similarly, the in instruction moves data from I/O memory to a register. I/O memory has its own address space, using 16 bit addresses. This is distinct from regular memory, which could have 32 bit addresses or more. Normally, devices map (parts of) their memory to I/O memory space, so that the processor can access them in this way. Reading and writing to and from these I/O memory areas is how a device driver normally communicates with the device.

Re: Outb?

Posted: Thu Nov 13, 2008 6:34 pm
by bewing
I would phrase it slightly differently. A x86 CPU chip has more than one bus attached to it.
It has a memory bus, as CodeCat says.
It also has something called an IO Port Bus.
The IO Port Bus uses 16 bit addressing, and 8 bits of data, per access.
The ASM instructions IN, OUT, INS, and OUTS send or receive data over this IO Port bus. (Sometimes, there are other ways to access it, too.)

The outb() function that you asked about is a C-language inline "asm" macro that uses the ASM OUT instruction to send one byte out over the IO Port Bus from the CPU to a device. You can't code an x86 OS without using the ASM IN and OUT opcodes, so the outb() function is generically used on all OSes that are coded in C or a C derivative.

Re: Outb?

Posted: Thu Nov 13, 2008 7:44 pm
by CodeCat
Now I have a question. If data is transferred 8 bits at a time, then how come you can still do out dx, ax using a 16 bit register as value?

Re: Outb?

Posted: Thu Nov 13, 2008 9:58 pm
by pcmattman
CodeCat: Intel Manuals volume 1 in the least should cover the IO port bus, if not, try 3A or 3B.

Re: Outb?

Posted: Fri Nov 14, 2008 12:21 am
by bewing
It is covered in the manuals, but the ramifications are not.

The answer to the question is that if you do a 16 bit OUT operation, the CPU automatically breaks it into two 8 bit operations, and IIRC sends the low byte over the IO Port bus first, then the high byte second, to the same IO Port. This is extended further to 32bit OUT operations.

The ramification is, almost all motherboards automatically insert a long pause between OUTs, if you try to do multiple OUTs to the same IO port, sequentially. This can be very very bad for IO Port Bus throughput. So you want to avoid doing this if at all possible. There are many devices (ATA controllers, for example) that require it, however.

Re: Outb?

Posted: Fri Nov 14, 2008 3:20 am
by Combuster
Hmm, my copy of the manuals suggests otherwise:
The Big Book of Patterns wrote:Any two consecutive 8-bit ports can be treated as a 16-bit port, and any four consecutive
ports can be a 32-bit port. In this manner, the processor can transfer 8, 16, or
32 bits to or from a device in the I/O address space. Like words in memory, 16-bit
ports should be aligned to even addresses (0, 2, 4, ...) so that all 16 bits can be
transferred in a single bus cycle.
Likewise, 32-bit ports should be aligned to
addresses that are multiples of four (0, 4, 8, ...). The processor supports data transfers
to unaligned ports, but there is a performance penalty because one or more
extra bus cycle must be used.

Re: Outb?

Posted: Fri Nov 14, 2008 5:55 am
by CodeCat
bewing wrote:The answer to the question is that if you do a 16 bit OUT operation, the CPU automatically breaks it into two 8 bit operations, and IIRC sends the low byte over the IO Port bus first, then the high byte second, to the same IO Port. This is extended further to 32bit OUT operations.
Ouch. Ok now it's a lot clearer, but I had never considered I/O ports as stream-like entities. I always figured they were just like memory locations with different addresses, so I originally thought that writing a word to say port 0x100 it would write a byte to that and another byte to 0x101 like it would for memory. I take it that the true situation means you should never transfer more than one byte at a time, unless the device specifically says it can handle a larger amount?

Re: Outb?

Posted: Fri Nov 14, 2008 8:51 am
by jal
CodeCat wrote:
bewing wrote:The answer to the question is that if you do a 16 bit OUT operation, the CPU automatically breaks it into two 8 bit operations, and IIRC sends the low byte over the IO Port bus first, then the high byte second, to the same IO Port. This is extended further to 32bit OUT operations.
Ouch. Ok now it's a lot clearer, but I had never considered I/O ports as stream-like entities. I always figured they were just like memory locations with different addresses, so I originally thought that writing a word to say port 0x100 it would write a byte to that and another byte to 0x101 like it would for memory. I take it that the true situation means you should never transfer more than one byte at a time, unless the device specifically says it can handle a larger amount?
No no, bewing is really wrong here, and your first assumption is right. A 16 bit out actually does write to two consecutive addresses. I/O address space is just like normal memory in this respect.


JAL

Re: Outb?

Posted: Fri Nov 14, 2008 5:46 pm
by Combuster
The manuals say that an aligned 16-bit out will result in a single bus cycle. That means that the data will be sent in one piece, and also, that the devices must be notified of the size of the write.

So a device will see either a single 16-bit write, or two 8-bit write, depending on whether you do a single word or two byte outs (and the same will hold for reads). That means that for devices with "normal" memory semantics, a 16-bit read will result in those 16 bits in the I/O memory, and writes will set those bits.
Even for those devices you assume they are, you have atomicity problems: if you do two byte reads, the device can modify the data inbetween and you'll get a possibly wrong result, but not if you do a single 16 (or even 32-bit) read.
And then there are the much more common devices that don't have a memory-like I/O space.
Consider the VGA and its clones. Normally you're supposed to do two byte outs to select a register, and then load that register. People commonly do word outs to write both in a single streak. But some (bad) clones didn't like that. Instead they would send the second byte to a register before they realized that the first byte specified a different one.
Most datasheets for a pc's stock peripherals show one or more address line and a write line, but not a width line, so if you word out to those things, it'd consequently only take the first byte into account since it expects only bytes. A recent thread suggested that the USB controller was sensitive to write sizes as well, returning all ones on a mismatched read size (which in turn suggests an aborted PCI operation).

Hence the paranoia about read and write sizes - the have mattered in the past, and will most likely do in the future. As a rule you should therefore never use a I/O access of the wrong size since they can have undefined effects.