well we can iterate now

This commit is contained in:
lif 2024-05-06 23:06:15 -07:00
parent 4a89fc6f07
commit 7d12f92a22
6 changed files with 191 additions and 51 deletions

45
Cargo.lock generated
View file

@ -26,6 +26,18 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "arbitrary-int"
version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c84fc003e338a6f69fbd4f7fe9f92b535ff13e9af8997f3b14b6ddff8b1df46d"
[[package]]
name = "arrayref"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
[[package]] [[package]]
name = "atomic-polyfill" name = "atomic-polyfill"
version = "1.0.3" version = "1.0.3"
@ -123,6 +135,7 @@ name = "efigife"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"embedded-graphics", "embedded-graphics",
"log",
"tinygif", "tinygif",
"uefi", "uefi",
"uefi-graphics2", "uefi-graphics2",
@ -284,6 +297,17 @@ version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "mbrs"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d080a720bb58430e0039347784859f9be41bf8578307b8156be4e02ca3b316e"
dependencies = [
"arbitrary-int",
"arrayref",
"thiserror",
]
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.7.2" version = "2.7.2"
@ -445,6 +469,26 @@ dependencies = [
"winapi-util", "winapi-util",
] ]
[[package]]
name = "thiserror"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.60",
]
[[package]] [[package]]
name = "tinygif" name = "tinygif"
version = "0.0.4" version = "0.0.4"
@ -696,4 +740,5 @@ name = "xtask"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"fatfs", "fatfs",
"mbrs",
] ]

View file

@ -12,6 +12,8 @@ resolver = "2"
[workspace.dependencies] [workspace.dependencies]
fatfs = { path = "rust-fatfs", default-features = false, features = ["alloc", "chrono"] } fatfs = { path = "rust-fatfs", default-features = false, features = ["alloc", "chrono"] }
embedded-graphics = "0.8.1" embedded-graphics = "0.8.1"
log = "0.4.21"
mbrs = "0.3.1"
tinygif = { version = "0.0.4", features = ["8k"] } tinygif = { version = "0.0.4", features = ["8k"] }
uefi = { version = "0.28.0", features = ["global_allocator", "panic_handler", "alloc"] } uefi = { version = "0.28.0", features = ["global_allocator", "panic_handler", "alloc"] }
uefi-graphics2 = "0.1.3" uefi-graphics2 = "0.1.3"

View file

@ -7,6 +7,7 @@ edition = "2021"
[dependencies] [dependencies]
embedded-graphics.workspace = true embedded-graphics.workspace = true
log.workspace = true
tinygif.workspace = true tinygif.workspace = true
uefi.workspace = true uefi.workspace = true
uefi-graphics2.workspace = true uefi-graphics2.workspace = true

View file

