Low level I/O access using outb and inb

20.4k views Asked by At

i'm having hard time trying to understand how interrupts work.

the code below initialize the Programmable Interrupt Controller

  #define PIC0_CTRL 0x20    /* Master PIC control register address. */
  #define PIC0_DATA 0x21    /* Master PIC data register address. */

  /* Mask all interrupts*/
  outb (PIC0_DATA, 0xff);

  /* Initialize master. */
  outb (PIC0_CTRL, 0x11); /* ICW1: single mode, edge triggered, expect ICW4. */
  outb (PIC0_DATA, 0x20); /* ICW2: line IR0...7 -> irq 0x20...0x27. */
  outb (PIC0_DATA, 0x04); /* ICW3: slave PIC on line IR2. */
  outb (PIC0_DATA, 0x01); /* ICW4: 8086 mode, normal EOI, non-buffered. */

  /* Unmask all interrupts. */
  outb (PIC0_DATA, 0x00);

can someone explain to me how it works:

-the role of outb (i didn't understand the linux man)

-the addresses and their meaning

another unrelated question,i read that outb and inb are for port-mapped I/O, can we use memory-mapped I/o for doing Input/output communication?

thanks.

3

There are 3 answers

1
NPE On BEST ANSWER

outb() writes the byte specified by its second argument to the I/O port specified by its first argument. In this context, a "port" is a means for the CPU to communication with another chip.

The specific C code that you present relates to the 8259A Programmable Interrupt Controller (PIC).

You can read about the PIC here and here.

If that doesn't provide enough details to understand the commands and the bit masks, you could always refer to the chip's datasheet.

0
Brendan On

Device specific code is best read in conjunction with the corresponding datasheet. For example, the "8259A Programmable Interrupt Controller" datasheet (http://pdos.csail.mit.edu/6.828/2005/readings/hardware/8259A.pdf) clearly (but concisely) explains almost everything.

However, this datasheet will only explain how the chip can be used (in any system), and won't explain how the chip is used in a specific system (e.g. in "PC compatible" 80x86 systems). For that you need to rely on "implied de facto standards" (as a lot of the features of the PIC chips aren't used on "PC compatible" 80x86 systems, and may not be supported on modern/integrated chipsets).

Normally (for historical reasons) the PIC chip's IRQs are mapped to interrupts in a strange/bad way. For example, IRQ 0 is mapped to interrupt 8 and conflicts with the CPU's double fault exception. The specific code you've posted remaps the PIC chips so that IRQ0 is mapped to interrupt 0x20 (and IRQ1 to interrupt 0x21, ..., IRQ 15 mapped to IRQ 0x2F). It's something an OS typically does to avoid the conflicts (e.g. so that each interrupt is used for an IRQ or an exception and never both).

To understand "outb()", look at the "OUT" instruction in Intel's manuals. It's like there's 2 address spaces - one for normal physical addresses and a completely separate one for IO ports, where normal instructions (indirectly) access normal physical memory; and the IO port instructions (IN, OUT, INSB/W/D, OUTSB/W/D) access the separate "IO address space".

3
old_timer On

The traditional 8088/86 had/has a memory control signal that is essentially another address bit tied directly to the instruction. The control signal separating the accesses into I/O and Memory, creating two separate address spaces. Not unlike CS, DS, etc creating separate memory spaces inside the chip (before hitting the external memory space). Other processor families use what is called memory mapped I/O.

These days the memory controllers/system is chopped up inside and outside the chip in all different ways, sometimes for example with many control signals that indicate instruction vs data, cache line fills, write through vs write back, etc. To save on external circuitry the memory mapping happens inside the chip and for example dedicated rom interfaces, separate from ram, etc are found on the edge, far more complicated and separate than I/O space vs Memory space of the old 8088/86.

the out and in instruction and a few family members change whether you are doing an I/O access or memory access, and traditinally the interrupt controller was a chip that decoded the memory bus looking for I/O access with the address allocated for that device. Decades of reverse compatibility later and you have the present code you are looking at.

If you really want to understand it you need to find the datasheets for the device that contains the interrupt controller, likely to be combined with a bunch of other logic on a big support chip. Other datasheets may be required as well.