1*5225e6b1SAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project 2*5225e6b1SAndroid Build Coastguard Worker // 3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at 6*5225e6b1SAndroid Build Coastguard Worker // 7*5225e6b1SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0 8*5225e6b1SAndroid Build Coastguard Worker // 9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License. 14*5225e6b1SAndroid Build Coastguard Worker 15*5225e6b1SAndroid Build Coastguard Worker use crate::fastboot::PinFutContainerTyped; 16*5225e6b1SAndroid Build Coastguard Worker use crate::{ 17*5225e6b1SAndroid Build Coastguard Worker fastboot::{BufferPool, GblFastboot}, 18*5225e6b1SAndroid Build Coastguard Worker GblOps, 19*5225e6b1SAndroid Build Coastguard Worker }; 20*5225e6b1SAndroid Build Coastguard Worker use core::{ffi::CStr, fmt::Write, future::Future, ops::DerefMut, str::from_utf8}; 21*5225e6b1SAndroid Build Coastguard Worker use fastboot::{next_arg, next_arg_u64, snprintf, CommandResult, FormattedBytes, VarInfoSender}; 22*5225e6b1SAndroid Build Coastguard Worker use gbl_async::{block_on, select, yield_now}; 23*5225e6b1SAndroid Build Coastguard Worker use gbl_storage::BlockIo; 24*5225e6b1SAndroid Build Coastguard Worker 25*5225e6b1SAndroid Build Coastguard Worker // See definition of [GblFastboot] for docs on lifetimes and generics parameters. 26*5225e6b1SAndroid Build Coastguard Worker impl<'a: 'c, 'b: 'c, 'c, 'd, 'e, G, B, S, T, P, C, F> 27*5225e6b1SAndroid Build Coastguard Worker GblFastboot<'a, 'b, 'c, 'd, 'e, G, B, S, T, P, C, F> 28*5225e6b1SAndroid Build Coastguard Worker where 29*5225e6b1SAndroid Build Coastguard Worker G: GblOps<'a, 'e>, 30*5225e6b1SAndroid Build Coastguard Worker B: BlockIo, 31*5225e6b1SAndroid Build Coastguard Worker S: DerefMut<Target = [u8]>, 32*5225e6b1SAndroid Build Coastguard Worker T: DerefMut<Target = [u8]>, 33*5225e6b1SAndroid Build Coastguard Worker P: BufferPool, 34*5225e6b1SAndroid Build Coastguard Worker C: PinFutContainerTyped<'c, F>, 35*5225e6b1SAndroid Build Coastguard Worker F: Future<Output = ()> + 'c, 36*5225e6b1SAndroid Build Coastguard Worker { 37*5225e6b1SAndroid Build Coastguard Worker const VERSION_BOOTLOADER: &'static str = "version-bootloader"; 38*5225e6b1SAndroid Build Coastguard Worker const VERSION_BOOTLOADER_VAL: &'static str = "1.0"; 39*5225e6b1SAndroid Build Coastguard Worker 40*5225e6b1SAndroid Build Coastguard Worker const MAX_FETCH_SIZE: &'static str = "max-fetch-size"; 41*5225e6b1SAndroid Build Coastguard Worker const MAX_FETCH_SIZE_VAL: &'static str = "0xffffffffffffffff"; 42*5225e6b1SAndroid Build Coastguard Worker 43*5225e6b1SAndroid Build Coastguard Worker /// Entry point for "fastboot getvar <variable>..." get_var_internal<'s, 't>( &mut self, name: &CStr, args: impl Iterator<Item = &'t CStr> + Clone, out: &'s mut [u8], ) -> CommandResult<&'s str>44*5225e6b1SAndroid Build Coastguard Worker pub(crate) fn get_var_internal<'s, 't>( 45*5225e6b1SAndroid Build Coastguard Worker &mut self, 46*5225e6b1SAndroid Build Coastguard Worker name: &CStr, 47*5225e6b1SAndroid Build Coastguard Worker args: impl Iterator<Item = &'t CStr> + Clone, 48*5225e6b1SAndroid Build Coastguard Worker out: &'s mut [u8], 49*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<&'s str> { 50*5225e6b1SAndroid Build Coastguard Worker let args_str = args.clone().map(|v| v.to_str()); 51*5225e6b1SAndroid Build Coastguard Worker // Checks that all arguments are valid str first. 52*5225e6b1SAndroid Build Coastguard Worker args_str.clone().find(|v| v.is_err()).unwrap_or(Ok(""))?; 53*5225e6b1SAndroid Build Coastguard Worker let args_str = args_str.map(|v| v.unwrap()); 54*5225e6b1SAndroid Build Coastguard Worker Ok(match name.to_str()? { 55*5225e6b1SAndroid Build Coastguard Worker Self::VERSION_BOOTLOADER => snprintf!(out, "{}", Self::VERSION_BOOTLOADER_VAL), 56*5225e6b1SAndroid Build Coastguard Worker Self::MAX_FETCH_SIZE => snprintf!(out, "{}", Self::MAX_FETCH_SIZE_VAL), 57*5225e6b1SAndroid Build Coastguard Worker Self::PARTITION_SIZE => self.get_var_partition_size(args_str, out)?, 58*5225e6b1SAndroid Build Coastguard Worker Self::PARTITION_TYPE => self.get_var_partition_type(args_str, out)?, 59*5225e6b1SAndroid Build Coastguard Worker Self::BLOCK_DEVICE => self.get_var_block_device(args_str, out)?, 60*5225e6b1SAndroid Build Coastguard Worker Self::DEFAULT_BLOCK => self.get_var_default_block(out)?, 61*5225e6b1SAndroid Build Coastguard Worker _ => { 62*5225e6b1SAndroid Build Coastguard Worker let sz = self.gbl_ops.fastboot_variable(name, args, out)?; 63*5225e6b1SAndroid Build Coastguard Worker from_utf8(out.get(..sz).ok_or("Invalid variable value size")?)? 64*5225e6b1SAndroid Build Coastguard Worker } 65*5225e6b1SAndroid Build Coastguard Worker }) 66*5225e6b1SAndroid Build Coastguard Worker } 67*5225e6b1SAndroid Build Coastguard Worker 68*5225e6b1SAndroid Build Coastguard Worker /// Entry point for "fastboot getvar all..." get_var_all_internal( &mut self, send: &mut impl VarInfoSender, ) -> CommandResult<()>69*5225e6b1SAndroid Build Coastguard Worker pub(crate) async fn get_var_all_internal( 70*5225e6b1SAndroid Build Coastguard Worker &mut self, 71*5225e6b1SAndroid Build Coastguard Worker send: &mut impl VarInfoSender, 72*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<()> { 73*5225e6b1SAndroid Build Coastguard Worker send.send_var_info(Self::VERSION_BOOTLOADER, [], Self::VERSION_BOOTLOADER_VAL).await?; 74*5225e6b1SAndroid Build Coastguard Worker send.send_var_info(Self::MAX_FETCH_SIZE, [], Self::MAX_FETCH_SIZE_VAL).await?; 75*5225e6b1SAndroid Build Coastguard Worker self.get_all_block_device(send).await?; 76*5225e6b1SAndroid Build Coastguard Worker let mut buf = [0u8; 32]; 77*5225e6b1SAndroid Build Coastguard Worker send.send_var_info(Self::DEFAULT_BLOCK, [], self.get_var_default_block(&mut buf)?).await?; 78*5225e6b1SAndroid Build Coastguard Worker self.get_all_partition_size_type(send).await?; 79*5225e6b1SAndroid Build Coastguard Worker 80*5225e6b1SAndroid Build Coastguard Worker // Gets platform specific variables 81*5225e6b1SAndroid Build Coastguard Worker let tasks = self.tasks(); 82*5225e6b1SAndroid Build Coastguard Worker Ok(self.gbl_ops.fastboot_visit_all_variables(|args, val| { 83*5225e6b1SAndroid Build Coastguard Worker if let Some((name, args)) = args.split_first_chunk::<1>() { 84*5225e6b1SAndroid Build Coastguard Worker let name = name[0].to_str().unwrap_or("?"); 85*5225e6b1SAndroid Build Coastguard Worker let args = args.iter().map(|v| v.to_str().unwrap_or("?")); 86*5225e6b1SAndroid Build Coastguard Worker let val = val.to_str().unwrap_or("?"); 87*5225e6b1SAndroid Build Coastguard Worker // Manually polls async tasks so that we can still get parallelism while running in 88*5225e6b1SAndroid Build Coastguard Worker // the context of backend. 89*5225e6b1SAndroid Build Coastguard Worker let _ = block_on(select(send.send_var_info(name, args, val), async { 90*5225e6b1SAndroid Build Coastguard Worker loop { 91*5225e6b1SAndroid Build Coastguard Worker tasks.borrow_mut().poll_all(); 92*5225e6b1SAndroid Build Coastguard Worker yield_now().await; 93*5225e6b1SAndroid Build Coastguard Worker } 94*5225e6b1SAndroid Build Coastguard Worker })); 95*5225e6b1SAndroid Build Coastguard Worker } 96*5225e6b1SAndroid Build Coastguard Worker })?) 97*5225e6b1SAndroid Build Coastguard Worker } 98*5225e6b1SAndroid Build Coastguard Worker 99*5225e6b1SAndroid Build Coastguard Worker const PARTITION_SIZE: &'static str = "partition-size"; 100*5225e6b1SAndroid Build Coastguard Worker const PARTITION_TYPE: &'static str = "partition-type"; 101*5225e6b1SAndroid Build Coastguard Worker 102*5225e6b1SAndroid Build Coastguard Worker /// "fastboot getvar partition-size" get_var_partition_size<'s, 't>( &mut self, mut args: impl Iterator<Item = &'t str> + Clone, out: &'s mut [u8], ) -> CommandResult<&'s str>103*5225e6b1SAndroid Build Coastguard Worker fn get_var_partition_size<'s, 't>( 104*5225e6b1SAndroid Build Coastguard Worker &mut self, 105*5225e6b1SAndroid Build Coastguard Worker mut args: impl Iterator<Item = &'t str> + Clone, 106*5225e6b1SAndroid Build Coastguard Worker out: &'s mut [u8], 107*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<&'s str> { 108*5225e6b1SAndroid Build Coastguard Worker let (_, _, _, sz) = self.parse_partition(args.next().ok_or("Missing partition")?)?; 109*5225e6b1SAndroid Build Coastguard Worker Ok(snprintf!(out, "{:#x}", sz)) 110*5225e6b1SAndroid Build Coastguard Worker } 111*5225e6b1SAndroid Build Coastguard Worker 112*5225e6b1SAndroid Build Coastguard Worker /// "fastboot getvar partition-type" get_var_partition_type<'s, 't>( &mut self, mut args: impl Iterator<Item = &'t str> + Clone, out: &'s mut [u8], ) -> CommandResult<&'s str>113*5225e6b1SAndroid Build Coastguard Worker fn get_var_partition_type<'s, 't>( 114*5225e6b1SAndroid Build Coastguard Worker &mut self, 115*5225e6b1SAndroid Build Coastguard Worker mut args: impl Iterator<Item = &'t str> + Clone, 116*5225e6b1SAndroid Build Coastguard Worker out: &'s mut [u8], 117*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<&'s str> { 118*5225e6b1SAndroid Build Coastguard Worker self.parse_partition(args.next().ok_or("Missing partition")?)?; 119*5225e6b1SAndroid Build Coastguard Worker Ok(snprintf!(out, "raw")) 120*5225e6b1SAndroid Build Coastguard Worker } 121*5225e6b1SAndroid Build Coastguard Worker 122*5225e6b1SAndroid Build Coastguard Worker /// Gets all "partition-size/partition-type" get_all_partition_size_type( &mut self, responder: &mut impl VarInfoSender, ) -> CommandResult<()>123*5225e6b1SAndroid Build Coastguard Worker async fn get_all_partition_size_type( 124*5225e6b1SAndroid Build Coastguard Worker &mut self, 125*5225e6b1SAndroid Build Coastguard Worker responder: &mut impl VarInfoSender, 126*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<()> { 127*5225e6b1SAndroid Build Coastguard Worker // Though any sub range of a GPT partition or raw block counts as a partition in GBL 128*5225e6b1SAndroid Build Coastguard Worker // Fastboot, for "getvar all" we only enumerate whole range GPT partitions. 129*5225e6b1SAndroid Build Coastguard Worker let disks = self.disks; 130*5225e6b1SAndroid Build Coastguard Worker let mut size_str = [0u8; 32]; 131*5225e6b1SAndroid Build Coastguard Worker for (idx, blk) in disks.iter().enumerate() { 132*5225e6b1SAndroid Build Coastguard Worker for ptn_idx in 0..blk.num_partitions().unwrap_or(0) { 133*5225e6b1SAndroid Build Coastguard Worker let ptn = blk.get_partition_by_idx(ptn_idx)?; 134*5225e6b1SAndroid Build Coastguard Worker let sz: u64 = ptn.size()?; 135*5225e6b1SAndroid Build Coastguard Worker let part = ptn.name()?; 136*5225e6b1SAndroid Build Coastguard Worker // Assumes max partition name length of 72 plus max u64 hex string length 18. 137*5225e6b1SAndroid Build Coastguard Worker let mut part_id_buf = [0u8; 128]; 138*5225e6b1SAndroid Build Coastguard Worker let part = snprintf!(part_id_buf, "{}/{:x}", part, idx); 139*5225e6b1SAndroid Build Coastguard Worker responder 140*5225e6b1SAndroid Build Coastguard Worker .send_var_info(Self::PARTITION_SIZE, [part], snprintf!(size_str, "{:#x}", sz)) 141*5225e6b1SAndroid Build Coastguard Worker .await?; 142*5225e6b1SAndroid Build Coastguard Worker // Image type is not supported yet. 143*5225e6b1SAndroid Build Coastguard Worker responder 144*5225e6b1SAndroid Build Coastguard Worker .send_var_info(Self::PARTITION_TYPE, [part], snprintf!(size_str, "raw")) 145*5225e6b1SAndroid Build Coastguard Worker .await?; 146*5225e6b1SAndroid Build Coastguard Worker } 147*5225e6b1SAndroid Build Coastguard Worker } 148*5225e6b1SAndroid Build Coastguard Worker Ok(()) 149*5225e6b1SAndroid Build Coastguard Worker } 150*5225e6b1SAndroid Build Coastguard Worker 151*5225e6b1SAndroid Build Coastguard Worker const BLOCK_DEVICE: &'static str = "block-device"; 152*5225e6b1SAndroid Build Coastguard Worker const TOTAL_BLOCKS: &'static str = "total-blocks"; 153*5225e6b1SAndroid Build Coastguard Worker const BLOCK_SIZE: &'static str = "block-size"; 154*5225e6b1SAndroid Build Coastguard Worker const BLOCK_DEVICE_STATUS: &'static str = "status"; 155*5225e6b1SAndroid Build Coastguard Worker 156*5225e6b1SAndroid Build Coastguard Worker /// Block device related information. 157*5225e6b1SAndroid Build Coastguard Worker /// 158*5225e6b1SAndroid Build Coastguard Worker /// `fastboot getvar block-device:<id>:total-blocks` 159*5225e6b1SAndroid Build Coastguard Worker /// `fastboot getvar block-device:<id>:block-size` 160*5225e6b1SAndroid Build Coastguard Worker /// `fastboot getvar block-device:<id>:status` get_var_block_device<'s, 't>( &mut self, mut args: impl Iterator<Item = &'t str> + Clone, out: &'s mut [u8], ) -> CommandResult<&'s str>161*5225e6b1SAndroid Build Coastguard Worker fn get_var_block_device<'s, 't>( 162*5225e6b1SAndroid Build Coastguard Worker &mut self, 163*5225e6b1SAndroid Build Coastguard Worker mut args: impl Iterator<Item = &'t str> + Clone, 164*5225e6b1SAndroid Build Coastguard Worker out: &'s mut [u8], 165*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<&'s str> { 166*5225e6b1SAndroid Build Coastguard Worker let id = next_arg_u64(&mut args)?.ok_or("Missing block device ID")?; 167*5225e6b1SAndroid Build Coastguard Worker let id = usize::try_from(id)?; 168*5225e6b1SAndroid Build Coastguard Worker let val_type = next_arg(&mut args).ok_or("Missing value type")?; 169*5225e6b1SAndroid Build Coastguard Worker let blk = &self.disks[id]; 170*5225e6b1SAndroid Build Coastguard Worker let info = blk.block_info(); 171*5225e6b1SAndroid Build Coastguard Worker Ok(match val_type { 172*5225e6b1SAndroid Build Coastguard Worker Self::TOTAL_BLOCKS => snprintf!(out, "{:#x}", info.num_blocks), 173*5225e6b1SAndroid Build Coastguard Worker Self::BLOCK_SIZE => snprintf!(out, "{:#x}", info.block_size), 174*5225e6b1SAndroid Build Coastguard Worker Self::BLOCK_DEVICE_STATUS => { 175*5225e6b1SAndroid Build Coastguard Worker snprintf!(out, "{}", blk.status().to_str()) 176*5225e6b1SAndroid Build Coastguard Worker } 177*5225e6b1SAndroid Build Coastguard Worker _ => return Err("Invalid type".into()), 178*5225e6b1SAndroid Build Coastguard Worker }) 179*5225e6b1SAndroid Build Coastguard Worker } 180*5225e6b1SAndroid Build Coastguard Worker 181*5225e6b1SAndroid Build Coastguard Worker /// Gets all "block-device" variables. get_all_block_device( &mut self, responder: &mut impl VarInfoSender, ) -> CommandResult<()>182*5225e6b1SAndroid Build Coastguard Worker async fn get_all_block_device( 183*5225e6b1SAndroid Build Coastguard Worker &mut self, 184*5225e6b1SAndroid Build Coastguard Worker responder: &mut impl VarInfoSender, 185*5225e6b1SAndroid Build Coastguard Worker ) -> CommandResult<()> { 186*5225e6b1SAndroid Build Coastguard Worker let mut val = [0u8; 32]; 187*5225e6b1SAndroid Build Coastguard Worker for (idx, blk) in self.gbl_ops.disks().iter().enumerate() { 188*5225e6b1SAndroid Build Coastguard Worker let mut id_str = [0u8; 32]; 189*5225e6b1SAndroid Build Coastguard Worker let id = snprintf!(id_str, "{:x}", idx); 190*5225e6b1SAndroid Build Coastguard Worker let info = blk.block_info(); 191*5225e6b1SAndroid Build Coastguard Worker responder 192*5225e6b1SAndroid Build Coastguard Worker .send_var_info( 193*5225e6b1SAndroid Build Coastguard Worker Self::BLOCK_DEVICE, 194*5225e6b1SAndroid Build Coastguard Worker [id, Self::TOTAL_BLOCKS], 195*5225e6b1SAndroid Build Coastguard Worker snprintf!(val, "{:#x}", info.num_blocks), 196*5225e6b1SAndroid Build Coastguard Worker ) 197*5225e6b1SAndroid Build Coastguard Worker .await?; 198*5225e6b1SAndroid Build Coastguard Worker responder 199*5225e6b1SAndroid Build Coastguard Worker .send_var_info( 200*5225e6b1SAndroid Build Coastguard Worker Self::BLOCK_DEVICE, 201*5225e6b1SAndroid Build Coastguard Worker [id, Self::BLOCK_SIZE], 202*5225e6b1SAndroid Build Coastguard Worker snprintf!(val, "{:#x}", info.block_size), 203*5225e6b1SAndroid Build Coastguard Worker ) 204*5225e6b1SAndroid Build Coastguard Worker .await?; 205*5225e6b1SAndroid Build Coastguard Worker responder 206*5225e6b1SAndroid Build Coastguard Worker .send_var_info( 207*5225e6b1SAndroid Build Coastguard Worker Self::BLOCK_DEVICE, 208*5225e6b1SAndroid Build Coastguard Worker [id, Self::BLOCK_DEVICE_STATUS], 209*5225e6b1SAndroid Build Coastguard Worker snprintf!(val, "{}", blk.status().to_str()), 210*5225e6b1SAndroid Build Coastguard Worker ) 211*5225e6b1SAndroid Build Coastguard Worker .await?; 212*5225e6b1SAndroid Build Coastguard Worker } 213*5225e6b1SAndroid Build Coastguard Worker Ok(()) 214*5225e6b1SAndroid Build Coastguard Worker } 215*5225e6b1SAndroid Build Coastguard Worker 216*5225e6b1SAndroid Build Coastguard Worker const DEFAULT_BLOCK: &'static str = "gbl-default-block"; 217*5225e6b1SAndroid Build Coastguard Worker 218*5225e6b1SAndroid Build Coastguard Worker /// "fastboot getvar gbl-default-block" get_var_default_block<'s>(&mut self, out: &'s mut [u8]) -> CommandResult<&'s str>219*5225e6b1SAndroid Build Coastguard Worker fn get_var_default_block<'s>(&mut self, out: &'s mut [u8]) -> CommandResult<&'s str> { 220*5225e6b1SAndroid Build Coastguard Worker Ok(match self.default_block { 221*5225e6b1SAndroid Build Coastguard Worker Some(v) => snprintf!(out, "{:#x}", v), 222*5225e6b1SAndroid Build Coastguard Worker None => snprintf!(out, "None"), 223*5225e6b1SAndroid Build Coastguard Worker }) 224*5225e6b1SAndroid Build Coastguard Worker } 225*5225e6b1SAndroid Build Coastguard Worker } 226