@ -1,6 +1,8 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
extern crate alloc;
use core::time::Duration; use core::time::Duration;
use uefi::prelude::*; use uefi::prelude::*;
@ -17,22 +19,26 @@ const GIF_SIZE: usize = include_bytes!("bad-apple.gif").len();
#[entry] #[entry]
fn main(_image_handle: Handle, mut boot_system_table: SystemTable<Boot>) -> Status { fn main(_image_handle: Handle, mut boot_system_table: SystemTable<Boot>) -> Status {
uefi::helpers::init(&mut boot_system_table).unwrap(); uefi::helpers::init(&mut boot_system_table).expect("helper init");
log::info!("hello!");
// Disable the watchdog timer // Disable the watchdog timer
boot_system_table boot_system_table
.boot_services() .boot_services()
.set_watchdog_timer(0, 0x10000, None) .set_watchdog_timer(0, 0x10000, None)
.unwrap(); .expect("disable watchdog timer");
let boot_services = boot_system_table.boot_services(); let boot_services = boot_system_table.boot_services();
boot_services.stall(1_000_000);
let img_handle = boot_services.image_handle(); let img_handle = boot_services.image_handle();
let loaded_image = boot_services let loaded_image = boot_services
.open_protocol_exclusive::<LoadedImage>(img_handle) .open_protocol_exclusive::<LoadedImage>(img_handle)
.unwrap(); .expect("loaded image");
let device_handle = loaded_image.device().unwrap(); let device_handle = loaded_image.device().expect("device handle");
let block_io = unsafe { let block_io = unsafe {
boot_services.open_protocol::<BlockIO>( boot_services.open_protocol::<BlockIO>(
@ -44,39 +50,56 @@ fn main(_image_handle: Handle, mut boot_system_table: SystemTable<Boot>) -> Stat
OpenProtocolAttributes::GetProtocol, OpenProtocolAttributes::GetProtocol,
) )
} }
.unwrap(); .expect("block io");
let mut gif_buf = [0u8; GIF_SIZE]; let mut gif_buf = [0u8; GIF_SIZE];
block_io block_io
.read_blocks(block_io.media().media_id(), Lba::from(0u64), &mut gif_buf) .read_blocks(block_io.media().media_id(), Lba::from(0u64), &mut gif_buf)
.unwrap(); .expect("read blocks");
let gif = tinygif::Gif::<Rgb888>::from_slice(&gif_buf).unwrap(); let gif = tinygif::Gif::<Rgb888>::from_slice(&gif_buf).expect("gif from slice");
// Get gop // Get gop
let gop_handle = boot_services let gop_handle = boot_services
.get_handle_for_protocol::<GraphicsOutput>() .get_handle_for_protocol::<GraphicsOutput>()
.unwrap(); .expect("graphics output handle");
let mut gop = boot_services let mut gop = boot_services
.open_protocol_exclusive::<GraphicsOutput>(gop_handle) .open_protocol_exclusive::<GraphicsOutput>(gop_handle)
.unwrap(); .expect("graphics output open");
use alloc::vec::Vec;
// Create UefiDisplay // Create UefiDisplay
for mode in gop.modes(&boot_services).collect::<Vec<_>>() {
let (w, h) = mode.info().resolution();
if w >= gif.width() as usize && h >= gif.height() as usize {
match mode.info().pixel_format() {
uefi::proto::console::gop::PixelFormat::Rgb
| uefi::proto::console::gop::PixelFormat::Bgr => {
if gop.set_mode(&mode).is_ok() {
break;
}
}
uefi::proto::console::gop::PixelFormat::Bitmask
| uefi::proto::console::gop::PixelFormat::BltOnly => {}
}
}
}
let mode = gop.current_mode_info(); let mode = gop.current_mode_info();
let (res_w, res_h) = mode.resolution(); let (res_w, res_h) = mode.resolution();
let mut display = UefiDisplay::new(gop.frame_buffer(), mode); let mut display = UefiDisplay::new(gop.frame_buffer(), mode);
// Tint the entire screen cyan // Tint the entire screen cyan
display.fill_entire(Rgb888::BLACK).unwrap(); display.fill_entire(Rgb888::BLACK).expect("fill black");
let timer_handle = boot_services let timer_handle = boot_services
.get_handle_for_protocol::<Timestamp>() .get_handle_for_protocol::<Timestamp>()
.unwrap(); .expect("timestamp handle");
let timer = boot_services let timer = boot_services
.open_protocol_exclusive::<Timestamp>(timer_handle) .open_protocol_exclusive::<Timestamp>(timer_handle)
.unwrap(); .expect("timestamp open");
let timer_hz = timer.get_properties().unwrap().frequency as f64; let timer_hz = timer.get_properties().expect("timer props").frequency as f64;
let start_timestamp = timer.get_timestamp(); let start_timestamp = timer.get_timestamp();
let mut gif_elapsed = Duration::new(0, 0); let mut gif_elapsed = Duration::new(0, 0);
@ -90,7 +113,9 @@ fn main(_image_handle: Handle, mut boot_system_table: SystemTable<Boot>) -> Stat
(res_h as i32 / gif.height() as i32) / 2, (res_h as i32 / gif.height() as i32) / 2,
); );
for frame in gif.frames() { for frame in gif.frames() {
frame.draw(&mut display.translated(translation)).unwrap(); frame
.draw(&mut display.translated(translation))
.expect("frame draw");
gif_elapsed += Duration::from_millis(frame.delay_centis as u64 * 10); gif_elapsed += Duration::from_millis(frame.delay_centis as u64 * 10);
// skip flush to catch up // skip flush to catch up

View file

@ -7,3 +7,4 @@ edition = "2021"
[dependencies] [dependencies]
fatfs.workspace = true fatfs.workspace = true
mbrs.workspace = true

View file

@ -9,16 +9,43 @@ use fatfs::{
FileSystem, FormatVolumeOptions, FsOptions, IoBase, IoError, Read as FatRead, Seek as FatSeek, FileSystem, FormatVolumeOptions, FsOptions, IoBase, IoError, Read as FatRead, Seek as FatSeek,
Write as FatWrite, Write as FatWrite,
}; };
use mbrs::{Mbr, PartInfo, PartType};
#[derive(Copy, Clone)]
enum Cpu {
X86_64,
AArch64,
}
impl std::fmt::Display for Cpu {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Cpu::X86_64 => "x86_64",
Cpu::AArch64 => "aarch64",
})
}
}
fn main() { fn main() {
let mut args: VecDeque<_> = std::env::args().skip(1).collect(); let mut args: VecDeque<_> = std::env::args().skip(1).collect();
match args.pop_front() { match args.pop_front() {
Some(cmd) => match cmd.as_str() { Some(cmd) => {
"build" => do_build(args), let cpu = match args
"run" => do_run(args), .pop_front()
.unwrap_or(std::env::consts::ARCH.to_string())
.as_str()
{
"aarch64" | "arm64" => Cpu::AArch64,
"x86_64" | "x64" => Cpu::X86_64,
x => unimplemented!("target cpu {:?}", x),
};
match cmd.as_str() {
"build" => do_build(cpu, args),
"run" => do_run(cpu, args),
x => eprintln!("unknown command {:?}", x), x => eprintln!("unknown command {:?}", x),
}, }
}
None => eprintln!("usage: cargo xtask [build|run] [x86_64|aarch64]"), None => eprintln!("usage: cargo xtask [build|run] [x86_64|aarch64]"),
} }
} }
@ -73,14 +100,15 @@ impl<T: Read + Write + Seek> FatWrite for MyStdIoWrapper<T> {
} }
} }
fn do_build(args: VecDeque<String>) { fn do_build(cpu: Cpu, _args: VecDeque<String>) {
let build_success = Command::new("cargo") let build = "debug";
let build_success = Command::new(env!("CARGO"))
.arg("build") .arg("build")
.arg("--bin") .arg("--bin")
.arg("efigife") .arg("efigife")
.arg("--release") //.arg("--release")
.arg("--target") .arg("--target")
.arg("aarch64-unknown-uefi") // TODO: target according to arg .arg(format!("{}-unknown-uefi", cpu))
.stdin(Stdio::inherit()) .stdin(Stdio::inherit())
.stdout(Stdio::inherit()) .stdout(Stdio::inherit())
.stderr(Stdio::inherit()) .stderr(Stdio::inherit())
@ -90,11 +118,12 @@ fn do_build(args: VecDeque<String>) {
.success(); .success();
assert!(build_success); assert!(build_success);
let efi_bin_path = concat!( let efi_bin_path = format!(
"{}/../target/{}-unknown-uefi/{}/efigife.efi",
env!("CARGO_MANIFEST_DIR"), env!("CARGO_MANIFEST_DIR"),
"/../target/aarch64-unknown-uefi/release/efigife.efi" cpu,
build
); );
eprintln!("{}", efi_bin_path);
let mut efi_bin_buf = Vec::new(); let mut efi_bin_buf = Vec::new();
let mut efi_bin_file = File::open(efi_bin_path).unwrap(); let mut efi_bin_file = File::open(efi_bin_path).unwrap();
let efi_bin_size = efi_bin_file.read_to_end(&mut efi_bin_buf); let efi_bin_size = efi_bin_file.read_to_end(&mut efi_bin_buf);
@ -110,7 +139,11 @@ fn do_build(args: VecDeque<String>) {
) )
.unwrap(); .unwrap();
let fat_fs = FileSystem::new(fat_disk, FsOptions::new()).unwrap(); let fat_fs = FileSystem::new(fat_disk, FsOptions::new()).unwrap();
let boot_efi_name = "BOOTAA64.EFI"; // TODO: parameterize on arg let boot_efi_name = match cpu {
Cpu::AArch64 => "BOOTAA64.EFI",
Cpu::X86_64 => "BOOTX64.EFI",
};
let mut boot_efi = fat_fs let mut boot_efi = fat_fs
.root_dir() .root_dir()
.create_dir("EFI") .create_dir("EFI")
@ -130,49 +163,82 @@ fn do_build(args: VecDeque<String>) {
let mut buf = Vec::new(); let mut buf = Vec::new();
let src_gif_size = src_gif_file.read_to_end(&mut buf).unwrap(); let src_gif_size = src_gif_file.read_to_end(&mut buf).unwrap();
drop(src_gif_file); drop(src_gif_file);
let fat_start_sector = (src_gif_size + 511) / 512; let fat_start_sector = (src_gif_size + 511) / 512;
let fat_sector_count = (fat_disk_buf.len() + 511) / 512;
buf.extend(std::iter::repeat(0).take(fat_start_sector * 512 - buf.len())); buf.extend(std::iter::repeat(0).take(fat_start_sector * 512 - buf.len()));
buf.extend(fat_disk_buf); buf.extend(fat_disk_buf);
let mut mbr = Mbr::default();
mbr.partition_table.entries[0] = Some(
PartInfo::try_from_lba(
true,
fat_start_sector as u32,
fat_sector_count as u32,
PartType::Efi,
)
.unwrap(),
);
let fake_mbr_buf = <[u8; 512]>::try_from(&mbr).unwrap();
buf[0x1be..0x200].copy_from_slice(&fake_mbr_buf[0x1be..0x200]);
let out_img_path = format!( let out_img_path = format!(
"{}/../target/bad-apple.{}-efi.raw.gif", "{}/../target/bad-apple.{}-efi.raw.gif",
env!("CARGO_MANIFEST_DIR"), env!("CARGO_MANIFEST_DIR"),
"aarch64" cpu
); );
let mut out_img_file = File::create(out_img_path).unwrap(); let mut out_img_file = File::create(out_img_path).unwrap();
out_img_file.write_all(&buf).unwrap(); out_img_file.write_all(&buf).unwrap();
} }
fn do_run(args: VecDeque<String>) { fn do_run(cpu: Cpu, args: VecDeque<String>) {
do_build(args.clone()); do_build(cpu, args.clone());
let mut cmd = match args[0].as_str() { let mut cmd = Command::new(format!("qemu-system-{}", cpu));
"aarch64" | "arm64" => { let kvm = cpu.to_string() == std::env::consts::ARCH;
let mut cmd = Command::new("qemu-system-aarch64"); match cpu {
cmd.arg("-drive") Cpu::AArch64 => {
.arg("if=none,id=code,format=raw,file=/usr/share/qemu/edk2-aarch64-code.fd,readonly=on") if kvm {
.arg("-M") cmd.arg("-M")
.arg("virt,pflash0=code,accel=kvm,gic-version=3") .arg("virt,pflash0=code,accel=kvm,gic-version=3")
.arg("-cpu") .arg("-cpu")
.arg("host") .arg("host");
.arg("-m") } else {
cmd.arg("-M").arg("virt,pflash0=code,gic-version=3");
}
cmd.arg("-drive").arg(
"if=none,id=code,format=raw,file=/usr/share/qemu/edk2-aarch64-code.fd,readonly=on",
);
}
Cpu::X86_64 => {
if kvm {
cmd.arg("-M")
.arg("q35,smm=on,accel=kvm")
.arg("-cpu")
.arg("host");
} else {
cmd.arg("-M").arg("q35,smm=on");
}
cmd.arg("-global")
.arg("ICH9-LPC.disable_s3=1")
.arg("-drive")
.arg(
"if=pflash,format=raw,unit=0,file=/usr/share/edk2-ovmf/OVMF_CODE.fd,readonly=on",
);
}
}
cmd.arg("-m")
.arg("512") .arg("512")
.arg("-device") .arg("-device")
.arg("virtio-gpu-pci"); .arg("virtio-gpu-pci")
cmd .args(&args);
}
"x86_64" | "x64" => {
//let mut cmd = Command::new("qemu-system-x86_64");
todo!();
}
x => unimplemented!("target cpu {:?}", x),
};
let out_img_path = format!( let out_img_path = format!(
"{}/../target/bad-apple.{}-efi.raw.gif", "{}/../target/bad-apple.{}-efi.raw.gif",
env!("CARGO_MANIFEST_DIR"), env!("CARGO_MANIFEST_DIR"),
"aarch64" cpu
); );
cmd.arg(out_img_path) cmd.arg("-drive")
.arg(format!("format=raw,file={}", out_img_path))
.stdin(Stdio::inherit()) .stdin(Stdio::inherit())
.stdout(Stdio::inherit()) .stdout(Stdio::inherit())
.stderr(Stdio::inherit()) .stderr(Stdio::inherit())