xref: /aosp_15_r20/bootable/libbootloader/gbl/libgbl/src/fastboot/vars.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
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