ladybird/Documentation/Kernel/IOWindow.md

3 KiB

The IOWindow class

Introduction to port-mapped IO and memory-mapped IO

Port-mapped IO

Port mapped IO is a x86-specific method to access hardware registers. It uses a set of specific instructions in the x86 architecture to invoke Input and Output operations on hardware that is present in the platform board.

IOAddress io(0x3f0)
u8 ide_status = io.offset(0).in<u8>()

Memory-mapped IO

Memory mapped IO is a platform-agnostic method to access hardware registers. It uses a set of memory access instructions in many computer architectures to invoke Input and Output operations on hardware that is present in the platform board.

auto mapping = Memory::TypedMapping::map_typed_writable<u16>(0xb8000);
*mapping = 0x001b;

The IOWindow class to rule them all (almost)!

The entire idea behind the IOWindow class is to make it much more easier to compile the Kernel for non-x86 builds, so the class abstracts platform-specific methods to access hardware such as the port-mapped IO method. In compile-time, when generating a Kernel for non-x86 target, the entire port-mapped IO code is omitted as it's not relevant for non-x86 targets.

In many cases, devices (such as PCI devices) can either use the IO space or memory space to expose their registers for the CPU to utilize as the host software invokes IO operations for various reasons. Some devices expose equivalent registers in both the IO space and memory space to help legacy host software to interact with the hardware. One example to this is old AHCI controllers which could be used in legacy mode - i.e. exposing SFF IDE registers in the IO space, or to enable memory mapped registers as being defined in the SATA AHCI HBA specification.

The general rule in kernel driver programming is to know that there are only two valid cases on whether to use the IOWindow structure or not:

  1. The device is known to either use the IO space, memory space or both, taking into consideration that variants of the device can disable either of the options. In this case, we need to use the IOWindow structure as it will help us to correctly use the IO window in either case.
  2. The device is known to use only the memory space, therefore we can ignore the IOWindow structure and instead use the Memory::TypedMapping structure to help navigating in the memory-mapped registers of the device.

A note about 64 bit access for memory mapped IO

As far as we can tell, writing to 64 bit register can actually be done for the most part with two 32 bit IO access operations. When genuine 64 bit access is needed, IOWindow is probably not the appropriate solution anyway, because the device is only supporting memory-mapped IO and there's no way it can provide register access via port mapped IO - that method simply doesn't support generating 64 bit IO access, so you should use the Memory::TypedMapping mapping method instead.

Therefore, to ensure we keep everything simple, there's simply no API to generate pure 64 bit IO access with the IOWindow class.