The Place to Start for Operating System Developers
It is currently Wed Jun 03, 2020 1:12 pm

All times are UTC - 6 hours

Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: Sizes and addresses of IO ports, weird behavior
PostPosted: Tue Jun 11, 2019 7:25 pm 

Joined: Tue Jun 11, 2019 6:35 pm
Posts: 1
I'm currently experimenting with communicating with the ATA disk controller through its I/O ports interface, because I try to figure out what sizes they are, and how the size of the data I'm trying to write or read to them affects the read/write operation. And I'm getting some werid behaviour I don't quite understand. Here's my test code:

mov ax, 0AAAAh      ; Just a pattern to better see what it will be overwritten with.
mov dx, 01F0h       ; ATA primary controller's Command Block ports start here.
in ax, dx           ; I read a 16-bit value, now AX seems to be FFFF.
mov bx, ax          ; I make a copy of that result in BX for later comparison.
mov ax, 0AAAAh      ; I restore my pattern.
in al, dx           ; Now I read just an 8-bit value into AL. After that, AX seems to be 0AAFFh, as expected.
xchg al, ah         ; I swap the halves of AX before reading another byte into AL. Now AX is 0FFAAh.
inc dx              ; I move on to the next ATA register, 01F1h.
in al, dx           ; I read one byte from 01f1h into AL, and... AX is 0FF00h   !!!  WTF??? o_O
; A while ago, 01F0h contained 0FFFFh, which I guess was 01f0h=0FFh and 01f1h=0FFh.
; But now it says that 01F0h=FFh, but 01F1h=00h ??  What is going on here?
; Ok, let's double check by reading a word beginning at 01F1h:
mov ax, 0CCCCh      ; Scratch pattern.
in ax,dx            ; Now it turns out that 01F1h contains 0000h. So I guess 01F1h=00h and 01F2=00h ? Let's see:
mov ax, 0AAAAh      ; Scratch pattern.
inc dx              ; DX is now 01F2h, and this port is supposed to contain 00h. Now does it?
in al, dx           ; AX is now... 00FFh, which means that 01F2h constains 0FFh  :/

Are my assumptions wrong then that every I/O port is 8-bit long, each byte from this 64K space having its own 16-bit address?
Well, not really an "assumption", since the Intel's manual itself states:

Intel wrote:
The processor’s I/O address space is separate and distinct from the physical-memory address space.
The I/O address space consists of 2¹⁶ (64K) individually addressable 8-bit I/O ports, numbered 0 through FFFFH. [...] 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.

so my understanding of the paragraph quoted above is that the I/O space is pretty much a fancy array of 65536 bytes, each with its own address, and when I read two consecutive bytes from 01F0h and 01F1h, I should have gotten the same result as when I read one 16-bit word beginning from 01F0h (it would then read the least-significant byte from 01F0h, and the most-significant byte from 01F1h).

So why am I getting those weird, contradictory results?
Can anyone explain to me this strange behaviour?

My question is related to the fact that I've seen an actual code for reading sectors from the disk through ATA ports, which used the insw instruction to read two bytes at a time from the Command Block "data" register 01F0h into some memory buffer, and it worked just fine, no strange behavior. But I see that the "error code" register 01F1h is just next to the "data" register 01F0h, so I'm confused how is it that when insw is reading words from 01F0h, it doesn't read the 01F1h port as the higher half of the data word :q Am I missing something?

 Post subject: Re: Sizes and addresses of IO ports, weird behavior
PostPosted: Wed Jun 12, 2019 1:36 am 

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 1979
IBM completely ignored Intel's recommendations when they designed their PC hardware.

From a hardware perspective, you can tell the difference between a 286 making two adjacent byte accesses and a 286 making one single word access. When IBM designed the PC AT Fixed Disk and Diskette Drive Adapter, they decided it would be a good idea to decode 0x1f1 differently depending on whether it was being accessed as a single byte or as the upper half of the word at 0x1f0. The result is that, despite Intel's claim otherwise, the I/O space is not a simple array.

Overlapping address decoding like this is also possible in the memory address space, but I'm not aware of any hardware that relies on it.

 Post subject: Re: Sizes and addresses of IO ports, weird behavior
PostPosted: Wed Jun 12, 2019 5:26 am 

Joined: Wed Mar 09, 2011 3:55 am
Posts: 359
To expand on Octocontrabass's post, when the processor executes an instruction that reads/writes an I/O port, it just places an address (and data in the case of a write) on the bus, signals an I/O request of the appropriate width, and waits for the device with that port number to respond. That device can then respond *absolutely however it wants*. Intel specified things the way they did because the 8088 could *only* make 8-bit accesses, so hardware that treated 8 and 16 bit accesses differently would react differently to a word I/O instruction from an 8086 or 286 (A single 16-bit access) than to the same instruction from an 8088 (two 8-bit accesses). But when IBM introduced a 16-bit bus on the PC/AT, they didn't try to make any new cards back-compatible with the older, 8088 based PCs, and consequently saw no reason not to violate the assumption that a 16-bit access would act the same as two 8-bit accesses to consecutive addresses.

Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 6 hours

Who is online

Users browsing this forum: 8infy, nexos, thewrongchristian and 13 guests

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group