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