174 lines
5.0 KiB
Rust
174 lines
5.0 KiB
Rust
#![no_std]
|
|
#![no_main]
|
|
#![allow(unused)]
|
|
|
|
#[macro_use]
|
|
extern crate log;
|
|
#[macro_use]
|
|
extern crate alloc;
|
|
|
|
// Keep this line to ensure the `mem*` functions are linked in.
|
|
extern crate rlibc;
|
|
|
|
extern crate goblin;
|
|
|
|
extern crate uefi;
|
|
extern crate uefi_services;
|
|
|
|
#[macro_use]
|
|
extern crate uefi_macros;
|
|
|
|
use core::ffi::c_void;
|
|
use core::ptr;
|
|
use uefi::Handle;
|
|
use uefi::{prelude::*, Identify};
|
|
use uefi::{
|
|
proto::console::gop::{BltOp, BltPixel, FrameBuffer, GraphicsOutput, PixelFormat},
|
|
table::boot::{
|
|
AllocateType, BootServices, MemoryType, OpenProtocolAttributes, OpenProtocolParams,
|
|
},
|
|
};
|
|
|
|
#[uefi_macros::entry]
|
|
pub fn efi_main(_image: Handle, mut st: SystemTable<Boot>) -> Status {
|
|
// Initialize logging, memory allocation and uefi services
|
|
let mut bt = match uefi_services::init(&mut st) {
|
|
Ok(_) => {
|
|
|
|
st.stdout().clear();
|
|
st.stdout().set_color(
|
|
uefi::proto::console::text::Color::LightMagenta,
|
|
uefi::proto::console::text::Color::Black,
|
|
);
|
|
|
|
// output firmware-vendor (CStr16 to Rust string)
|
|
// max size of 32 characters
|
|
let mut buf = arrayvec::ArrayString::<32>::new();
|
|
st.firmware_vendor().as_str_in_buf(&mut buf).unwrap();
|
|
info!("Firmware Vendor: {}", buf.as_str());
|
|
|
|
let rev = st.uefi_revision();
|
|
let (major, minor) = (rev.major(), rev.minor());
|
|
let buf = format!("UEFI {}.{}", major, minor / 10);
|
|
info!("{}", buf);
|
|
|
|
assert!(major >= 2, "Running on an old, unsupported version of UEFI");
|
|
assert!(
|
|
minor >= 30,
|
|
"Old version of UEFI 2, some features might not be available."
|
|
);
|
|
|
|
st.boot_services()
|
|
}
|
|
Err(_) => {
|
|
panic!();
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
let handle = bt.get_handle_for_protocol::<GraphicsOutput>()
|
|
.expect("missing GraphicsOutput protocol");
|
|
|
|
|
|
let mut gop = unsafe {
|
|
let mut gop_proto = st.boot_services().open_protocol::<GraphicsOutput>(
|
|
OpenProtocolParams {
|
|
handle,
|
|
agent: st.boot_services().image_handle(),
|
|
controller: None,
|
|
},
|
|
// For this test, don't open in exclusive mode. That
|
|
// would break the connection between stdout and the
|
|
// video console.
|
|
OpenProtocolAttributes::GetProtocol,
|
|
)
|
|
.expect("failed to open Graphics Output Protocol");
|
|
|
|
gop_proto
|
|
};
|
|
|
|
set_graphics_mode(&mut gop);
|
|
fill_color(&mut gop);
|
|
draw_fb(&mut gop);
|
|
info!("GOP Framebuffer test complete");
|
|
|
|
// Return success status
|
|
Status::SUCCESS
|
|
}
|
|
|
|
// Set a larger graphics mode.
|
|
fn set_graphics_mode(gop: &mut GraphicsOutput) {
|
|
// We know for sure QEMU has a 1024x768 mode.
|
|
let mode = gop
|
|
.modes()
|
|
.find(|mode| {
|
|
let info = mode.info();
|
|
info.resolution() == (1024, 768)
|
|
})
|
|
.unwrap();
|
|
|
|
gop.set_mode(&mode).expect("Failed to set graphics mode");
|
|
}
|
|
|
|
// Fill the screen with color.
|
|
fn fill_color(gop: &mut GraphicsOutput) {
|
|
let op = BltOp::VideoFill {
|
|
// Cornflower blue.
|
|
color: BltPixel::new(100, 149, 237),
|
|
dest: (0, 0),
|
|
dims: (1024, 768),
|
|
};
|
|
|
|
gop.blt(op).expect("Failed to fill screen with color");
|
|
}
|
|
|
|
// Draw directly to the frame buffer.
|
|
fn draw_fb(gop: &mut GraphicsOutput) {
|
|
// The `virtio-gpu-pci` graphics device we use on aarch64 doesn't
|
|
// support `PixelFormat::BltOnly`.
|
|
if cfg!(target_arch = "aarch64") {
|
|
return;
|
|
}
|
|
|
|
let mi = gop.current_mode_info();
|
|
let stride = mi.stride();
|
|
let (width, height) = mi.resolution();
|
|
|
|
let mut fb = gop.frame_buffer();
|
|
|
|
type PixelWriter = unsafe fn(&mut FrameBuffer, usize, [u8; 3]);
|
|
unsafe fn write_pixel_rgb(fb: &mut FrameBuffer, pixel_base: usize, rgb: [u8; 3]) {
|
|
fb.write_value(pixel_base, rgb);
|
|
}
|
|
unsafe fn write_pixel_bgr(fb: &mut FrameBuffer, pixel_base: usize, rgb: [u8; 3]) {
|
|
fb.write_value(pixel_base, [rgb[2], rgb[1], rgb[0]]);
|
|
}
|
|
let write_pixel: PixelWriter = match mi.pixel_format() {
|
|
PixelFormat::Rgb => write_pixel_rgb,
|
|
PixelFormat::Bgr => write_pixel_bgr,
|
|
_ => {
|
|
info!("This pixel format is not supported by the drawing demo");
|
|
return;
|
|
}
|
|
};
|
|
|
|
let mut fill_rectangle = |(x1, y1), (x2, y2), color| {
|
|
assert!((x1 < width) && (x2 < width), "Bad X coordinate");
|
|
assert!((y1 < height) && (y2 < height), "Bad Y coordinate");
|
|
for row in y1..y2 {
|
|
for column in x1..x2 {
|
|
unsafe {
|
|
let pixel_index = (row * stride) + column;
|
|
let pixel_base = 4 * pixel_index;
|
|
write_pixel(&mut fb, pixel_base, color);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
fill_rectangle((50, 30), (150, 600), [250, 128, 64]);
|
|
fill_rectangle((400, 120), (750, 450), [16, 128, 255]);
|
|
}
|