Skip to content

Framebuffer configuration #179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Oct 7, 2021
41 changes: 29 additions & 12 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ fn main() {

#[cfg(feature = "binary")]
mod binary {
use proc_macro2::TokenStream;
use quote::quote;
use std::convert::TryInto;

Expand Down Expand Up @@ -281,19 +282,29 @@ mod binary {
};

// Write config to file
let file_path = out_dir.join("bootloader_config.rs");
let mut file = File::create(file_path).expect("failed to create bootloader_config.rs");
file.write_all(
quote::quote! {
mod parsed_config {
use crate::config::Config;
pub const CONFIG: Config = #config;
let write_config = |path: &str, import: TokenStream| {
let file_path = out_dir.join(path);
let mut file = File::create(file_path).expect("failed to create config file");
file.write_all(
quote::quote! {
mod parsed_config {
use #import;
pub const CONFIG: Config = #config;
}
}
}
.to_string()
.as_bytes(),
)
.expect("write to bootloader_config.rs failed");
.to_string()
.as_bytes(),
)
.expect("writing config failed");
};
write_config(
"bootloader_config.rs",
quote::quote! { crate::config::Config },
);
write_config(
"kernel_bootloader_config.rs",
quote::quote! { bootloader::Config },
);

println!("cargo:rerun-if-env-changed=KERNEL");
println!("cargo:rerun-if-env-changed=KERNEL_MANIFEST");
Expand Down Expand Up @@ -326,6 +337,8 @@ mod binary {
pub kernel_stack_address: Option<AlignedAddress>,
pub boot_info_address: Option<AlignedAddress>,
pub framebuffer_address: Option<AlignedAddress>,
pub desired_framebuffer_height: Option<usize>,
pub desired_framebuffer_width: Option<usize>,
}

/// Convert to tokens suitable for initializing the `Config` struct.
Expand All @@ -344,6 +357,8 @@ mod binary {
let kernel_stack_address = optional(self.kernel_stack_address);
let boot_info_address = optional(self.boot_info_address);
let framebuffer_address = optional(self.framebuffer_address);
let desired_framebuffer_height = optional(self.desired_framebuffer_height);
let desired_framebuffer_width = optional(self.desired_framebuffer_width);

tokens.extend(quote! { Config {
map_physical_memory: #map_physical_memory,
Expand All @@ -355,6 +370,8 @@ mod binary {
kernel_stack_address: #kernel_stack_address,
boot_info_address: #boot_info_address,
framebuffer_address: #framebuffer_address,
desired_framebuffer_height: #desired_framebuffer_height,
desired_framebuffer_width: #desired_framebuffer_width
}});
}
}
Expand Down
23 changes: 23 additions & 0 deletions src/bin/uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

// Defines the constants `KERNEL_BYTES` (array of `u8`) and `KERNEL_SIZE` (`usize`).
include!(concat!(env!("OUT_DIR"), "/kernel_info.rs"));
// Contains the bootloader configuration specified by the kernel crate (needed for GOP configuration)
include!(concat!(env!("OUT_DIR"), "/kernel_bootloader_config.rs"));

static KERNEL: PageAligned<[u8; KERNEL_SIZE]> = PageAligned(KERNEL_BYTES);

Expand All @@ -18,10 +20,12 @@ use bootloader::{
boot_info::FrameBufferInfo,
};
use core::{mem, panic::PanicInfo, slice};
use parsed_config::CONFIG;
use uefi::{
prelude::{entry, Boot, Handle, ResultExt, Status, SystemTable},
proto::console::gop::{GraphicsOutput, PixelFormat},
table::boot::{MemoryDescriptor, MemoryType},
Completion,
};
use x86_64::{
structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB},
Expand Down Expand Up @@ -149,6 +153,25 @@ fn init_logger(st: &SystemTable<Boot>) -> (PhysAddr, FrameBufferInfo) {
.expect_success("failed to locate gop");
let gop = unsafe { &mut *gop.get() };

let mode = {
let modes = gop.modes().map(Completion::unwrap);
match (
CONFIG.desired_framebuffer_height,
CONFIG.desired_framebuffer_width,
) {
(Some(height), Some(width)) => modes
.filter(|m| m.info().resolution() == (width, height))
.last(),
(Some(height), None) => modes.filter(|m| m.info().resolution().1 == height).last(),
(None, Some(width)) => modes.filter(|m| m.info().resolution().0 == width).last(),
_ => None,
}
};
if let Some(mode) = mode {
gop.set_mode(&mode)
.expect_success("failed to apply gop mode");
}

let mode_info = gop.current_mode_info();
let mut framebuffer = gop.frame_buffer();
let slice = unsafe { slice::from_raw_parts_mut(framebuffer.as_mut_ptr(), framebuffer.size()) };
Expand Down
12 changes: 12 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,16 @@ pub struct Config {
///
/// Only considered if `map_framebuffer` is `true`.
pub framebuffer_address: Option<u64>,
/// Desired height of the framebuffer mode when running in UEFI mode.
///
/// Defaults to using the default mode if neither `desired_framebuffer_height` or
/// `desired_framebuffer_width` is supplied, and using the last available mode that
/// fits them if 1 or more is set.
pub desired_framebuffer_height: Option<usize>,
/// Desired width of the framebuffer mode when running in UEFI mode.
///
/// Defaults to using the default mode if neither `desired_framebuffer_height` or
/// `desired_framebuffer_width` is supplied, and using the last available mode that
/// fits them if 1 or more is set.
pub desired_framebuffer_width: Option<usize>,
}