1 // Copyright 2023, 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 //! Support for parsing GUID partition tables. 16 17 use core::cmp::min; 18 use core::fmt; 19 use core::mem::size_of; 20 use core::ops::RangeInclusive; 21 use core::slice; 22 use static_assertions::const_assert; 23 use static_assertions::const_assert_eq; 24 use uuid::Uuid; 25 use virtio_drivers::device::blk::SECTOR_SIZE; 26 use vmbase::util::ceiling_div; 27 use vmbase::virtio::{pci, HalImpl}; 28 use zerocopy::FromBytes; 29 30 type VirtIOBlk = pci::VirtIOBlk<HalImpl>; 31 32 pub enum Error { 33 /// VirtIO error during read operation. 34 FailedRead(virtio_drivers::Error), 35 /// VirtIO error during write operation. 36 FailedWrite(virtio_drivers::Error), 37 /// Invalid GPT header. 38 InvalidHeader, 39 /// Invalid partition block index. 40 BlockOutsidePartition(usize), 41 } 42 43 impl fmt::Display for Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result44 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 45 match self { 46 Self::FailedRead(e) => write!(f, "Failed to read from disk: {e}"), 47 Self::FailedWrite(e) => write!(f, "Failed to write to disk: {e}"), 48 Self::InvalidHeader => write!(f, "Found invalid GPT header"), 49 Self::BlockOutsidePartition(i) => write!(f, "Accessed invalid block index {i}"), 50 } 51 } 52 } 53 54 pub type Result<T> = core::result::Result<T, Error>; 55 56 pub struct Partition { 57 partitions: Partitions, 58 indices: RangeInclusive<usize>, 59 } 60 61 impl Partition { get_by_name(device: VirtIOBlk, name: &str) -> Result<Option<Self>>62 pub fn get_by_name(device: VirtIOBlk, name: &str) -> Result<Option<Self>> { 63 Partitions::new(device)?.get_partition_by_name(name) 64 } 65 new(partitions: Partitions, entry: &Entry) -> Self66 fn new(partitions: Partitions, entry: &Entry) -> Self { 67 let first = entry.first_lba().try_into().unwrap(); 68 let last = entry.last_lba().try_into().unwrap(); 69 70 Self { partitions, indices: first..=last } 71 } 72 indices(&self) -> RangeInclusive<usize>73 pub fn indices(&self) -> RangeInclusive<usize> { 74 self.indices.clone() 75 } 76 read_block(&mut self, index: usize, blk: &mut [u8]) -> Result<()>77 pub fn read_block(&mut self, index: usize, blk: &mut [u8]) -> Result<()> { 78 let index = self.block_index(index).ok_or(Error::BlockOutsidePartition(index))?; 79 self.partitions.read_block(index, blk) 80 } 81 write_block(&mut self, index: usize, blk: &[u8]) -> Result<()>82 pub fn write_block(&mut self, index: usize, blk: &[u8]) -> Result<()> { 83 let index = self.block_index(index).ok_or(Error::BlockOutsidePartition(index))?; 84 self.partitions.write_block(index, blk) 85 } 86 block_index(&self, index: usize) -> Option<usize>87 fn block_index(&self, index: usize) -> Option<usize> { 88 if self.indices.contains(&index) { 89 Some(index) 90 } else { 91 None 92 } 93 } 94 } 95 96 pub struct Partitions { 97 device: VirtIOBlk, 98 entries_count: usize, 99 } 100 101 impl Partitions { 102 pub const LBA_SIZE: usize = SECTOR_SIZE; 103 new(mut device: VirtIOBlk) -> Result<Self>104 fn new(mut device: VirtIOBlk) -> Result<Self> { 105 let mut blk = [0; Self::LBA_SIZE]; 106 device.read_blocks(Header::LBA, &mut blk).map_err(Error::FailedRead)?; 107 let header = Header::read_from_prefix(blk.as_slice()).unwrap().0; 108 if !header.is_valid() { 109 return Err(Error::InvalidHeader); 110 } 111 let entries_count = usize::try_from(header.entries_count()).unwrap(); 112 113 Ok(Self { device, entries_count }) 114 } 115 get_partition_by_name(mut self, name: &str) -> Result<Option<Partition>>116 fn get_partition_by_name(mut self, name: &str) -> Result<Option<Partition>> { 117 const_assert_eq!(Partitions::LBA_SIZE.rem_euclid(size_of::<Entry>()), 0); 118 let entries_per_blk = Partitions::LBA_SIZE.checked_div(size_of::<Entry>()).unwrap(); 119 120 // Create a UTF-16 reference against which we'll compare partition names. Note that unlike 121 // the C99 wcslen(), this comparison will cover bytes past the first L'\0' character. 122 let mut needle = [0; Entry::NAME_SIZE / size_of::<u16>()]; 123 for (dest, src) in needle.iter_mut().zip(name.encode_utf16()) { 124 *dest = src; 125 } 126 127 let mut blk = [0; Self::LBA_SIZE]; 128 let mut rem = self.entries_count; 129 let num_blocks = ceiling_div(self.entries_count, entries_per_blk).unwrap(); 130 for i in Header::ENTRIES_LBA..Header::ENTRIES_LBA.checked_add(num_blocks).unwrap() { 131 self.read_block(i, &mut blk)?; 132 let entries = blk.as_ptr().cast::<Entry>(); 133 // SAFETY: blk is assumed to be properly aligned for Entry and its size is assert-ed 134 // above. All potential values of the slice will produce valid Entry values. 135 let entries = unsafe { slice::from_raw_parts(entries, min(rem, entries_per_blk)) }; 136 for entry in entries { 137 let entry_name = entry.name; 138 if entry_name == needle { 139 return Ok(Some(Partition::new(self, entry))); 140 } 141 rem -= 1; 142 } 143 } 144 Ok(None) 145 } 146 read_block(&mut self, index: usize, blk: &mut [u8]) -> Result<()>147 fn read_block(&mut self, index: usize, blk: &mut [u8]) -> Result<()> { 148 self.device.read_blocks(index, blk).map_err(Error::FailedRead) 149 } 150 write_block(&mut self, index: usize, blk: &[u8]) -> Result<()>151 fn write_block(&mut self, index: usize, blk: &[u8]) -> Result<()> { 152 self.device.write_blocks(index, blk).map_err(Error::FailedWrite) 153 } 154 } 155 156 type Lba = u64; 157 158 /// Structure as defined in release 2.10 of the UEFI Specification (5.3.2 GPT Header). 159 #[derive(FromBytes)] 160 #[repr(C, packed)] 161 struct Header { 162 signature: u64, 163 revision: u32, 164 header_size: u32, 165 header_crc32: u32, 166 reserved0: u32, 167 current_lba: Lba, 168 backup_lba: Lba, 169 first_lba: Lba, 170 last_lba: Lba, 171 disk_guid: u128, 172 entries_lba: Lba, 173 entries_count: u32, 174 entry_size: u32, 175 entries_crc32: u32, 176 } 177 const_assert!(size_of::<Header>() < Partitions::LBA_SIZE); 178 179 impl Header { 180 const SIGNATURE: u64 = u64::from_le_bytes(*b"EFI PART"); 181 const REVISION_1_0: u32 = 1 << 16; 182 const LBA: usize = 1; 183 const ENTRIES_LBA: usize = 2; 184 is_valid(&self) -> bool185 fn is_valid(&self) -> bool { 186 self.signature() == Self::SIGNATURE 187 && self.header_size() == size_of::<Self>().try_into().unwrap() 188 && self.revision() == Self::REVISION_1_0 189 && self.entry_size() == size_of::<Entry>().try_into().unwrap() 190 && self.current_lba() == Self::LBA.try_into().unwrap() 191 && self.entries_lba() == Self::ENTRIES_LBA.try_into().unwrap() 192 } 193 signature(&self) -> u64194 fn signature(&self) -> u64 { 195 u64::from_le(self.signature) 196 } 197 entries_count(&self) -> u32198 fn entries_count(&self) -> u32 { 199 u32::from_le(self.entries_count) 200 } 201 header_size(&self) -> u32202 fn header_size(&self) -> u32 { 203 u32::from_le(self.header_size) 204 } 205 revision(&self) -> u32206 fn revision(&self) -> u32 { 207 u32::from_le(self.revision) 208 } 209 entry_size(&self) -> u32210 fn entry_size(&self) -> u32 { 211 u32::from_le(self.entry_size) 212 } 213 entries_lba(&self) -> Lba214 fn entries_lba(&self) -> Lba { 215 Lba::from_le(self.entries_lba) 216 } 217 current_lba(&self) -> Lba218 fn current_lba(&self) -> Lba { 219 Lba::from_le(self.current_lba) 220 } 221 } 222 223 /// Structure as defined in release 2.10 of the UEFI Specification (5.3.3 GPT Partition Entry 224 /// Array). 225 #[repr(C, packed)] 226 struct Entry { 227 type_guid: Uuid, 228 guid: Uuid, 229 first_lba: Lba, 230 last_lba: Lba, 231 flags: u64, 232 name: [u16; Entry::NAME_SIZE / size_of::<u16>()], // UTF-16 233 } 234 235 impl Entry { 236 const NAME_SIZE: usize = 72; 237 first_lba(&self) -> Lba238 fn first_lba(&self) -> Lba { 239 Lba::from_le(self.first_lba) 240 } 241 last_lba(&self) -> Lba242 fn last_lba(&self) -> Lba { 243 Lba::from_le(self.last_lba) 244 } 245 } 246