• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! Rust wrapper for `GBL_EFI_FASTBOOT_USB_PROTOCOL`.
16 
17 use crate::{
18     protocol::{Protocol, ProtocolInfo},
19     utils::with_timeout,
20     {efi_call, Event},
21 };
22 use core::time::Duration;
23 use efi_types::{EfiGuid, GblEfiFastbootUsbProtocol};
24 use gbl_async::yield_now;
25 use liberror::{Error, Result};
26 
27 /// GBL_EFI_FASTBOOT_USB_PROTOCOL
28 pub struct GblFastbootUsbProtocol;
29 
30 impl ProtocolInfo for GblFastbootUsbProtocol {
31     type InterfaceType = GblEfiFastbootUsbProtocol;
32 
33     const GUID: EfiGuid =
34         EfiGuid::new(0x6281a893, 0xac23, 0x4ca7, [0xb2, 0x81, 0x34, 0x0e, 0xf8, 0x16, 0x89, 0x55]);
35 }
36 
37 // Protocol interface wrappers.
38 impl Protocol<'_, GblFastbootUsbProtocol> {
39     /// Wrapper of `GBL_EFI_FASTBOOT_USB_PROTOCOL.fastboot_usb_interface_start()`
fastboot_usb_interface_start(&self) -> Result<usize>40     pub fn fastboot_usb_interface_start(&self) -> Result<usize> {
41         let mut max_packet_size = 0;
42         // SAFETY:
43         // `self.interface()?` guarantees self.interface is non-null and points to a valid object
44         // established by `Protocol::new()`.
45         // `self.interface` and `max_packet_size` are input/output parameters, outlive the call and
46         // will not be retained.
47         unsafe {
48             efi_call!(
49                 self.interface()?.fastboot_usb_interface_start,
50                 self.interface,
51                 &mut max_packet_size,
52             )?;
53         }
54         Ok(max_packet_size)
55     }
56 
57     /// Wrapper of `GBL_EFI_FASTBOOT_USB_PROTOCOL.fastboot_usb_interface_stop()`
fastboot_usb_interface_stop(&self) -> Result<()>58     pub fn fastboot_usb_interface_stop(&self) -> Result<()> {
59         // SAFETY:
60         // `self.interface()?` guarantees self.interface is non-null and points to a valid object
61         // established by `Protocol::new()`.
62         // `self.interface` is input parameter, outlives the call, and will not be retained.
63         unsafe { efi_call!(self.interface()?.fastboot_usb_interface_stop, self.interface,) }
64     }
65 
66     /// Wrapper of `GBL_EFI_FASTBOOT_USB_PROTOCOL.fastboot_usb_receive()`
fastboot_usb_receive(&self, out: &mut [u8]) -> Result<usize>67     pub fn fastboot_usb_receive(&self, out: &mut [u8]) -> Result<usize> {
68         let mut out_size = out.len();
69         // SAFETY:
70         // `self.interface()?` guarantees self.interface is non-null and points to a valid object
71         // established by `Protocol::new()`.
72         // `self.interface`, `out_size` and `buffer` are input/output parameters, outlive the call
73         // and will not be retained.
74         unsafe {
75             efi_call!(
76                 @bufsize out_size,
77                 self.interface()?.fastboot_usb_receive,
78                 self.interface,
79                 &mut out_size,
80                 out.as_mut_ptr() as _,
81             )?;
82         }
83 
84         Ok(out_size)
85     }
86 
87     /// Wrapper of `GBL_EFI_FASTBOOT_USB_PROTOCOL.fastboot_usb_send()`
fastboot_usb_send(&self, data: &[u8]) -> Result<usize>88     pub fn fastboot_usb_send(&self, data: &[u8]) -> Result<usize> {
89         let mut out_size = data.len();
90         // SAFETY:
91         // `self.interface()?` guarantees self.interface is non-null and points to a valid object
92         // established by `Protocol::new()`.
93         // `self.interface`, `out_size` and `buffer` are input/output parameters, outlive the call
94         // and will not be retained.
95         unsafe {
96             efi_call!(
97                 @bufsize out_size,
98                 self.interface()?.fastboot_usb_send,
99                 self.interface,
100                 &mut out_size,
101                 data.as_ptr() as _,
102             )?;
103         }
104 
105         Ok(out_size)
106     }
107 
108     /// Returns the `GBL_EFI_FASTBOOT_USB_PROTOCOL.wait_for_send_completion` EFI event.
wait_for_send_completion(&self) -> Result<Event>109     pub fn wait_for_send_completion(&self) -> Result<Event> {
110         Ok(Event::new_unowned(self.interface()?.wait_for_send_completion))
111     }
112 
113     /// Receives the next packet from the USB.
receive_packet(&self, out: &mut [u8]) -> Result<usize>114     pub async fn receive_packet(&self, out: &mut [u8]) -> Result<usize> {
115         loop {
116             match self.fastboot_usb_receive(out) {
117                 Ok(out_size) => return Ok(out_size),
118                 Err(Error::NotReady) => yield_now().await,
119                 Err(e) => return Err(e),
120             }
121         }
122     }
123 
124     /// A helper to wait for the send event to signal.
wait_send(&self) -> Result<()>125     async fn wait_send(&self) -> Result<()> {
126         let bs = self.efi_entry().system_table().boot_services();
127         while !bs.check_event(&self.wait_for_send_completion()?)? {
128             yield_now().await;
129         }
130         Ok(())
131     }
132 
133     /// Sends a packet over the USB.
send_packet(&self, data: &[u8], timeout: Duration) -> Result<()>134     pub async fn send_packet(&self, data: &[u8], timeout: Duration) -> Result<()> {
135         self.fastboot_usb_send(data)?;
136         with_timeout(self.efi_entry(), self.wait_send(), timeout).await?.ok_or(Error::Timeout)?
137     }
138 }
139