Write BIOS and EFI partitions in memory

This commit is contained in:
Jeremy Soller
2022-09-07 09:45:27 -06:00
parent ddf59d8c7d
commit 4b1df136a6
2 changed files with 124 additions and 91 deletions
+2 -2
View File
@@ -24,7 +24,7 @@ arg_parser = "0.1.0"
failure = "0.1.8"
fatfs = "0.3.0"
fscommon = "0.1.1"
gpt = { git = "https://gitlab.redox-os.org/redox-os/gpt" }
gpt = "3.0.0"
libc = "0.2.70"
pkgar = "0.1.9"
pkgar-core = "0.1.0"
@@ -39,7 +39,7 @@ serde = "1.0.110"
serde_derive = "1.0.110"
termion = "1.5.5"
toml = "0.5.6"
uuid = { version = "0.7.4", features = ["v4"] }
uuid = { version = "0.8", features = ["v4"] }
[patch.crates-io]
ring = { git = "https://gitlab.redox-os.org/redox-os/ring.git", branch = "redox-unix-0.13.5" }
+122 -89
View File
@@ -27,7 +27,8 @@ use std::{
collections::BTreeMap,
env,
fs,
io::{self, stderr, Write},
io::{self, stderr, Read, Seek, SeekFrom, Write},
os::unix::fs::MetadataExt,
path::Path,
process::{self, Command},
str::FromStr,
@@ -403,120 +404,152 @@ pub fn with_whole_disk<P, F, T>(disk_path: P, bootloader_bios: &[u8], bootloader
}
};
// TODO: support other block sizes?
let block_size = 512;
// Write BIOS bootloader to disk, resetting all partitioning
let disk_size = {
eprintln!("Writing bootloader with size {:#x}", bootloader_bios.len());
// Open disk
let mut disk = fs::OpenOptions::new()
.read(true)
.write(true)
.open(disk_path.as_ref())?;
// Write bootloader data
disk.write(&bootloader_bios)?;
// Get disk size
disk.metadata()?.len()
};
// Open disk, mark it as not initialized
let mut gpt_disk = gpt::GptConfig::new()
.writable(true)
.initialized(false)
// Open disk and read metadata
eprintln!("Opening disk {}", disk_path.as_ref().display());
let mut disk_file = fs::OpenOptions::new()
.read(true)
.write(true)
.open(disk_path.as_ref())?;
let disk_metadata = disk_file.metadata()?;
let disk_size = disk_metadata.len();
let block_size = disk_metadata.blksize();
let gpt_block_size = match block_size {
512 => gpt::disk::LogicalBlockSize::Lb512,
_ => {
// TODO: support (and test) other block sizes
return Err(format_err!("block size {} not supported", block_size));
}
};
// Calculate partition offsets
let gpt_reserved = 34 * 512; // GPT always reserves 34 512-byte sectors
// First megabyte of the disk is reserved for BIOS partition, wich includes GPT tables
let bios_size = 1024 * 1024;
let bios_start = gpt_reserved / block_size;
let bios_end = (1024 * 1024 / block_size) - 1; // End at 1 MiB
let bios_end = (bios_size / block_size) - 1; // End at 1 MiB
// Last megabyte of the disk is reserved for EFI partition
let efi_size = 1024 * 1024;
let efi_end = ((disk_size - gpt_reserved) / block_size) - 1;
let efi_start = efi_end - ((1024 * 1024) / block_size); // 1 MiB from end of disk
let efi_start = efi_end - (efi_size / block_size); // 1 MiB from end of disk
let redoxfs_start = bios_end + 1;
let redoxfs_end = efi_start - 1;
// Add BIOS boot partition
let mut partitions = BTreeMap::new();
let mut partition_id = 1;
partitions.insert(partition_id, gpt::partition::Partition {
part_type_guid: gpt::partition_types::BIOS,
part_guid: uuid::Uuid::new_v4(),
first_lba: bios_start,
last_lba: bios_end,
flags: 0, // TODO
name: "BIOS".to_string(),
});
partition_id += 1;
// Format and install BIOS partition
{
let mut bios_partition = {
// We write the BIOS partition and partition tables in memory to avoid non block aligned I/O
let mut bios_partition = Box::new(io::Cursor::new(vec![0u8; bios_size as usize]));
// Add RedoxFS partition
partitions.insert(partition_id, gpt::partition::Partition {
//TODO: Use REDOX_REDOXFS type (needs GPT crate changes)
part_type_guid: gpt::partition_types::LINUX_FS,
part_guid: uuid::Uuid::new_v4(),
first_lba: redoxfs_start,
last_lba: redoxfs_end,
flags: 0,
name: "REDOX".to_string(),
});
partition_id += 1;
// Write BIOS bootloader to disk
eprintln!("Write bootloader with size {:#x}", bootloader_bios.len());
bios_partition.write_all(&bootloader_bios)?;
// Add EFI boot partition
partitions.insert(partition_id, gpt::partition::Partition {
part_type_guid: gpt::partition_types::EFI,
part_guid: uuid::Uuid::new_v4(),
first_lba: efi_start,
last_lba: efi_end,
flags: 0, // TODO
name: "EFI".to_string(),
});
// Replace MBR tables with protective MBR
let mbr_blocks = ((disk_size + block_size - 1) / block_size) - 1;
eprintln!("Writing protective MBR with disk blocks {:#x}", mbr_blocks);
gpt::mbr::ProtectiveMBR::with_lb_size(mbr_blocks as u32)
.update_conservative(&mut bios_partition)?;
// Initialize GPT table
gpt_disk.update_partitions(partitions)?;
// Open disk, mark it as not initialized
let mut gpt_disk = gpt::GptConfig::new()
.initialized(false)
.writable(true)
.logical_block_size(gpt_block_size)
.create_from_device(bios_partition, None)?;
eprintln!("Writing GPT tables: {:#?}", gpt_disk);
// Add BIOS boot partition
let mut partitions = BTreeMap::new();
let mut partition_id = 1;
partitions.insert(partition_id, gpt::partition::Partition {
part_type_guid: gpt::partition_types::BIOS,
part_guid: uuid::Uuid::new_v4(),
first_lba: bios_start,
last_lba: bios_end,
flags: 0, // TODO
name: "BIOS".to_string(),
});
partition_id += 1;
// Write partition layout, returning disk file
let mut disk_file = gpt_disk.write()?;
// Add RedoxFS partition
partitions.insert(partition_id, gpt::partition::Partition {
//TODO: Use REDOX_REDOXFS type (needs GPT crate changes)
part_type_guid: gpt::partition_types::LINUX_FS,
part_guid: uuid::Uuid::new_v4(),
first_lba: redoxfs_start,
last_lba: redoxfs_end,
flags: 0,
name: "REDOX".to_string(),
});
partition_id += 1;
// Replace MBR tables with protective MBR
let mbr_blocks = ((disk_size + block_size - 1) / block_size) - 1;
eprintln!("Writing protective MBR with disk blocks {:#x}", mbr_blocks);
gpt::mbr::ProtectiveMBR::with_lb_size(mbr_blocks as u32)
.update_conservative(&mut disk_file)?;
// Add EFI boot partition
partitions.insert(partition_id, gpt::partition::Partition {
part_type_guid: gpt::partition_types::EFI,
part_guid: uuid::Uuid::new_v4(),
first_lba: efi_start,
last_lba: efi_end,
flags: 0, // TODO
name: "EFI".to_string(),
});
eprintln!("Writing GPT tables: {:#?}", partitions);
// Initialize GPT table
gpt_disk.update_partitions(partitions)?;
// Write partition layout, returning disk file
gpt_disk.write()?
};
eprintln!("Copying BIOS partition to disk with size {:#x}", bios_size);
for block in 0..bios_size / block_size {
let offset = block * block_size;
let mut block = vec![0; block_size as usize];
bios_partition.seek(SeekFrom::Start(offset))?;
bios_partition.read_exact(&mut block)?;
disk_file.seek(SeekFrom::Start(offset))?;
disk_file.write_all(&block)?;
}
}
// Format and install EFI partition
{
// We write the BIOS partition and partition tables in memory to avoid non block aligned I/O
let mut efi_partition = vec![0u8; efi_size as usize];
{
eprintln!("Formatting EFI partition with size {:#x}", efi_size);
fatfs::format_volume(io::Cursor::new(&mut efi_partition), fatfs::FormatVolumeOptions::new())?;
eprintln!("Opening EFI partition");
let fs = fatfs::FileSystem::new(io::Cursor::new(&mut efi_partition), fatfs::FsOptions::new())?;
eprintln!("Creating EFI directory");
let root_dir = fs.root_dir();
root_dir.create_dir("EFI")?;
eprintln!("Creating EFI/BOOT directory");
let efi_dir = root_dir.open_dir("EFI")?;
efi_dir.create_dir("BOOT")?;
eprintln!("Writing EFI/BOOT/{} file with size {:#x}", bootloader_efi_name, bootloader_efi.len());
let boot_dir = efi_dir.open_dir("BOOT")?;
let mut file = boot_dir.create_file(bootloader_efi_name)?;
file.truncate()?;
file.write_all(&bootloader_efi)?;
}
eprintln!("Copying BIOS partition to disk with size {:#x}", efi_size);
let mut disk_efi = fscommon::StreamSlice::new(
&mut disk_file,
efi_start * block_size,
(efi_end + 1) * block_size,
)?;
eprintln!("Formatting EFI partition with size {:#x}", (efi_end - efi_start) * block_size);
fatfs::format_volume(&mut disk_efi, fatfs::FormatVolumeOptions::new())?;
eprintln!("Opening EFI partition");
let fs = fatfs::FileSystem::new(disk_efi, fatfs::FsOptions::new())?;
eprintln!("Creating EFI directory");
let root_dir = fs.root_dir();
root_dir.create_dir("EFI")?;
eprintln!("Creating EFI/BOOT directory");
let efi_dir = root_dir.open_dir("EFI")?;
efi_dir.create_dir("BOOT")?;
eprintln!("Writing EFI/BOOT/{} file", bootloader_efi_name);
let boot_dir = efi_dir.open_dir("BOOT")?;
let mut file = boot_dir.create_file(bootloader_efi_name)?;
file.truncate()?;
file.write_all(&bootloader_efi)?;
disk_efi.write_all(&efi_partition)?;
}
// Format and install RedoxFS partition