xtask\tasks\guest_test\uefi/
gpt_efi_disk.rs1use anyhow::Context;
5use anyhow::Result;
6use fatfs::FileSystem;
7use fatfs::FormatVolumeOptions;
8use fatfs::FsOptions;
9use guid::Guid;
10use std::io::Cursor;
11use std::io::Seek;
12use std::path::Path;
13use zerocopy::IntoBytes;
14
15const SECTOR_SIZE: usize = 512;
16const EFI_GUID: Guid = guid::guid!("{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}");
17
18pub fn create_gpt_efi_disk(out_img: &Path, with_files: &[(&Path, &Path)]) -> Result<()> {
19 if out_img.extension().unwrap_or_default() != "img" {
20 return Err(anyhow::anyhow!(
21 "only .img disk images are supported at this time"
22 ));
23 }
24
25 let disk_size = 1024 * 1024 * 32; let num_sectors = disk_size / SECTOR_SIZE;
27
28 let mut disk = vec![0; num_sectors * SECTOR_SIZE];
29
30 let efi_partition_range = {
31 let mut cur = Cursor::new(&mut disk);
32
33 let mut mbr = mbrman::MBR::new_from(&mut cur, SECTOR_SIZE as u32, [0xff; 4])?;
34 let mut gpt = gptman::GPT::new_from(&mut cur, SECTOR_SIZE as u64, [0xff; 16])?;
35
36 let first_chs = mbrman::CHS::new(0, 0, 2);
38 let last_chs = mbrman::CHS::empty(); mbr[1] = mbrman::MBRPartitionEntry {
40 boot: mbrman::BOOT_INACTIVE,
41 first_chs,
42 sys: 0xEE, last_chs,
44 starting_lba: 1,
45 sectors: gpt.header.last_usable_lba.try_into().unwrap_or(0xFFFFFFFF),
46 };
47 mbr.write_into(&mut cur)?;
48
49 cur.rewind()?;
50
51 gpt[1] = gptman::GPTPartitionEntry {
53 partition_type_guid: EFI_GUID.as_bytes().try_into().unwrap(),
54 unique_partition_guid: [0xff; 16],
55 starting_lba: gpt.header.first_usable_lba,
56 ending_lba: gpt.header.last_usable_lba,
57 attribute_bits: 0,
58 partition_name: "EFI".into(),
59 };
60 gpt.write_into(&mut cur)?;
61
62 let partition_start_byte = gpt[1].starting_lba as usize * SECTOR_SIZE;
64 let partition_num_bytes = (gpt[1].ending_lba - gpt[1].starting_lba) as usize * SECTOR_SIZE;
65 partition_start_byte..partition_start_byte + partition_num_bytes
66 };
67
68 init_fat(&mut disk[efi_partition_range], with_files).context("initializing FAT partition")?;
69
70 fs_err::write(out_img, &disk)?;
71 log::info!("Wrote test image to: {}", out_img.display());
72
73 Ok(())
74}
75
76fn init_fat(partition: &mut [u8], with_files: &[(&Path, &Path)]) -> Result<()> {
77 let efi_fs = {
78 let mut cursor = Cursor::new(partition);
79 fatfs::format_volume(
80 &mut cursor,
81 FormatVolumeOptions::new()
82 .fat_type(fatfs::FatType::Fat32)
83 .volume_label(*b"hvlite_test"),
84 )?;
85
86 cursor.rewind()?;
87 FileSystem::new(cursor, FsOptions::new().update_accessed_date(false))?
88 };
89
90 let root_dir = efi_fs.root_dir();
91 for (dst_file, src_file) in with_files {
92 let ancestors = dst_file.ancestors().collect::<Vec<_>>();
93 let num_ancestors = ancestors.len();
94
95 for (i, chunk) in ancestors.into_iter().rev().enumerate() {
96 if i == 0 {
98 continue;
99 }
100
101 if i != num_ancestors - 1 {
102 log::info!("creating dir {}", chunk.display());
103 root_dir
104 .create_dir(chunk.to_str().unwrap())
105 .context("creating dir")?;
106 } else {
107 log::info!("creating file {}", chunk.display());
108 let mut file = root_dir
109 .create_file(chunk.to_str().unwrap())
110 .context(format!("creating file {}", chunk.display()))?;
111 std::io::copy(&mut fs_err::File::open(src_file)?, &mut file)?;
112 }
113 }
114 }
115
116 log::info!("{:?}", efi_fs.stats()?);
117
118 Ok(())
119}