-
Notifications
You must be signed in to change notification settings - Fork 907
[opentitanlib,qemu] Implement a minimal USB host #28644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: earlgrey_1.0.0
Are you sure you want to change the base?
Conversation
72627ae to
ab4ed95
Compare
This virtual host talks to the QEMU usbdev driver. At the moment, this host perform the initial handshake, turns on vbus, waits for a device connection and retrieve the device descriptor. Signed-off-by: Amaury Pouly <[email protected]>
ab4ed95 to
5fcbb86
Compare
| } | ||
|
|
||
| /// This structure records a complete event received from QEMU on the chardev. | ||
| /// The complete payload is parsed and the received data in stored as-is. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /// The complete payload is parsed and the received data in stored as-is. | |
| /// The complete payload is parsed and the received data is stored as-is. |
| #[allow(clippy::too_many_arguments)] | ||
| fn send_control_in( | ||
| &mut self, | ||
| addr: u8, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: it's not very important, but I wonder if it would be possible to refactor to reduce the number of arguments being passed in here and to a couple of other functions. It's quite hard to follow from reading it.
| Ok(QemuUsbdevEvent { cmd, id, data }) => { | ||
| ensure!( | ||
| cmd == QemuUsbdevCmd::Hello, | ||
| "Expected an HELLO event, got {cmd:?}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| "Expected an HELLO event, got {cmd:?}" | |
| "Expected a HELLO event, got {cmd:?}" |
| ); | ||
| ensure!( | ||
| payload.magic == Self::USBDEV_HELLO_MAGIC, | ||
| "HELLO payload has the wrong magic bytes" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: maybe dump the incorrect magic bytes here to help debugging?
| fn wait_connect(&mut self) -> anyhow::Result<WaitResult<u32>> { | ||
| Ok(match self.wait_qemu_event()? { | ||
| Ok(QemuUsbdevEvent { cmd, id, data }) => { | ||
| // If device was previously disconnect, the only valid event that the device |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // If device was previously disconnect, the only valid event that the device | |
| // If the device was previously disconnected, the only valid event that the device |
|
|
||
| /// Perform a full enumeration sequence, retrieving the | ||
| /// device and config descriptors, as well as assigning | ||
| /// an address to the device. If the device fails to enumetate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /// an address to the device. If the device fails to enumetate | |
| /// an address to the device. If the device fails to enumerate |
| // HACK Wait for a while. This should really be done in QEMU to emulate the reset. | ||
| std::thread::sleep(std::time::Duration::from_millis(100)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question on this hack (maybe it could be added to the comment) - why do we have to add this delay? Is this to give QEMU time to reset, or is it expected by the host, or is there some other reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment resets are handled as zero-time events on the QEMU side. This is problematic because if you send a reset followed by a SETUP then you could end up with the SW having both reset and rx interrupts set. The SW has no way to know in which order they arrived and has to assume that the reset happened afterwards (this is because a bus reset takes several milliseconds on a real bus) which messes up with the transfer.
The real solution is to emulate the reset properly in QEMU (which will be done eventually) but this hack avoids the issue above.
| const USB_DEVICE_DESCRIPTOR_LENGTH: usize = 18; | ||
|
|
||
| // Location of the bMaxPacketSize field in the device descriptor. | ||
| const USV_DEV_DESC_MAX_PACKET_SIZE_OFFSET: usize = 7; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| const USV_DEV_DESC_MAX_PACKET_SIZE_OFFSET: usize = 7; | |
| const USB_DEV_DESC_MAX_PACKET_SIZE_OFFSET: usize = 7; |
| } | ||
|
|
||
| /// This thread simulates a USB host. It can react to events sent by otlib | ||
| /// other the channel. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| /// other the channel. | |
| /// over the channel. |
?
| // We spawn a thread just to listen to events send by QEMU USBDEV. | ||
| // Those will be sent to the same channel used otlib to gives us |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // We spawn a thread just to listen to events send by QEMU USBDEV. | |
| // Those will be sent to the same channel used otlib to gives us | |
| // We spawn a thread just to listen to events sent by QEMU USBDEV. | |
| // Those will be sent to the same channel otlib uses to gives us |
This virtual host talks to the QEMU usbdev driver. At the moment, this host perform the initial handshake, turns on vbus, waits for a device connection and retrieve the device descriptor.
This host is not super useful in its current state and will be extended in future PRs but it is already quite a large piece of work and it's good state to stop.