sys::hw service

The sys::hw service is in charge of hardware devices. It coordinates and manages communications with the hardware.

It is known as the I/O manager, or Ion.

Hardware detection

Hardware detection is handled by the kernel itself, which exposes a raw device descriptor (RDD).

Unique device identifier

Each device gets a unique device identifier (UDI) encoded on 8 bytes, which identifies a unique hardware device. It is unique across devices and consistent across reboots. Unlike the kernel's device identifier (KDI), the UDI is generated randomly to prevent from getting informations on the hardware just from the UDI.

Device formats

This section describes the multiple formats used by this service to deal with devices.

Device type descriptor

From the RDD is derived the device type descriptor (DTD), which describes the device's type. Its composition and size depends on the connection type, but it varies from empty (0 byte) if the connection type guarantees no information, up to 256 bytes.

The format remains to be determined but should be along the lines of a number-based equivalent of ModAlias, like :

  • PCI-Express:
    • Vendor (8 bytes)
    • Sub-vendor (8 bytes)
    • Type (8 bytes)
    • Sub-type (8 bytes)
    • ...
  • ...

Drivable device raw descriptor

A drivable device raw descriptor (DDRD) is a 512-byte long data structure meant to be used by drivers. It uses the following format:

  • UDI (8 bytes)
  • CII (4 bytes)
  • Size of the DTD (1 byte)
  • DTD (up to 256 bytes)
  • Future-proof

Driven device type

A driven device type (DDT), usually referred to as the device type, is generated by the driver for each device it drives from the DDRD. This is a normalized value, used by the system to determine which actions can be performed through this device.

It's a 4-byte value, the strongest two bytes describing the category and the weakest two the sub-category.

The following list contains all possible values for DDTs, but is far from being complete yet. It will also grow over time as new device types appear on the market.

  • 0x0001: Storage
    • 0x0001: Hard drive
    • 0x0002: SSD
    • 0x0003: USB flash drive
    • 0x0004: SD flash memory card
  • ...

Normalization

When a device is driven, other processes can ask this service to use normalized methods. These are methods that allow to perform a specific action or to receive normalized notifications about specific events of a specific device.

Also, interrupts are normalized to ensure constancy across devices of the same type. They are sent to the driver processes using the DEVICE_EVENT notification.

The normalization of methods, notifications and interrupts is performed by the driver in charge of the device.

There are several methods, depending on the device's type (DDT). Notifications differ as well.

You can find the far from being complete list in the relevant specifications directory. It will grow over time as new device types appear on the market and as existing devices evolve to provide new features.

Patterns

Several methods of this service use patterns, which allow to match devices depending on several criterias.

A pattern is a data structure whose size varies from 5 to 277 bytes made of the following:

  • Pattern (1 byte)
    • Bit 0: match all connection types
    • Bit 2: match all buses
    • Bit 3: match all ports
  • Connection type (1 byte)
  • Bus number (1 byte)
  • Port number (1 byte)
  • DTD length (1 byte) - 0 to omit DTD
  • DTD pattern indicator (32 bytes, only if DTD) - indicates which bytes of the DTD must be used as patterns
  • DTD (up to 256 bytes)

It's possible to match only devices that use a given connection type, and more specifically on a given bus and/or port.

It's also possible to list only devices that match a specific DTD pattern. For that, the bit corresponding to the byte number in the DTD pattern indicator must be set.

For instance, providing the DTD 0x0100B2 with the DTD pattern indicator set to 0b01000000, the second byte will match all devices.

Drivers

From a higher level point of view, drivers are services that declare their parent applications as being able to handle certain type of devices through the REGISTER_DRIVER method, using patterns.

Registering as a driver for a pattern requires the application to expose the driver service(s) relevant to the DDT provided in the pattern.

When a device is connected, a driver is selected from the list of drivers able to handle this specific device. If the device is connected for the very first time, the selected driver process first receives an IDENTIFY_DEVICE notification to translate the DDRD into a DDT.

Then, the driver process receives a DEVICE_EVENT notification, which will also be sent if the status of the device changes.

From this point, the driver process can communicate with the device using its I/O ports with the READ_IO_PORT and WRITE_IO_PORT syscalls.

It can also map the device's memory into its own address space using an AMS with the DEVICE_AMS syscall.

