Skip to content

Commit a9c8e9e

Browse files
committed
First prototype implementation of ELF loading and config parsing in UEFI binary
1 parent 048b6a0 commit a9c8e9e

File tree

4 files changed

+126
-31
lines changed

4 files changed

+126
-31
lines changed

Cargo.lock

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ authors = ["Philipp Oppermann <dev@phil-opp.com>"]
55
license = "MIT/Apache-2.0"
66
description = "An experimental x86_64 bootloader that works on both BIOS and UEFI systems."
77
repository = "https://github.com/rust-osdev/bootloader"
8-
edition = "2018"
8+
edition = "2021"
99

1010
[workspace]
1111
members = [
@@ -39,7 +39,7 @@ x86_64 = { version = "0.14.7", optional = true, default-features = false, featur
3939
usize_conversions = { version = "0.2.0", optional = true }
4040
bit_field = { version = "0.10.0", optional = true }
4141
log = { version = "0.4.8", optional = true }
42-
uefi = { version = "0.11.0", optional = true }
42+
uefi = { version = "0.13.0", optional = true }
4343
argh = { version = "0.1.3", optional = true }
4444
displaydoc = { version = "0.1.7", optional = true }
4545
conquer-once = { version = "0.2.1", optional = true, default-features = false }
@@ -50,7 +50,7 @@ thiserror = { version = "1.0.20", optional = true }
5050
json = { version = "0.12.4", optional = true }
5151
rsdp = { version = "1.0.0", optional = true }
5252
fatfs = { version = "0.3.4", optional = true }
53-
gpt = { version = "2.0.0", optional = true }
53+
gpt = { version = "3.0.0", optional = true }
5454

5555
[dependencies.font8x8]
5656
version = "0.2.5"

src/bin/uefi.rs

Lines changed: 107 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,113 @@
77
#[repr(align(4096))]
88
struct PageAligned<T>(T);
99

10-
use bootloader::binary::{legacy_memory_region::LegacyFrameAllocator, SystemInfo};
11-
use bootloader_api::info::FrameBufferInfo;
12-
use core::{arch::asm, mem, panic::PanicInfo, slice};
10+
use bootloader::binary::{legacy_memory_region::LegacyFrameAllocator, Kernel, SystemInfo};
11+
use bootloader_api::{info::FrameBufferInfo, BootloaderConfig};
12+
use core::{arch::asm, mem, panic::PanicInfo, ptr, slice};
1313
use uefi::{
1414
prelude::{entry, Boot, Handle, ResultExt, Status, SystemTable},
15-
proto::console::gop::{GraphicsOutput, PixelFormat},
16-
table::boot::{MemoryDescriptor, MemoryType},
17-
Completion,
15+
proto::{
16+
console::gop::{GraphicsOutput, PixelFormat},
17+
device_path::DevicePath,
18+
loaded_image::LoadedImage,
19+
media::{
20+
file::{File, FileAttribute, FileInfo, FileMode},
21+
fs::SimpleFileSystem,
22+
},
23+
},
24+
table::boot::{AllocateType, MemoryDescriptor, MemoryType},
25+
CStr16, Completion,
1826
};
1927
use x86_64::{
2028
structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB},
2129
PhysAddr, VirtAddr,
2230
};
31+
use xmas_elf::ElfFile;
2332

2433
#[entry]
2534
fn efi_main(image: Handle, st: SystemTable<Boot>) -> Status {
26-
let (framebuffer_addr, framebuffer_info) = init_logger(&st);
27-
log::info!("Hello World from UEFI bootloader!");
35+
main_inner(image, st)
36+
}
37+
38+
fn main_inner(image: Handle, mut st: SystemTable<Boot>) -> Status {
39+
let mut buf = [0; 100];
40+
st.stdout()
41+
.output_string(
42+
CStr16::from_str_with_buf("UEFI bootloader started; trying to load kernel", &mut buf)
43+
.unwrap(),
44+
)
45+
.unwrap()
46+
.unwrap();
47+
48+
let file_system_raw = {
49+
let ref this = st.boot_services();
50+
let loaded_image = this
51+
.handle_protocol::<LoadedImage>(image)?
52+
.expect("Failed to retrieve `LoadedImage` protocol from handle");
53+
let loaded_image = unsafe { &*loaded_image.get() };
54+
55+
let device_handle = loaded_image.device();
56+
57+
let device_path = this
58+
.handle_protocol::<DevicePath>(device_handle)?
59+
.expect("Failed to retrieve `DevicePath` protocol from image's device handle");
60+
let mut device_path = unsafe { &*device_path.get() };
61+
62+
let device_handle = this
63+
.locate_device_path::<SimpleFileSystem>(&mut device_path)?
64+
.expect("Failed to locate `SimpleFileSystem` protocol on device path");
65+
66+
this.handle_protocol::<SimpleFileSystem>(device_handle)
67+
}
68+
.unwrap()
69+
.unwrap();
70+
let file_system = unsafe { &mut *file_system_raw.get() };
71+
72+
let mut root = file_system.open_volume().unwrap().unwrap();
73+
let kernel_file_handle = root
74+
.open("kernel-x86_64", FileMode::Read, FileAttribute::empty())
75+
.unwrap()
76+
.unwrap();
77+
let mut kernel_file = match kernel_file_handle.into_type().unwrap().unwrap() {
78+
uefi::proto::media::file::FileType::Regular(f) => f,
79+
uefi::proto::media::file::FileType::Dir(_) => panic!(),
80+
};
81+
82+
let mut buf = [0; 100];
83+
let kernel_info: &mut FileInfo = kernel_file.get_info(&mut buf).unwrap().unwrap();
84+
let kernel_size = usize::try_from(kernel_info.file_size()).unwrap();
85+
86+
let kernel_ptr = st
87+
.boot_services()
88+
.allocate_pages(
89+
AllocateType::AnyPages,
90+
MemoryType::LOADER_DATA,
91+
((kernel_size - 1) / 4096) + 1,
92+
)
93+
.unwrap()
94+
.unwrap() as *mut u8;
95+
unsafe { ptr::write_bytes(kernel_ptr, 0, kernel_size) };
96+
let kernel_slice = unsafe { slice::from_raw_parts_mut(kernel_ptr, kernel_size) };
97+
kernel_file.read(kernel_slice).unwrap().unwrap();
98+
99+
let kernel_elf = ElfFile::new(kernel_slice).unwrap();
100+
101+
let config = {
102+
let section = kernel_elf
103+
.find_section_by_name(".bootloader-config")
104+
.unwrap();
105+
let raw = section.raw_data(&kernel_elf);
106+
BootloaderConfig::deserialize(raw).unwrap()
107+
};
108+
109+
let kernel = Kernel {
110+
elf: kernel_elf,
111+
config,
112+
};
113+
114+
let (framebuffer_addr, framebuffer_info) = init_logger(&st, config);
115+
log::info!("UEFI bootloader started");
116+
log::info!("Reading kernel and configuration from disk was successful");
28117
log::info!("Using framebuffer at {:#x}", framebuffer_addr);
29118

30119
let mmap_storage = {
@@ -62,7 +151,7 @@ fn efi_main(image: Handle, st: SystemTable<Boot>) -> Status {
62151
};
63152

64153
bootloader::binary::load_and_switch_to_kernel(
65-
&KERNEL.0,
154+
kernel,
66155
frame_allocator,
67156
page_tables,
68157
system_info,
@@ -135,7 +224,7 @@ fn create_page_tables(
135224
}
136225
}
137226

138-
fn init_logger(st: &SystemTable<Boot>) -> (PhysAddr, FrameBufferInfo) {
227+
fn init_logger(st: &SystemTable<Boot>, config: BootloaderConfig) -> (PhysAddr, FrameBufferInfo) {
139228
let gop = st
140229
.boot_services()
141230
.locate_protocol::<GraphicsOutput>()
@@ -145,8 +234,14 @@ fn init_logger(st: &SystemTable<Boot>) -> (PhysAddr, FrameBufferInfo) {
145234
let mode = {
146235
let modes = gop.modes().map(Completion::unwrap);
147236
match (
148-
CONFIG.minimum_framebuffer_height,
149-
CONFIG.minimum_framebuffer_width,
237+
config
238+
.frame_buffer
239+
.minimum_framebuffer_height
240+
.map(|v| usize::try_from(v).unwrap()),
241+
config
242+
.frame_buffer
243+
.minimum_framebuffer_width
244+
.map(|v| usize::try_from(v).unwrap()),
150245
) {
151246
(Some(height), Some(width)) => modes
152247
.filter(|m| {

src/binary/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ pub struct SystemInfo {
5959
}
6060

6161
pub struct Kernel<'a> {
62-
elf: ElfFile<'a>,
63-
config: BootloaderConfig,
62+
pub elf: ElfFile<'a>,
63+
pub config: BootloaderConfig,
6464
}
6565

6666
/// Loads the kernel ELF executable into memory and switches to it.

0 commit comments

Comments
 (0)