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
- Unique device identifier
- Device formats
- Normalization
- Drivers
- Latency reduction for storage devices
- Methods
- Notifications
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:
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
: Storage0x0001
: Hard drive0x0002
: SSD0x0003
: USB flash drive0x0004
: 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 index0x1001
: Invalid connection type0x1002
: Bus number was provided without a connection type0x1003
: Port number was provided without a connection type0x1004
: Invalid DTD0x1005
: Range is greater than the available answer size0x3000
: Client is not a system service0x3001
: Provided bus was not found0x3002
: 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 service0x3001
: 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 service0x3001
: Process' parent application does not expose the relevant integration services0x3002
: 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:
- Notification ID (8 bytes)
- Normalized notification's content
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 service03x001
: Unknown device UDI provided0x3002
: Provided method code is invalid for this device0x3003
: 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:
- Authorization token (8 bytes) to use with
UNAUTHORIZE_FS_INTERFACE
Errors:
0x3000
: Client is not thesys::fs
service0x3001
: Unknown device UDI provided0x3002
: Start byte is not aligned on the device's sectors0x3003
: End byte is not aligned on the device's sectors0x3004
: 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 thesys::fs
service0x3001
: 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:
- DDRD (512 bytes)
Expected answer:
- DTD (512 bytes)
Errors:
0x3000
: The provided DTD is invalid0x3001
: 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:
- Drives this specific device
- Subscribed to it using the
SUBSCRIBE_DEVICES
method
Datafield:
- DDT (512 bytes)
- Event code (1 byte):
0x10
: device was just connected0x11
: a driver was just selected for the device0x12
: the device is ready to use0x20
: device was disconnected (software)0x21
: the device is being disconnected by its driver0x22
: the device has been disconnected by the driver0x23
: the device was brutally disconnected (hardware)0x30
: device was just put to sleep0x31
: 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:
- Device's UDI (8 bytes)
- Normalized interrupt
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:
- Device's UDI (4 bytes)
- Normalized notification's content