Other processes can then ask the driver to perform specific actions depending on the type of device, using normalized methods which can be sent to the driver using the ASK_DRIVER method. The driver receives these informations through the DRIVER_METHOD_REQUEST notification.

All methods and notifications are transmitted through this service, which performs permission checkings and validates some arguments.

The driver is also in charge of translating the interrupts of a device as well as eventual events polled from its (mapped) memory to normalized notifications which can then be sent to processes that subscribed to them using the related normalized methods.

You can see the complete list of methods and notifications for each type of driver services in the related section of the documentation.

Driver selection

A driver is selected for a specific hardware device if it matches any of the following criterias, in decreasing importance order:

  • The user selected this driver for this specific hardware device ;
  • The user selected this driver for this specific type of hardware devices (pattern) ;
  • This driver is the one with the most specific pattern covering this hardware device ;
  • This driver is the only one able to drive this specific hardware device (DTD)

If no criteria is matched, the driver isn't selected to drive the given hardware device.

A note on performances

Although hardware devices' interrupts are notified to the driver through service socket notifications, the latency is still minimal as soon as the driver listens to the RECV_SOCK_MSG signal, which like all signals uses interrupts and so guarantees a very low latency.

Latency reduction for storage devices

Direct driver access for sys::fs

All operations related to storage devices are handled by the sys::fs service. To avoid the cost of using sys::hw as a relay for hardware operations, the sys::fs service is allowed to directly communicate with all storage driver services.

Direct storage access for sys::fs

In the event a specific storage device doesn't require a dedicated driver, the sys::fs service can directly access the said hardware device.

Methods

0x0001 ENUM_DEVICES

Enumerate connected devices, reserved to system services.

It's also possible to only count the number of devices matching the provided criterias by providing a start index and end index of 0.

Required permission: devices.enum

Arguments:

  • Start index (4 bytes)
  • End index (4 bytes)
  • Pattern (277 bytes)

Answer:

  • Number of found devices globally (4 bytes)
  • Number of devices listed in this answer (4 bytes)
  • DDRD of each device (512 bytes * number of devices)
  • 0x01 if some devices were masked due to insufficient permissions, 0x00 else (1 byte)

Errors:

  • 0x1000: Start index is lower than the end index
  • 0x1001: Invalid connection type
  • 0x1002: Bus number was provided without a connection type
  • 0x1003: Port number was provided without a connection type
  • 0x1004: Invalid DTD
  • 0x1005: Range is greater than the available answer size
  • 0x3000: Client is not a system service
  • 0x3001: Provided bus was not found
  • 0x3002: Provided port was not found

0x0002 SUBSCRIBE_DEVICES

Subscribe to events related to devices matching a patterns, reserved to system services.

All current and future devices matching this pattern will cause a DEVICE_EVENT notification.

Required permission: devices.subscribe

Arguments:

  • 0x00 to subscribe, any other value to unsubscribe
  • Pattern (277 bytes)

Answer:

None

Errors:

  • 0x3000: Client is not a system service
  • 0x3001: Asked to unsubscribe but no subscription is active for this pattern

0x1000 REGISTER_DRIVER

Set up a service as a driver for all devices matching a pattern.
If multiple drivers have colliding patterns, the final user will be prompted to choose a driver.

When a new device is connected, the driver process will receive an IDENTIFY_DEVICE notification to translate the DDRD into a DDT.

The driver process will receive DEVICE_EVENT notifications for drivable devices. This notification will only be sent for devices for which the system chose this driver as the main one.
Notifications are also retroactive, which means they will be sent for already-connected devices.

The driver will also have the device registered in its drivable devices attribute, allowing it to use the DEVICE_AMS syscall to map the device's memory in its own.

Required permission: devices.register_driver

Arguments:

  • Pattern of the devices to drive (up to 277 bytes)

Answer:

None

Errors:

  • 0x3000: Current process is not a service
  • 0x3001: Process' parent application does not expose the relevant integration services
  • 0x3002: Current process is already registered as a driver for this pattern

0x1001 UNREGISTER_DRIVER

Unregister a service previously registered as a driver.

Required permission: None

Arguments:

  • Pattern to unsubscribe from (up to 277 bytes)

