Skip to content

Commit 6ca0e28

Browse files
committed
[ot] hw/opentitan: ot_usbdev: Implementation data transfers
This commit implements the logic to support data transfers and wire them in the server. The protocol is updated with commands to support this. Isochronous transfers are not properly supported at the moment. Signed-off-by: Amaury Pouly <[email protected]>
1 parent fd52f34 commit 6ca0e28

File tree

3 files changed

+1422
-104
lines changed

3 files changed

+1422
-104
lines changed

docs/opentitan/usbdev.md

Lines changed: 196 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
## `usbdev-cmd` Chardev
66

7-
The USBDEV driver exposes a chardev with ID `usbdev-cmd` which can used to control some aspects of the
8-
emulation.
7+
The USBDEV driver exposes a chardev with ID `usbdev-cmd` which can used to control some aspects of
8+
the emulation.
99
Once connected, the driver accepts textual commands.
1010
Each command must end with a newline.
1111
The following commands are recognized:
@@ -14,18 +14,21 @@ The following commands are recognized:
1414

1515
## `usbdev-host` Chardev
1616

17-
The USBDEV driver exposes a chardev with ID `usbdev-host` which can used to simulate the presence of
18-
a USB host. The implementation is such that the USBDEV behaves as a server, waiting for a connection
19-
from a virtual host. Once connected, the host and device exchange binary commands following the protocol
20-
described in the [host simulation](#host-simulation) section.
17+
The USBDEV driver exposes a chardev with ID `usbdev-host` which can used to simulate the presence
18+
of a USB host.
19+
The implementation is such that the USBDEV behaves as a server, waiting for a connection from a
20+
virtual host.
21+
Once connected, the host and device exchange binary commands following the protocol described in
22+
the [host simulation](#host-simulation) section.
2123

2224
## VBUS handling
2325

24-
On a real machine, the VBUS sense pin is usually connected to the VBUS connector so
25-
that the chip can detect when a cable is plugged in. For the purpose of emulation, a different
26-
approach needs to be taken. The driver supports two modes of operation which are controlled
27-
by the `vbus-override` property which can be set on the command-line by
28-
`-global ot-usbdev.vbus-override=<mode>`. The following modes are supported:
26+
On a real machine, the VBUS sense pin is usually connected to the VBUS connector so that the chip
27+
can detect when a cable is plugged in.
28+
For the purpose of emulation, a different approach needs to be taken. The driver supports two modes
29+
of operation which are controlled by the `vbus-override` property which can be set on the
30+
command-line by `-global ot-usbdev.vbus-override=<mode>`.
31+
The following modes are supported:
2932

3033
- `vbus-override=on`: in this mode, the VBUS sense pin is entirely managed over the `usbdev`
3134
chardev.
@@ -40,56 +43,68 @@ by the `vbus-override` property which can be set on the command-line by
4043
## Host simulation
4144

4245
The QEMU USBDEV driver only simulates a USB device controller (UDC) which requires the presence
43-
of a USB host. A (virtual) host exchanges messages with the UDC over the [`udev-host` chardev](#usbdev-host-chardev).
44-
This binary protocol is somewhat similar to the [USB/IP][usbip]
45-
protocol but lower level. This protocol is also different from the [USB network redirection (a.k.a usbredir)][usbredir]
46+
of a USB host.
47+
A (virtual) host exchanges messages with the UDC over the
48+
[`udev-host` chardev](#usbdev-host-chardev).
49+
This binary protocol is somewhat similar to the [USB/IP][usbip] protocol but lower level.
50+
This protocol is also different from the [USB network redirection (a.k.a usbredir)][usbredir]
4651
protocol supported by QEMU.
4752

4853
[usbip]: (https://docs.kernel.org/usb/usbip_protocol.html)
4954
[usbredir]: (https://gitlab.freedesktop.org/spice/usbredir/-/blob/main/docs/usb-redirection-protocol.md)
5055

5156
### Rationale for a different protocol
5257

53-
Both the USB/IP and usbredir protocols are too high-level for the purpose of emulating and testing a low-level
54-
UDC driver. For example, both protocols require that the device be fully enumerated and configured before the
55-
host is even made aware of its presence. In contrast, we want to be able to fully emulate the enumeration sequence.
56-
Another big difference is bus management: USB/IP does not support bus resets and usbredir does not support resume/suspend,
57-
and neither models VBUS. This is a side-effect of the intended use case of these protocols: to connect a real USB device
58-
to a virtual USB host. However, this new protocol should be low-level enough that it is possible to implement a
59-
bridge from either usbredir or USB/IP to this protocol (while losing some features).
58+
Both the USB/IP and usbredir protocols are too high-level for the purpose of emulating and testing
59+
a low-level UDC driver.
60+
For example, both protocols require that the device be fully enumerated and configured before the
61+
host is even made aware of its presence.
62+
In contrast, we want to be able to fully emulate the enumeration sequence.
63+
Another big difference is bus management: USB/IP does not support bus resets and usbredir does not
64+
support resume/suspend, and neither models VBUS.
65+
This is a side-effect of the intended use case of these protocols: to connect a real USB device to
66+
a virtual USB host.
67+
However, this new protocol should be low-level enough that it is possible to implement a bridge
68+
from either usbredir or USB/IP to this protocol (while losing some features).
6069

6170
### High-level overview
6271

6372
This protocol does not specify which of the device or the host should be the client/guest.
64-
On connection, the client must send a [`Hello` command](#hello-command), to which the server
65-
must respond with another `Hello` command. After that, messages are exchanged asynchronously.
73+
On connection, the client must send a [`Hello` command](#hello-command), to which the server must
74+
respond with another `Hello` command.
75+
After that, messages are exchanged asynchronously.
6676

6777
#### Bus states
6878

69-
The protocol reflects the low-level details of the USB bus and provides independent
70-
handling of VBUS (controlled by the host) and connection (controlled by the device).
71-
The host can turn VBUS on and off at any point. When VBUS is on, the device can freely
72-
connect or disconnect by asynchronously sending a message to the host. As on a real bus,
73-
turning off VBUS disconnects the device. VBUS is assumed to be initially off.
79+
The protocol reflects the low-level details of the USB bus and provides independent handling of
80+
VBUS (controlled by the host) and connection (controlled by the device).
81+
The host can turn VBUS on and off at any point. When VBUS is on, the device can freely connect or
82+
disconnect by asynchronously sending a message to the host.
83+
As on a real bus, turning off VBUS disconnects the device.
84+
VBUS is assumed to be initially off.
7485

7586
It is an error for the device to send a message when VBUS is not on and the host must ignore such
76-
messages. However due to the asynchronous nature of the protocol, it is possible for the host to
77-
receive a message event *after* sending a `VBUS Off` message which was sent *before* reception of
78-
this message by the device. The ID of the message makes it clear when this is the case so that
79-
the host can safely ignore those messages.
87+
messages.
88+
However due to the asynchronous nature of the protocol, it is possible for the host to receive a
89+
message event *after* sending a `VBUS Off` message which was sent *before* reception of this
90+
message by the device.
91+
The ID of the message makes it clear when this is the case so that the host can safely ignore those
92+
messages.
8093

81-
When VBUS is turned on, the host assumes that the device is *not* connected. The device must
82-
send a `Connect` message to notify the host.
94+
When VBUS is turned on, the host assumes that the device is *not* connected. The device must send
95+
a `Connect` message to notify the host.
8396

84-
While VBUS is turned on, the host can reset, suspend or resume the device. As on a real bus,
85-
the device will become unconfigured after a bus reset and an enumeration sequence must be performed.
97+
While VBUS is turned on, the host can reset, suspend or resume the device.
98+
As on a real bus, the device will become unconfigured after a bus reset and an enumeration sequence
99+
must be performed.
86100

87101
**TODO** Clarify suspend/resume
88102

89103
### Packet format
90104

91-
The protocol is based on packets which are exchanged asynchronously by the device and host. Each packet starts
92-
with a header followed by a payload. All fields are in little-endian.
105+
The protocol is based on packets which are exchanged asynchronously by the device and host.
106+
Each packet starts with a header followed by a payload.
107+
All fields are in little-endian.
93108

94109
| **Field** | **Offset** | **Size** | **Value** |
95110
| --------- | ---------- | -------- | --------- |
@@ -105,16 +120,19 @@ The following commands are defined.
105120
| **Command** | **Value** | **Direction** | **Description** | **Reference** |
106121
| ----------- | --------- | ------------- | --------------- | ------------- |
107122
| Invalid | 0 | N/A | To avoid 0 meaning something | |
108-
| Hello | 1 | Both | First packet sent when connecting | [`Hello` command](#hello-command) |
123+
| Hello | 1 | Both | First packet sent when connecting | [Hello command](#hello-command) |
109124
| VBUS On | 2 | Host to device | Turn VBUS on | [Bus commands](#bus-commands) |
110125
| VBUS Off | 3 | Host to device | Turn VBUS off | [Bus commands](#bus-commands) |
111126
| Connect | 4 | Device to host | Report device connection | [Bus commands](#bus-commands) |
112127
| Disconnect | 5 | Device to host | Report device disconnection | [Bus commands](#bus-commands) |
113128
| Reset | 6 | Host to device | Reset the device | [Bus commands](#bus-commands) |
114129
| Resume | 7 | Host to device | Resume the device | [Bus commands](#bus-commands) |
115130
| Suspend | 8 | Host to device | Suspend the device | [Bus commands](#bus-commands) |
131+
| Setup | 9 | Host to device | Send a SETUP packet | [Setup command](#setup-command) |
132+
| Transfer | 10 | Host to device | Start a transfer | [Transfer command](#transfer-command) |
133+
| Complete | 11 | Device to host | Complete a transfer | [Complete command](#complete-command) |
134+
116135

117-
**TODO** Add transfer commands
118136

119137
#### Hello command
120138

@@ -132,5 +150,141 @@ The payload of this command is defined as follows.
132150
These commands (VBUS On/Off, (Dis)connection, Reset, Suspend/Resume) do not have any payload.
133151
See the [bus states](#bus-states) section for more detail.
134152

135-
For the Connect/Disconnect commands, which are sent by the device, the ID should be the ID of the *last command*
136-
processed by the device.
153+
For the Connect/Disconnect commands, which are sent by the device, the ID should be the ID of the
154+
*last command* processed by the device.
155+
156+
Sending a `Reset`, `VBUS Off` or `Suspend` command to the device automatically cancels any pending
157+
`Transfer` command.
158+
The device *may* send a `Complete` event with the `Cancelled` status for such transfers.
159+
160+
#### Setup command
161+
162+
This command is used to send a SETUP packet to the device.
163+
The payload of this command starts with a header defined as follows.
164+
See [Transfer handling](#transfer-handling) for more details.
165+
166+
| **Field** | **Offset** | **Size** | **Value** |
167+
| --------- | ---------- | -------- | --------- |
168+
| Address | 0 | 1 | Device address |
169+
| Endpoint | 1 | 1 | Endpoint number |
170+
| Reserved | 2 | 2 | Set to zero |
171+
| Setup | 4 | 8 | SETUP packet |
172+
173+
Sending a `Setup` command to an endpoint automatically cancels any pending transfer on this
174+
endpoint.
175+
The device *may* send a `Complete` event to the host with the `Cancelled` status.
176+
177+
#### Transfer command
178+
179+
This command is used to start a transfer to or from the device.
180+
See [Transfer handling](#transfer-handling) for more details.
181+
The payload of this command is defined below.
182+
183+
| **Field** | **Offset** | **Size** | **Value** |
184+
| --------- | ---------- | -------- | --------- |
185+
| Address | 0 | 1 | Device address |
186+
| Endpoint | 1 | 1 | Endpoint (see below) |
187+
| Packet Size | 2 | 2 | Packet size (see [Transfer handling](#transfer-handling)) |
188+
| Flags | 4 | 1 | Transfer flags (see below) |
189+
| Reserved | 5 | 3 | Set to 0 |
190+
| Transfer Size | 8 | 4 | Size of the data |
191+
| Data | 12 | variable | Transfer data (see below) |
192+
193+
The `Endpoint` field is encoded as follows:
194+
| **Field** | **Bits** | **Value** |
195+
| --------- | -------- | -------- |
196+
| EP Number | 3:0 | The endpoint number |
197+
| Reserved | 6:4 | Set to 0 |
198+
| Direction | 7 | Set to 1 for IN endpoint and 0 for OUT endpoint |
199+
200+
Note that when submitting a control transfer, the `Direction` field must be set to indicate whether
201+
this is control OUT or IN transaction.
202+
203+
The following flags are defined.
204+
205+
| **Flag** | **Bit** | **Meaning** |
206+
| -------- | ------- | ----------- |
207+
| ZLP | 0 | A zero-length packet must be sent after the data (only valid for OUT transfers) |
208+
209+
For OUT transfers, the `Transfer Size` field indicates the size of the data in the payload after
210+
the header.
211+
For IN transfers, the `Transfer Size` field indicates the maximum size of the transfers to return
212+
to the host.
213+
214+
Sending a `Transfer` command to an endpoint while one is already in progress is an error.
215+
The device must immediately reply with a `Complete` event with the `Error` status.
216+
217+
#### Complete command
218+
219+
The ID of this command must be the ID of the corresponding `Transfer` command.
220+
See [Transfer handling](#transfer-handling) for more details.
221+
The payload of this command is defined as follows.
222+
223+
| **Field** | **Offset** | **Size** | **Value** |
224+
| --------- | ---------- | -------- | --------- |
225+
| Status | 0 | 1 | Status of the transfer (see below) |
226+
| Reserved | 1 | 3 | Set to 0 |
227+
| Transfer Size | 4 | 4 | Amount of data transferred |
228+
| Data | 8 | variable | Transfer data (see below) |
229+
230+
The `Transfer Size` field indicates the size of the data.
231+
The data must only be present when completing an IN transaction.
232+
233+
The following status codes are defined:
234+
235+
| **Status** | **Value** | **Meaning** |
236+
| -------- | ------- | ----------- |
237+
| Success | 0 | The data was successfully transferred |
238+
| Stalled | 1 | The device stalled the transfer |
239+
| Cancelled | 2 | Transfer was cancelled (see below) |
240+
| Error | 3 | An unspecified error occurred |
241+
242+
A transfer may be cancelled by any bus event such a turning VBUS off, the device disconnecting,
243+
the host resetting or suspending the device, or the host sending a `Setup` command.
244+
245+
246+
### Transfer handling
247+
248+
In order to perform data transfers, the host must send a correct sequence of Setup and Data
249+
commands, in accordance to the USB specification.
250+
The protocol is designed to be very low-level and only provides minimal help.
251+
The host is allowed to send non-spec compliant sequences to fuzz the device.
252+
For properly sequenced transfers, the host should follow the guidelines below.
253+
254+
Note that the `Transfer` command allows the host to send/receive more data than the indicated
255+
packet size.
256+
In this case, the transfer will automatically be split into multiple packets of size `Packet Size`.
257+
For OUT transfers, all packets except possibly the last one will be of the size indicated in the
258+
command.
259+
For IN transfers, the transfer stops as soon as a short packet is received (packet of size less
260+
than the one indicated in the command).
261+
If the `ZLP` flag is set for an OUT transfer, the device will additionally receive a zero-length
262+
packet.
263+
If at any point during this sequence, the device stalls the transfer, the transfer stops and the
264+
device must send a `Complete` event to the host with the `Stalled` status and the `Size` field
265+
indicating how much data was transferred successfully (and for IN transfers, the data must be
266+
present in the payload).
267+
If the transfer succeeds, the device must send a `Complete` event with the `Success` status, the
268+
`Size` field indicating how much data was transferred successfully (and for IN transfers, the data
269+
must be present in the payload).
270+
271+
### Control transfers
272+
273+
The host should first send a `Setup` command at the selected address and endpoint.
274+
The device does not reply to this command. Note that the USB specification specifies that sending
275+
a SETUP packet to an endpoint immediately cancels any transaction on this endpoint.
276+
The device *may* send a `Complete` events for such transfers with the `Cancelled` status.
277+
278+
The rest of the sequence depends on the direction of the transfer:
279+
- OUT transfers: the host should send one or more `Transfer` commands to the endpoint
280+
(with the OUT direction) with the control data.
281+
Once all transfers are complete, the host should send a `Transfer` command to the endpoint
282+
with the IN direction and `Size` set to 0.
283+
- IN transfers: the host should send one or more `Transfer` commands to the endpoint,
284+
(with the IN direction) to receive the control data.
285+
Once all transfers are complete, the host should send a `Transfer` command to the endpoint
286+
with the OUT direction and `Size` set to 0.
287+
288+
### Bulk and interrupt transfers
289+
290+
TODO

0 commit comments

Comments
 (0)