Skip to content

Commit 600209d

Browse files
committed
q-dev: update docs
1 parent ca949bb commit 600209d

File tree

1 file changed

+128
-54
lines changed

1 file changed

+128
-54
lines changed

doc/qubes-devices.rst

+128-54
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,80 @@
11
:py:mod:`qubes.devices` -- Devices
2-
===================================
2+
==================================
33

4-
Main concept is that some domain (backend) may expose (potentially multiple)
5-
devices, which can be attached to other domains (frontend). Devices can be of
6-
different buses (like 'pci', 'usb', etc.). Each device bus is implemented by
7-
an extension (see :py:mod:`qubes.ext`).
4+
The main concept is that a domain (backend) can expose (potentially multiple)
5+
devices, each through a port, where only one device can be in one port at
6+
any given time. Such devices can be connected to other domains (frontends).
7+
Devices can be of different buses (like 'pci', 'usb', etc.). Each device bus
8+
is implemented by an extension (see :py:mod:`qubes.ext`).
89

9-
Devices are identified by pair of (backend domain, `port_id`), where `port_id`
10-
is :py:class:`str` and can contain only characters from `[a-zA-Z0-9._-]` set.
10+
Devices are identified by a pair (`port`, `device_id`), where `port` is a pair
11+
(backend domain, `port_id`). Both `port_id` and `device_id` are :py:class:`str`,
12+
and in addition, port_id is unique per backend. More about the requirements
13+
for `port_id` and `device_id` can be found in the sections below.
1114

15+
Classes
16+
-------
17+
18+
:py:class:`qubes.device_protocol.Port`: a pair `<backend_domain>:<port_id>`
19+
with `devclass` (e.g., `pci`, `usb`). In the previous version (before
20+
QubesOS 4.3), this was referred to as `Device`, and `port_id` was named `ident`.
21+
22+
:py:class:`qubes.device_protocol.AnyPort`: A class used to handle cases where
23+
any port is accepted.
24+
25+
:py:class:`qubes.device_protocol.VirtualDevice`: A pair `<port>:<device_id>`.
26+
This class links a device identified by `device_id` to a specific port.
27+
If both values are specified, the instance represents a device connected to
28+
that particular port. If the port is of type `AnyPort`, it represents a device
29+
identified by `device_id` that can be connected to any port. This is used by
30+
:py:class:`qubes.device_protocol.DeviceInfo`, which describes what to do with
31+
a device identified by `device_id` when connected anywhere. Similarly,
32+
when `device_id` is `*`, the instance represents any potential device
33+
connected to the given port. As a result, the device is considered "virtual"
34+
meaning it may or may not represent an actual device in the system.
35+
A device with `*:*` (any port and any device) is not permitted.
36+
37+
:py:class:`qubes.device_protocol.DeviceInfo`: Derived from `VirtualDevice`.
38+
Extensions should assume that `Port` is provided, and based on that,
39+
`device_id` should return the same string for the same device, regardless of
40+
which port it is connected to. The `device_id` acts as a device hash
41+
and *should* be "human-readable". It must contain only digits, ASCII letters,
42+
spaces, and the following characters: `!#$%&()*+,-./:;<>?@[\]^_{|}~`.
43+
It cannot be empty or equal to `*`.
44+
45+
:py:class:`qubes.device_protocol.DeviceAssignment`: Represents the relationship
46+
between a `VirtualDevice` and a `frontend_domain`. There are four modes:
47+
#. `manual` (attachment): The device is manually attached to `frontend_domain`.
48+
This type of assignment does not persist across domain restarts.
49+
#. `auto-attach`: Any device that matches a `VirtualDevice` will be
50+
automatically attached to the `frontend_domain` when discovered
51+
or during domain startup.
52+
#. `ask-to-attach`: Functions like `auto-attach`, but prompts the user for
53+
confirmation before attaching. If no GUI is available, the prompt is ignored.
54+
#. `required`: The device must be available during `frontend_domain` startup and
55+
will be attached before the domain is started.
56+
57+
:py:class:`qubes.device_protocol.DeviceInterface`: Represents device interfaces
58+
as a 7-character code in the format `BCCSSII`, where `B` indicates the devclass
59+
(e.g., `p` for PCI, `u` for USB, `?` for unknown), `CC` is the class code,
60+
`SS` is the subclass code, and `II` represents the interface code.
61+
62+
:py:class:`qubes.device_protocol.DeviceCategory`: Provides an easy-to-use,
63+
arbitrary subset of interfaces with names assigned to categories considered as
64+
most relevant to users. When needed, the class should be extended with new
65+
categories. This structure allows for quick identification of the device type
66+
and can be useful when displaying devices to the end user.
1267

1368
Device Assignment vs Attachment
1469
-------------------------------
1570

16-
:py:class:`qubes.device_protocol.DeviceAssignment` describes the assignment of a device
17-
to a frontend VM. For clarity let's us introduce two types of assignments:
71+
For clarity let's us introduce two types of assignments:
1872
*potential* and *real* (attachment). Attachment indicates that the device
1973
has been attached by the Qubes backend to its frontend VM and is visible
2074
from its perspective. Potential assignment, on the other hand,
21-
has two additional options: `automatically_attach` and `required`.
22-
For detailed descriptions, refer to the `DeviceAssignment` documentation.
75+
has tree modes: `auto-attach`, `ask-to-attach` and `required`.
76+
For detailed descriptions, take a look at
77+
:py:class:`qubes.device_protocol.DeviceAssignment` documentation.
2378
In general we refer to potential assignment as assignment
2479
and real assignment as attachment. To check whether the device is currently
2580
attached, we check :py:meth:`qubes.device_protocol.DeviceAssignment.attached`,
@@ -28,17 +83,35 @@ we check :py:meth:`qubes.device_protocol.DeviceAssignment.attach_automatically`.
2883
Potential and real connections may coexist at the same time,
2984
in which case both values will be true.
3085

86+
Understanding Device Identity
87+
-----------------------------
88+
89+
It is important to understand that :py:class:`qubes.device_protocol.Port` does not
90+
correspond to the device itself, but rather to the *port* to which the device
91+
is connected. Therefore, when assigning a device to a VM, such as
92+
`sys-usb:1-1.1`, the port `1-1.1` is actually assigned, and thus
93+
*every* devices connected to it will be automatically attached.
94+
Similarly, when assigning `vm:sda`, every block device with the name `sda`
95+
will be automatically attached. We can limit this using
96+
:py:meth:`qubes.device_protocol.DeviceInfo.device_id`, which returns a string
97+
containing information presented by the device, such as for example
98+
`vendor_id`, `product_id`, `serial_number`, and encoded interfaces.
99+
In the case of block devices, `device_id` consists of the parent's `device_id`
100+
to which the device is connected (if any) and the interface/partition number.
101+
In practice, this means that, a partition on a USB drive will only
102+
be automatically attached to a frontend domain if the parent presents
103+
the correct serial number etc.
31104

32105
Actions
33106
-------
34107

35-
The `assign` action signifies that a device will be assigned to the frontend VM
108+
The `assign` action means that a device will be assigned to the frontend VM
36109
in a potential form (this does not change the current system state).
37110
This will result in an attempt to automatically attach the device
38-
upon the next VM startup. If `required=True`, and the device cannot be attached,
111+
upon the next VM startup. If `mode=required`, and the device cannot be attached,
39112
the VM startup will fail. Additionally, upon device detection (`device-added`),
40113
an attempt will be made to attach the device. However, at any time
41-
(unless `required=True`), the user can manually modify this state by performing
114+
(unless `mode=required`), the user can manually modify this state by performing
42115
`attach` or `detach` on the device, changing the current system state.
43116
This will not alter the assignment, and automatic attachment attempts
44117
will still be made in the future. To remove the assignment the user
@@ -48,23 +121,23 @@ Assignment Management
48121
---------------------
49122

50123
Assignments can be edited at any time: regardless of whether the VM is running
51-
or the device is currently attached. An exception is `required=True`,
52-
in which case the VM must be shut down. Removing the assignment does not change the real system state, so if the device is currently attached
53-
and the user remove the assignment, it will not be detached,
54-
but it will not be automatically attached in the future.
55-
Similarly, it works the other way around with `assign`.
124+
or the device is currently attached. Removing the assignment does not change
125+
the real system state, so if the device is currently attached and the user
126+
remove the assignment, it will not be detached, but it will not be
127+
automatically attached in the future. Similarly, it works the other way
128+
around with `assign`.
56129

57130
Proper Assignment States
58131
------------------------
59132

60133
In short, we can think of device assignment in terms of three flags:
61134
#. `attached` - indicating whether the device is currently assigned,
62-
#. `attach_automatically` - indicating whether the device will be
135+
#. `attach_automatically` - indicating whether the device will be
63136
automatically attached by the system daemon,
64137
#. `required` - determining whether the failure of automatic attachment should
65138
result in the domain startup being interrupted.
66139