Errors:

  • 0x3000: Current process is not registered as a driver for this pattern

0x2000 NOTIFY_PROCESS

Send a notification to a process that registered itself for normalized methods through a normalized method.

Required permission: None

Arguments:

Answer:

Expected answer by the notified process for this method if any

Errors:

  • 0x3000: Unknown notification ID

0xA000 ASK_DRIVER

Ask a driver to use a normalized method on a device it drives.

Reserved to system services.

Required permission: devices.ask_driver

Arguments:

  • Device's UDI (8 bytes)
  • Method's code (4 bytes)
  • Method's arguments (size depends on the method)

Answer:

Expected answer format for this method

Errors:

  • 0x3000: Client is not a system service
  • 03x001: Unknown device UDI provided
  • 0x3002: Provided method code is invalid for this device
  • 0x3003: Invalid arguments provided for this method

0xD000 AUTHORIZE_FS_INTERFACE

Authorize a filesystem interface to access a specific part of a storage device.

The interface service will be allowed to perform requests on the provided storage device, only on the provided data segment.

Arguments:

  • Device's UDI (8 bytes)
  • Start byte (8 bytes)
  • End byte (8 bytes)

Answer:

Errors:

  • 0x3000: Client is not the sys::fs service
  • 0x3001: Unknown device UDI provided
  • 0x3002: Start byte is not aligned on the device's sectors
  • 0x3003: End byte is not aligned on the device's sectors
  • 0x3004: End byte is greater than or equal to the start byte

0xD001 UNAUTHORIZE_FS_INTERFACE

Unauthorize a filesystem interface authorization created using the AUTHORIZE_FS_INTERFACE method.

Arguments:

  • Authorization token (8 bytes)

Errors:

  • 0x3000: Client is not the sys::fs service
  • 0x3001: Unknown authorization token provided

0xD002 AUTH_PERFORM_STORAGE

Used by filesystem interfaces which received an authorization beforehand.

Perform an action just like with the ASK_DRIVER method, but restricted to the authorization's scope.

Arguments:

  • Authorization token (8 bytes)
  • Method's code (4 bytes)
  • Method's arguments (size depends on the method)

Answer:

Expected answer format for this method

Errors:

  • 0x3000: The provided authorization token is unknown or not tied to this client

Notifications

0x0002 IDENTIFY_DEVICE

Sent for a specific device the client that was selected as its driver.

Datafield:

Expected answer:

  • DTD (512 bytes)

Errors:

  • 0x3000: The provided DTD is invalid
  • 0x3001: The client does not expose the driver service relevant to this type of device

0x0003 DEVICE_EVENT

Sent for a specific device to clients that either:

Datafield:

  • DDT (512 bytes)
  • Event code (1 byte):
    • 0x10: device was just connected
    • 0x11: a driver was just selected for the device
    • 0x12: the device is ready to use
    • 0x20: device was disconnected (software)
    • 0x21: the device is being disconnected by its driver
    • 0x22: the device has been disconnected by the driver
    • 0x23: the device was brutally disconnected (hardware)
    • 0x30: device was just put to sleep
    • 0x31: device was just awoken from sleep
  • Indicator (1 byte):
    • Bit 0: set if this device is connected for the first time
    • Bit 1: set if this device was disconnected brutally (not by the system itself)
    • Bit 2: set if this device is connected for the first time on this specific port

0x1000 DEVICE_INTERRUPT

Sent to a driver after a device it's currently driving raised an interrupt.

Datafield:

0xA000 DRIVER_METHOD_REQUEST

Sent to a driver after receiving a valid normalized method request.

The driver is expected to answer using the relevant answer format for the provided normalized method and arguments.

The notification ID is generated by this service to allow the driver to send normalized notifications to a process that registers for it through this method without showing the caller process' PID to the driver process.

Datafield:

  • DDT (4 bytes)
  • Notification ID (8 bytes)
  • Method's code (4 bytes)
  • Method's arguments (size depends on the method)

Expected answer:

Expected answer format for this method if any

0xA001 DEVICE_NORM_NOTIF

Sent to a process that subscribed to normalized notifications of a device.
This notification is transferred by the sys::hw service after the driver sent it its content through the NOTIFY_PROCESS method.

Datafield: