In my MIT OS course (686) I have found some code that I don't understand. I'm trying to understand the instruction inb $0x64, %al
in boot/boot.S.
My understanding is that it's reading one byte from data port 0x64 into AL, What is port 0x64? Which device or mechanism is it testing for busy? I'm confused about the comment in the code Busy? What does the comment mean and what does it refer to?
# Enable A20:
# For fascinating historical reasons (related to the fact that
# the earliest 8086-based PCs could only address 1MB of physical memory
# and subsequent 80286-based PCs wanted to retain maximum compatibility),
# physical address line 20 is tied to low when the machine boots.
# Obviously this a bit of a drag for us, especially when trying to
# address memory above 1MB. This code undoes this.
seta20.1: inb $0x64,%al # Get status
testb $0x2,%al # Busy?
jnz seta20.1 # Yes
movb $0xd1,%al # Command: Write
outb %al,$0x64 # output port
seta20.2: inb $0x64,%al # Get status
testb $0x2,%al # Busy?
jnz seta20.2 # Yes
movb $0xdf,%al # Enable
outb %al,$0x60 # A20
What is port 0x64?
Port 0x64 is the IO port of the keyboard controller.
Keyboard controller has two ports 0x64 and 0x60.
Port 0x64 (Command Port) is used for sending commands to keyboard controller (PS/2).
Port 0x60 (Data Port) is used for sending data to/from PS/2(Keyboard) controller or the PS/2 device itself.
Which device or mechanism is it testing for busy? I'm confused about the comment in the code Busy? What does the comment mean and what does it refer to?
The code here makes the CPU poll the PS/2 keyboard controller to see if it is busy.
inb $0x64,%al # Get status
The above instruction reads the Status Register of the PS/2 controller which of 8 bits in length. Specifically it is trying to read the state of the input buffer - bit 1.
testb $0x2,%al # Busy?
The byte returned from the previous inb instruction is tested here. Here the status of the input buffer is checked to see if it full or empty - bit 1(0x2).
Status Register - PS/2 Controller
Bit Meaning
0 Output buffer status (0 = empty, 1 = full) (must be set before attempting to read data from IO port 0x60)
1 Input buffer status (0 = empty, 1 = full) (must be clear before attempting to write data to IO port 0x60 or IO port 0x64)
2 System Flag - Meant to be cleared on reset and set by firmware (via. PS/2 Controller Configuration Byte) if the system passes self tests (POST)
3 Command/data (0 = data written to input buffer is data for PS/2 device, 1 = data written to input buffer is data for PS/2 controller command)
4 Unknown (chipset specific) - May be "keyboard lock" (more likely unused on modern systems)
5 Unknown (chipset specific) - May be "receive time-out" or "second PS/2 port output buffer full"
6 Time-out error (0 = no error, 1 = time-out error)
7 Parity error (0 = no error, 1 = parity error)
Syntax of x86 assembly code The above thread explains in detail about the Port 0x64 and 0x60 referred here.
Also the below link discusses in details on how the IO ports are used. How are I/O port addresses and data sent?
The port 0x64 is the one used by the 8042 keyboard controller in the original IBM PS/2 system. Because 8042 is a general-purpose micro controller that can run programs and has programmable pins, the IBM engineers decided to use the extra pins for unrelated functionalities - one of the pins is used for resetting the CPU, causing it to enter the boot code.
Another function was the A20 gate - as 80286 added 4 bits into the address bus, there were some programs that were written for 8086 and expected the addresses to wrap around to 0 after 1048575 (2^20 - 1). So the IBM engineers figured out a clever solution horrible hack - they used an extra pin from the keyboard controller, that is set to 0 after boot, and added an AND gate to the address line 20 that uses the A20 address line and this line from the keyboard controller as its input - essentially the 20th bit of the CPU address bus going to the memory controller is zeroed, unless the A20 gate enable pin is enabled.
Of course if you want to actually address all of your memory, like any modern operating system would, then you need to re-enable it.
The convention is to ask the controller if it is busy, and when it is no longer busy, to send the commands to it (if you write a command to it when it is busy then all sorts of things might happen including it ignoring the command or being locked in a weird state).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With