merge UEFI-FB driver for text mode console into mainline #2

Merged
Nivirx merged 12 commits from next into master 2023-03-18 20:39:28 -04:00
2 changed files with 33 additions and 85 deletions
Showing only changes of commit 744a0bb796 - Show all commits

View File

@@ -28,6 +28,7 @@ use uefi::{
AllocateType, BootServices, MemoryType, OpenProtocolAttributes, OpenProtocolParams, AllocateType, BootServices, MemoryType, OpenProtocolAttributes, OpenProtocolParams,
}, },
}; };
use uefi_fb::UefiFb;
mod uefi_fb; mod uefi_fb;
mod sync; mod sync;
@@ -68,36 +69,14 @@ pub fn efi_main(_image: Handle, mut st: SystemTable<Boot>) -> Status {
} }
}; };
let fb = uefi_fb::UefiFb::new();
uefifb_test(&fb)
}
fn uefifb_test(fb: &UefiFb) -> Status {
// run tests here
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"); info!("GOP Framebuffer test complete");
// Return success status
Status::SUCCESS Status::SUCCESS
} }

View File

@@ -12,15 +12,15 @@ use uefi::{
}; };
use alloc::sync::Arc; use alloc::sync::Arc;
use crate::sync; use crate::sync;
use crate::sync::Spinlock::*; use crate::sync::{Spinlock, SpinlockGuard};
struct UefiFb { pub struct UefiFb<'a> {
gop: Arc<ScopedProtocol<GraphicsOutput>> gop: ScopedProtocol<'a, GraphicsOutput<'a>>
} }
impl UefiFb { impl UefiFb<'_> {
pub fn new() -> UefiFb { pub fn new() -> UefiFb<'static> {
let st_ref = unsafe { uefi_services::system_table().as_ref() }; let st_ref = unsafe { uefi_services::system_table().as_ref() };
let bt = st_ref.boot_services(); let bt = st_ref.boot_services();
@@ -45,27 +45,15 @@ impl UefiFb {
gop_proto gop_proto
}; };
UefiFb { gop }
UefiFb {
gop: Arc::new(gop)
}
/*
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. // Set a larger graphics mode.
pub fn set_graphics_mode(&mut self) { pub fn set_graphics_mode(&mut self, mode_tuple: Option<(i16,i16,i16)>) {
// We know for sure QEMU has a 1024x768 mode. if mode_tuple == None {
let mode = self.gop // We know for sure QEMU has a 1024x768 mode.
let mode = self.gop
.modes() .modes()
.find(|mode| { .find(|mode| {
let info = mode.info(); let info = mode.info();
@@ -73,42 +61,38 @@ impl UefiFb {
}) })
.unwrap(); .unwrap();
self.gop.set_mode(&mode).expect("Failed to set graphics mode"); self.gop.set_mode(&mode).expect("Failed to set graphics mode");
} else {
unimplemented!()
}
} }
// Fill the screen with color. // Fill the screen with color.
fn fill_color(&mut self) { fn fb_blt_fill(&mut self, color: BltPixel, dest: (usize, usize), dims: (usize, usize)) {
let op = BltOp::VideoFill { let op = BltOp::VideoFill {
// Cornflower blue. color,
color: BltPixel::new(100, 149, 237), dest,
dest: (0, 0), dims
dims: (1024, 768),
}; };
self.gop.blt(op).expect("Failed to fill screen with color"); self.gop.blt(op).expect("Failed to fill screen with color");
} }
// Draw directly to the frame buffer. // Draw directly to the frame buffer.
fn draw_fb(&mut self) { fn draw_fb(&mut self, index: usize, rgb: [u8; 3]) {
// The `virtio-gpu-pci` graphics device we use on aarch64 doesn't
// support `PixelFormat::BltOnly`.
if cfg!(target_arch = "aarch64") {
return;
}
let mi = self.gop.current_mode_info(); let mi = self.gop.current_mode_info();
let stride = mi.stride();
let (width, height) = mi.resolution();
let mut fb = self.gop.frame_buffer(); let mut fb = self.gop.frame_buffer();
type PixelWriter = unsafe fn(&mut FrameBuffer, usize, [u8; 3]); 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_rgb(fb: &mut FrameBuffer, index: usize, rgb: [u8; 3]) {
fb.write_value(index, rgb);
} }
unsafe fn write_pixel_bgr(fb: &mut FrameBuffer, pixel_base: usize, rgb: [u8; 3]) { unsafe fn write_pixel_bgr(fb: &mut FrameBuffer, index: usize, rgb: [u8; 3]) {
fb.write_value(pixel_base, [rgb[2], rgb[1], rgb[0]]); fb.write_value(index, [rgb[2], rgb[1], rgb[0]]);
} }
let write_pixel: PixelWriter = match mi.pixel_format() { let write_pixel: PixelWriter = match mi.pixel_format() {
PixelFormat::Rgb => write_pixel_rgb, PixelFormat::Rgb => write_pixel_rgb,
PixelFormat::Bgr => write_pixel_bgr, PixelFormat::Bgr => write_pixel_bgr,
@@ -118,21 +102,6 @@ impl UefiFb {
} }
}; };
let mut fill_rectangle = |(x1, y1), (x2, y2), color| { unsafe { write_pixel(&mut fb, index, rgb) };
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]);
} }
} }