67-
Then the proper states of assignment
140+
Then the possible states of assignment
68141
(`attached`, `automatically_attached`, `required`) are as follow:
69142
#. `(True, False, False)` -> domain is running, device is manually attached
70143
and could be manually detach any time.
@@ -79,51 +152,52 @@ because either (i) domain is halted, device (ii) manually detached or
79152
#. `(False, True, True)` -> domain is halted, device assigned to domain
80153
and required to start domain.
81154

155+
Note that if `required=True` then `automatically_attached=True`.
156+
157+
Conflicted Assignments
158+
----------------------
159+
160+
If a connected device has multiple assignments to different `frontend_domain`
161+
instances, the user will be asked to choose which domain connect the device to.
162+
If no GUI client is available, the device will not be connected to any domain.
163+
If multiple assignments exist for a connected device with different options but
164+
to the same `frontend_domain`, the most specific assignment will take
165+
precedence, according to the following order (from highest to lowest priority):
166+
#. Assignment specifies both `port` and `device_id`.
167+
#. Assignment specifies only the `port`.
168+
#. Assignment specifies only the `device_id`.
169+
170+
It is important to note that only one matching assignment can exist within
171+
each of the categories listed above.
172+
173+
Port Assignment
174+
---------------
175+
176+
It is possible to not assign a specific device but rather a port,
177+
(e.g., we can use the `--port` flag in the client). In this case,
178+
the value `*` will appear in the `identity` field of the `qubes.xml` file.
179+
This indicates that the identity presented by the devices will be ignored,
180+
and all connected devices will be automatically attached.
181+
82182

83183
PCI Devices
84184
-----------
85185

86186
PCI devices cannot be manually attached to a VM at any time.
87187
We must first create an assignment (`assign`) as required
88-
(in client we can use `--required` flag) while the VM is turned off.
89-
Then, it will be automatically attached upon each VM startup.
90-
However, if a PCI device is currently in use by another VM,
91-
the startup of the second VM will fail.
92-
PCI devices can only be assigned with the `required=True`, which does not
93-
allow for manual modification of the state during VM operation (attach/detach).
188+
(in client we can use `--required` flag). Then, it will be automatically
189+
attached upon each VM startup. However, if a PCI device is currently in use
190+
by another VM, the startup of the second VM will fail.
94191

95192
Microphone
96193
----------
97194

98-
The microphone cannot be assigned (potentially) to any VM (attempting to attach the microphone during VM startup fails).
195+
The microphone cannot be assigned with the `mode=required` to any VM.
99196

100-
Understanding Device Self Identity
101-
----------------------------------
102-
103-
It is important to understand that :py:class:`qubes.device_protocol.Port` does not
104-
correspond to the device itself, but rather to the *port* to which the device
105-
is connected. Therefore, when assigning a device to a VM, such as
106-
`sys-usb:1-1.1`, the port `1-1.1` is actually assigned, and thus
107-
*every* devices connected to it will be automatically attached.
108-
Similarly, when assigning `vm:sda`, every block device with the name `sda`
109-
will be automatically attached. We can limit this using :py:meth:`qubes.device_protocol.DeviceInfo.device_id`, which returns a string containing information
110-
presented by the device, such as, `vendor_id`, `product_id`, `serial_number`,
111-
and encoded interfaces. In the case of block devices, `device_id`
112-
consists of the parent port to which the device is connected (if any),
113-
the parent's `device_id`, and the interface/partition number.
114-
In practice, this means that, a partition on a USB drive will only be
115-
automatically attached to a frontend domain if the parent presents
116-
the correct serial number etc., and is connected to a specific port.
117-
118-
Port Assignment
119-
---------------
197+
USB Devices
198+
-----------
120199

121-
It is possible to not assign a specific device but rather a port,
122-
(e.g., we can use the `--port` flag in the client). In this case,
123-
the value `any` will appear in the `identity` field of the `qubes.xml` file.
124-
This indicates that the identity presented by the devices will be ignored,
125-
and all connected devices will be automatically attached. Note that to create
126-
an assignment, *any* device must currently be connected to the port.
200+
The USB devices cannot be assigned with the `mode=required` to any VM.
127201

128202

129203
.. automodule:: qubes.devices

0 commit comments

Comments
 (0)