X86 Serial Port Address

An I/O port is usually used as a technical term for a specific address on the x86 s IO bus. This bus provides communication with devices in a fixed order and size.

Serial port address. b_cochofel Posts: 30 Member. September 2003 in x86 Assembly. MEM 0040h:0000h - BASE I/O ADDRESS OF FIRST SERIAL I/O PORT Size: WORD.

Apr 26, 2010  Port IO. From OSDev Wiki. The x86 architecture separates the address space in two programmatically distinct groups: serial and parallel port.

Jan 21, 2005  The serial port, also known as the COM port, is the most common out-of-band hardware interface. For information about selecting serial ports that.

The second day in the Linux device drivers laboratory was expected to be quite different from the typical software-oriented class. Apart from accessing and programming architecture-specific I/O mapped hardware in x86, it had a lot to offer first-timers with regard to reading hardware device manuals commonly called data sheets and how to understand them to write device drivers. In contrast, the previous session about generic architecture-transparent hardware interfacing was about mapping and accessing memory-mapped devices in Linux without any device-specific details.

x86-specific hardware interfacing

Unlike most other architectures, x86 has an additional hardware accessing mechanism, through direct I/O mapping. It is a direct 16-bit addressing scheme, and doesn t need mapping to a virtual address for access. These addresses are referred to as port addresses, or ports. Since this is an additional access mechanism, it has an additional set of x86 assembly/machine code instructions. And yes, there are the input instructions inb, inw, and inl for reading an 8-bit byte, a 16-bit word, and a 32-bit long word, respectively, from I/O mapped devices, through ports. The corresponding output instructions are outb, outw and outl, respectively. The equivalent C functions/macros available through the header are as follows:

void outb u8 value, unsigned long port ;

void outw u16 value, unsigned long port ;

void outl u32 value, unsigned long port ;

The basic question that may arise relates to which devices are I/O mapped and what the port addresses of these devices are. The answer is pretty simple. As per x86-standard, all these devices and their mappings are predefined. Figure 1 shows a snippet of these mappings through the kernel window /proc/ioports. The listing includes predefined DMA, the timer and RTC, apart from serial, parallel and PCI bus interfaces, to name a few.

Figure 1: x86-specific I/O ports

For example, the first serial port is always I/O mapped from 0x3F8 to 0x3FF. But what does this mapping mean. What do we do with this. How does it help us to use the serial port. That is where a data-sheet of the corresponding device needs to be looked up.

A serial port is controlled by the serial controller device, commonly known as an UART Universal Asynchronous Receiver/Transmitter or at times a USART Universal Synchronous/Asynchronous Receiver/Transmitter. On PCs, the typical UART used is the PC16550D. The data-sheet for this PDF can be downloaded as part of the self-extracting package BIN file used for the Linux device driver kit, available at lddk.esrijan.com.

Generally speaking, from where, and how, does one get these device data sheets. Typically, an online search with the corresponding device number should yield their data-sheet links. Then, how does one get the device number. Simple by having a look at the device. If it is inside a desktop, open it up and check it out. Yes, this is the least you may have to do to get going with the hardware, in order to write device drivers. Assuming all this has been done, it is time to peep into the data sheet of the PC16550D UART.

Device driver writers need to understand the details of the registers of the device, as it is these registers that writers need to program, to use the device. Page 14 of the data sheet also shown in Figure 2 shows the complete table of all the twelve 8-bit registers present in the UART PC16550D.

Figure 2: Registers of UART PC16550D

Each of the eight rows corresponds to the respective bit of the registers. Also, note that the register addresses start from 0 and goes up to 7. The interesting thing about this is that a data sheet always gives the register offsets, which then needs to be added to the base address of the device, to get the actual register addresses.

Who decides the base address and where is it obtained from. Base addresses are typically board/platform specific, unless they are dynamically configurable like in the case of PCI devices. In this case, i.e., a serial device on x86, it is dictated by the x86 architecture and that precisely was the starting serial port address mentioned above 0x3F8.

Thus, the eight register offsets, 0 to 7, exactly map to the eight port addresses 0x3F8 to 0x3FF. So, these are the actual addresses to be read or written, for reading or writing the corresponding serial registers, to achieve the desired serial operations, as per the register descriptions.

All the serial register offsets and the register bit masks are defined in the header. So, rather than hard-coding these values from the data sheet, the corresponding macros could be used instead. All the following code uses these macros, along with the following:

Operating on the device registers

To summarise the decoding of the PC16550D UART data sheet, here are a few examples of how to do read and write operations of the serial registers and their bits.

Reading and writing the Line Control Register LCR :

val inb SERIAL_PORT_BASE UART_LCR / 3 / ;

outb val, SERIAL_PORT_BASE UART_LCR / 3 / ;

Setting and clearing the Divisor Latch Access Bit DLAB in LCR:

Reading and writing the Divisor Latch :

dlab inb SERIAL_PORT_BASE UART_LCR ;

dlab UART_LCR_DLAB; // Setting DLAB to access Divisor Latch

outb dlab, SERIAL_PORT_BASE UART_LCR ;

val inw SERIAL_PORT_BASE UART_DLL / 0 / ;

outw val, SERIAL_PORT_BASE UART_DLL / 0 / ;

To get a real experience of low-level hardware access and Linux device drivers, the best way would be to play with the Linux device driver kit LDDK mentioned above. However, just for a feel of low-level hardware access, a blinking light emitting diode LED may be tried, as follows:

Connect a light-emitting diode LED with a 330 ohm resistor in series across Pin 3 Tx and Pin 5 Gnd of the DB9 connector of your PC.

Pull up and down the transmit Tx line with a 500 ms delay, by loading and unloading the blink_led driver, using insmod blink_led.ko and rmmod blink_led, respectively.

Driver file blink_led.ko can be created from its source file blink_led.c by running make with the usual driver Makefile. Given below is the complete blink_led.c:

data inb SERIAL_PORT_BASE UART_LCR ;

outb data, SERIAL_PORT_BASE UART_LCR ;

/ Defaulting the Tx line high /

MODULE_AUTHOR Anil Kumar Pugalia ;

MODULE_DESCRIPTION Blinking LED Hack ;

You might have wondered why Shweta is missing from this article. She bunked all the classes. Watch out for the next article to find out why.

Reading Parallel/Serial Port Address from BIOS Typically, The addresses of Parallel and Serial ports present on a PC is stored in BIOS. An application can read this.

x86 serial port address Device Drivers, Part 8: Accessing x86-Specific I/O-Mapped Hardware
  • In the x86 architecture, an input/output base address is the first address of a range of consecutive read/write addresses that a device uses on the x86 s IO bus.
  • Simplest: serial port on x86. For example, the first serial port is always I/O mapped from 0x3F8 to 0x3FF. But what does this mapping mean. What do we do with this.
x86 serial port address