asdf idk uhhhhh

This commit is contained in:
Janis 2023-03-14 13:57:28 +01:00
parent 354012852a
commit c22758f860
9 changed files with 226 additions and 179 deletions

View file

@ -6,7 +6,8 @@ build-std = ["core", "compiler_builtins", "alloc"]
build-std-features = ["compiler-builtins-mem"] build-std-features = ["compiler-builtins-mem"]
[alias] [alias]
qemu = "run --target x86_64-unknown-uefi" qemu = "run --bin bootloader --target x86_64-unknown-uefi"
test-qemu = "test --bin test --target x86_64-unknown-uefi"
[target.'x86_64-unknown-uefi'] [target.'x86_64-unknown-uefi']
rustflags = ["-Ctarget-feature=+sse,+mmx,+sse2,-soft-float"] rustflags = ["-Ctarget-feature=+sse,+mmx,+sse2,-soft-float"]

View file

@ -1,2 +1,2 @@
[workspace] [workspace]
members = ["bootloader"] members = ["bootloader", "kibble", "btrfs"]

View file

@ -5,8 +5,13 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [lib]
[[bin]]
name = "read_btrfs"
path = "src/bin/read_btrfs.rs"
[dependencies]
log = "0.4" log = "0.4"
anyhow = {version = "1.0", default-features = false} anyhow = {version = "1.0", default-features = false}
thiserror = {path = "../../nostd/thiserror", default-features = false} thiserror = {path = "../../nostd/thiserror", default-features = false}
@ -15,17 +20,23 @@ itertools = {version = "0.10", default-features = false, features = ["use_alloc"
volatile = "0.4" volatile = "0.4"
bitfield = "0.14" bitfield = "0.14"
bytemuck = "1.12.3" bytemuck = "1.12.3"
bitflags = "1.3.1"
num-complex = {version = "0.4", default-features = false, features = ["libm"]} num-complex = {version = "0.4", default-features = false, features = ["libm"]}
fontdue = {version = "0.7"} fontdue = {version = "0.7"}
goblin = {version = "0.6", default-features = false, features = ["alloc", "pe32", "pe64"]} goblin = {version = "0.6", default-features = false, features = ["alloc", "pe32", "pe64"]}
uefi = { version = "0.18", features = ["alloc", "logger", "exts"] } # uefi = { version = "0.19", features = ["alloc", "logger", "unstable"] }
uefi-services = "0.15" # uefi-services = "0.16"
uefi = {path = "../../../uefi-rs/uefi", features = ["alloc", "logger", "unstable"] }
uefi-services = {path = "../../../uefi-rs/uefi-services" }
raw-cpuid = "10.0" raw-cpuid = "10.0"
x86_64 = "0.14" x86_64 = "0.14"
ucs2 = {path = "../../nostd/ucs2-rs"} ucs2 = {path = "../../nostd/ucs2-rs"}
terminal = {path = "../../nostd/terminal"} terminal = {path = "../../nostd/terminal"}
serde_ini = {path = "../../nostd/serde-ini"} toml = {path = "../../nostd/toml/crates/toml", default-features = false}
serde = {version = "1.0", default-features = false, features = ["alloc", "derive"]} serde = {version = "1.0", default-features = false, features = ["alloc", "derive"]}
[dev-dependencies]
x86_64 = "0.14"

View file

@ -1,8 +1,14 @@
use uefi::{ use uefi::{
prelude::BootServices, proto::loaded_image::LoadedImage, table::boot::ScopedProtocol, Handle, prelude::BootServices,
proto::{device_path::DevicePath, loaded_image::LoadedImage},
table::boot::ScopedProtocol,
CString16, Handle,
}; };
use crate::Result; use crate::{
device_path::{DevicePathBuf, DevicePathBufBuilder},
Result,
};
pub struct Context<'a> { pub struct Context<'a> {
handle: Handle, handle: Handle,
@ -20,4 +26,57 @@ impl<'a> Context<'a> {
image, image,
}) })
} }
pub fn handle(&self) -> Handle {
self.handle
}
pub fn image(&self) -> &ScopedProtocol<LoadedImage> {
&self.image
}
pub fn boot_services(&self) -> &BootServices {
self.boot_services
}
pub fn file_path(&self) -> Option<&DevicePath> {
self.image().file_path()
}
pub fn device_path(&self) -> Result<DevicePathBuf> {
let device_path = self
.boot_services()
.open_protocol_exclusive::<DevicePath>(self.image().device())?;
Ok(DevicePathBufBuilder::new()
.with_device_path(&*device_path)?
.finalize()?)
}
pub fn load_driver(&self, path: &str) -> Result<Handle> {
let driver_path = CString16::try_from(path)?;
let driver_device_path = DevicePathBufBuilder::new()
.with_device_path(self.device_path().expect("device path"))
.and_then(|builder| builder.with_file_path(&driver_path))
.and_then(|builder| builder.finalize())
.expect("device path");
let handle = self
.boot_services()
.load_image(
self.handle(),
uefi::table::boot::LoadImageSource::FromFilePath {
file_path: &driver_device_path,
from_boot_manager: false,
},
)
.expect("btrfs_driver_load");
self.boot_services()
.start_image(handle)
.expect("start btrfs driver");
Ok(handle)
}
} }

View file

@ -13,6 +13,10 @@ pub enum Error {
NoAlignedSubslice, NoAlignedSubslice,
#[error("No Mode found for this GOP")] #[error("No Mode found for this GOP")]
NoModeFound, NoModeFound,
#[error("supplied buffer was too small, needs to be at least {0} bytes wide.")]
BufferTooSmall(usize),
#[error(transparent)]
Utf8Error(#[from] core::str::Utf8Error),
#[error("{0}")] #[error("{0}")]
FontError(&'static str), FontError(&'static str),
#[error(transparent)] #[error(transparent)]
@ -23,6 +27,10 @@ pub enum Error {
AllocError(#[from] alloc::alloc::AllocError), AllocError(#[from] alloc::alloc::AllocError),
#[error("FromStrWithBufError: {0:?}")] #[error("FromStrWithBufError: {0:?}")]
FromStrWithBufError(uefi::data_types::FromStrWithBufError), FromStrWithBufError(uefi::data_types::FromStrWithBufError),
#[error("FromStrError: {0:?}")]
FromStrError(#[from] uefi::data_types::FromStrError),
#[error("DevicePathBuildError: {0:?}")]
DevicePathBuildError(uefi::proto::device_path::build::BuildError),
} }
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
@ -36,6 +44,12 @@ impl From<uefi::data_types::FromStrWithBufError> for Error {
} }
} }
impl From<uefi::proto::device_path::build::BuildError> for Error {
fn from(value: uefi::proto::device_path::build::BuildError) -> Self {
Self::DevicePathBuildError(value)
}
}
impl From<uefi::Error> for Error { impl From<uefi::Error> for Error {
fn from(inner: uefi::Error) -> Self { fn from(inner: uefi::Error) -> Self {
Self::UefiError(UefiError { inner }) Self::UefiError(UefiError { inner })

View file

@ -1,85 +1,26 @@
use core::{ use core::cell::{Ref, RefCell, RefMut};
alloc::{AllocError, Allocator, Layout},
borrow::{Borrow, BorrowMut},
cell::{Ref, RefCell, RefMut},
mem::MaybeUninit,
ops::{Deref, DerefMut},
ptr::NonNull,
};
use alloc::{borrow::ToOwned, boxed::Box, sync::Arc, vec, vec::Vec}; use alloc::{boxed::Box, sync::Arc, vec};
use log::{debug, info};
use uefi::{ use uefi::{
data_types::Align,
proto::media::{ proto::media::{
file::{Directory as UefiDirectory, File, FileAttribute, FileHandle, FileInfo, FileMode}, file::{Directory as UefiDirectory, File, FileAttribute, FileHandle, FileInfo, FileMode},
fs::SimpleFileSystem, fs::SimpleFileSystem,
}, },
table::boot::ScopedProtocol, table::boot::ScopedProtocol,
CStr16, ResultExt, Status, CStr16,
}; };
use crate::error::{Error, Result}; use crate::error::Result;
pub struct FileSystem<'a> { pub struct FileSystem<'a> {
inner: RefCell<ScopedProtocol<'a, SimpleFileSystem>>, inner: RefCell<ScopedProtocol<'a, SimpleFileSystem>>,
} }
pub struct FileInfoIterator {
dir: Directory,
}
impl FileInfoIterator {
pub fn new(dir: Directory) -> Self {
Self { dir }
}
pub fn next_entry(&mut self) -> Result<Option<Box<FileInfo>>> {
let layout = Layout::from_size_align(0, FileInfo::alignment())?;
let mut ptr = alloc::alloc::Global.allocate(layout)?;
if let Some(error) = self.dir.read_entry(unsafe { ptr.as_mut() }).err() {
match error.status() {
Status::BUFFER_TOO_SMALL => {
let layout = Layout::from_size_align(
error.data().expect("no size given after buffer_too_small!"),
FileInfo::alignment(),
)?;
let mut ptr = alloc::alloc::Global.allocate(layout)?;
let file_info = self
.dir
.read_entry(unsafe { ptr.as_mut() })
.map(|info| {
info.map(|info| unsafe { Box::<FileInfo>::from_raw(info as *mut _) })
.ok_or_else(|| unsafe {
alloc::alloc::Global.deallocate(ptr.cast(), layout);
AllocError
})
})
.discard_errdata()??;
Ok(Some(file_info))
}
_ => Err(error).discard_errdata()?,
}
} else {
Ok(None)
}
}
}
pub mod dir { pub mod dir {
use core::{ use core::ops::Deref;
alloc::{AllocError, Allocator, Layout},
ops::Deref,
};
use alloc::boxed::Box; use alloc::boxed::Box;
use uefi::{ use uefi::proto::media::file::{File, FileAttribute, FileHandle, FileInfo, FileMode};
data_types::Align,
proto::media::file::{File, FileAttribute, FileHandle, FileInfo, FileMode},
ResultExt, Status,
};
use crate::Result; use crate::Result;
@ -130,37 +71,7 @@ pub mod dir {
impl Directory { impl Directory {
pub fn next_entry(&mut self) -> Result<Option<Box<FileInfo>>> { pub fn next_entry(&mut self) -> Result<Option<Box<FileInfo>>> {
let layout = Layout::from_size_align(0, FileInfo::alignment())?; Ok(self.get_entry()?)
let mut ptr = alloc::alloc::Global.allocate(layout)?;
if let Some(error) = self.read_entry(unsafe { ptr.as_mut() }).err() {
match error.status() {
Status::BUFFER_TOO_SMALL => {
let layout = Layout::from_size_align(
error.data().expect("no size given after buffer_too_small!"),
FileInfo::alignment(),
)?;
let mut ptr = alloc::alloc::Global.allocate(layout)?;
let file_info = self
.read_entry(unsafe { ptr.as_mut() })
.map(|info| {
info.map(|info| unsafe {
Box::<FileInfo>::from_raw(info as *mut _)
})
.ok_or_else(|| unsafe {
alloc::alloc::Global.deallocate(ptr.cast(), layout);
AllocError
})
})
.discard_errdata()??;
Ok(Some(file_info))
}
_ => Err(error).discard_errdata()?,
}
} else {
Ok(None)
}
} }
} }
@ -179,14 +90,6 @@ pub mod dir {
} }
} }
impl Iterator for FileInfoIterator {
type Item = Box<FileInfo>;
fn next(&mut self) -> Option<Self::Item> {
self.next_entry().ok().flatten()
}
}
#[repr(transparent)] #[repr(transparent)]
#[derive(Clone)] #[derive(Clone)]
pub struct Directory { pub struct Directory {
@ -211,11 +114,8 @@ impl Directory {
self.get_mut().open(filename, open_mode, attributes) self.get_mut().open(filename, open_mode, attributes)
} }
pub fn read_entry<'buf>( pub fn get_entry(&mut self) -> uefi::Result<Option<Box<FileInfo>>> {
&mut self, self.get_mut().read_entry_boxed()
buffer: &'buf mut [u8],
) -> uefi::Result<Option<&'buf mut FileInfo>, Option<usize>> {
self.get_mut().read_entry(buffer)
} }
} }

View file

@ -1,58 +1,50 @@
#![feature(abi_efiapi)] #![feature(
#![feature(allocator_api)] allocator_api,
#![feature(error_in_core)] ptr_metadata,
#![feature(alloc_error_handler)] error_in_core,
#![feature(negative_impls)] alloc_error_handler,
#![feature(int_roundings)] negative_impls,
#![feature(core_intrinsics)] int_roundings,
#![feature(iter_intersperse)] core_intrinsics
)]
#![no_std] #![no_std]
#![no_main] #![no_main]
use alloc::{collections::BTreeMap, string::String, vec}; use alloc::{collections::BTreeMap, vec};
use graphics::GraphicsOutput;
use log::info; use log::info;
use serde::Deserialize; use serde::Deserialize;
use uefi::{ use uefi::{
prelude::*, prelude::*,
proto::{ proto::{
console::gop, console::gop,
media::file::{File, FileAttribute, FileMode}, device_path::DevicePath,
loaded_image::LoadedImage,
media::{
file::{File, FileAttribute, FileInfo, FileMode},
fs::SimpleFileSystem,
},
}, },
table::{ table::{
boot::{OpenProtocolAttributes, OpenProtocolParams, SearchType}, boot::{OpenProtocolAttributes, OpenProtocolParams, SearchType},
Boot, SystemTable, Boot, SystemTable,
}, },
Identify, Status, CString16, Identify, Status,
}; };
extern crate alloc; extern crate alloc;
mod context; use bootloader::{
mod error; device_path::{DevicePathBuf, DevicePathBufBuilder},
mod fpu; fpu::enable_fpu,
mod fs; fs,
mod graphics; graphics::GraphicsOutput,
mod input; Result,
};
use error::{Error, Result};
use crate::fpu::enable_fpu;
#[allow(dead_code)]
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Config { pub struct Config {
#[serde(rename = "FREELOADER")] timeout: Option<u64>,
freeloader: FreeLoaderConfig,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct FreeLoaderConfig {
timeout: u64,
#[serde(rename = "DefaultOS")]
default_os: String,
font_path: String,
} }
#[derive(Debug)] #[derive(Debug)]
@ -63,10 +55,24 @@ pub struct Context {
impl Context { impl Context {
pub fn new(handle: Handle, mut st: SystemTable<Boot>) -> uefi::Result<Self> { pub fn new(handle: Handle, mut st: SystemTable<Boot>) -> uefi::Result<Self> {
uefi_services::init(&mut st)?; uefi_services::init(&mut st).expect("services");
enable_fpu().expect("no FPU/SSE/SSE2!");
Ok(Self { handle, st }) Ok(Self { handle, st })
} }
pub fn device_path(&self) -> Result<DevicePathBuf> {
let loaded_image = self
.boot_services()
.open_protocol_exclusive::<LoadedImage>(self.handle())?;
let device_path = self
.boot_services()
.open_protocol_exclusive::<DevicePath>(loaded_image.device())?;
Ok(DevicePathBufBuilder::new()
.with_device_path(&*device_path)?
.finalize()?)
}
pub fn fs(&self) -> Result<fs::FileSystem> { pub fn fs(&self) -> Result<fs::FileSystem> {
let file_system = self.st.boot_services().get_image_file_system(self.handle)?; let file_system = self.st.boot_services().get_image_file_system(self.handle)?;
@ -128,37 +134,80 @@ impl Context {
GraphicsOutput::from_gop_with_mode(gop, mode) GraphicsOutput::from_gop_with_mode(gop, mode)
} }
pub fn load_driver(&self, path: &str) -> Result<Handle> {
let driver_path = CString16::try_from(path)?;
let driver_device_path = DevicePathBufBuilder::new()
.with_device_path(self.device_path().expect("device path"))
.and_then(|builder| builder.with_file_path(&driver_path))
.and_then(|builder| builder.finalize())
.expect("device path");
let handle = self
.boot_services()
.load_image(
self.handle(),
uefi::table::boot::LoadImageSource::FromFilePath {
file_path: &driver_device_path,
from_boot_manager: false,
},
)
.expect("btrfs_driver_load");
self.boot_services()
.start_image(handle)
.expect("start btrfs driver");
Ok(handle)
}
pub fn run(mut self) -> Result<Status> { pub fn run(mut self) -> Result<Status> {
info!("Hello, UEFI!"); info!("Hello, UEFI!");
self.system_table_mut().stdin().reset(false)?; self.system_table_mut().stdin().reset(false)?;
enable_fpu().expect("no FPU/SSE/SSE2!");
let fs = self.fs()?; let fs = self.fs()?;
for entry in fs.root_dir()?.into_iter() { let filename = CString16::try_from("config.toml").unwrap();
info!("{:#?}", entry); let mut config_file =
if !entry.attribute().contains(FileAttribute::DIRECTORY) { fs.root_dir()?
let mut file = entry .open(&filename, FileMode::Read, FileAttribute::empty())?;
.open(FileMode::Read, None)?
.into_regular_file()
.unwrap();
let mut buf = vec![0u8; entry.file_size() as usize]; let mut buffer = vec![0; config_file.get_boxed_info::<FileInfo>()?.file_size() as usize];
_ = file.read(&mut buf).unwrap(); config_file
let s = String::from_utf8_lossy(&buf); .into_regular_file()
info!("{:?}", s); .unwrap()
} .read(&mut buffer)
.unwrap();
let config = toml::from_str::<Config>(&core::str::from_utf8(&buffer).expect("from_utf8"))
.expect("toml parse");
info!("config: {:?}", config);
drop(fs);
self.load_driver("bootloader\\drivers\\btrfs_x64.efi")
.expect("driver");
let handles = self
.boot_services()
.find_handles::<SimpleFileSystem>()
.expect("SFS handles");
for handle in handles {
if let Ok(mut sfs) = self
.boot_services()
.open_protocol_exclusive::<SimpleFileSystem>(handle)
{
let mut dir = sfs.open_volume().expect("root dir");
let info = dir.get_boxed_info::<FileInfo>();
info!("{:?}", info);
};
} }
let mut display = self.get_graphics_output()?; info!("done");
let (width, height) = display.resolution();
info!("creating terminal");
loop {} loop {}
Ok(Status::SUCCESS)
} }
} }

View file

@ -1,3 +0,0 @@
[FREELOADER]
TimeOut=10
DefaultOS=Windows

20
qemu.sh
View file

@ -2,15 +2,31 @@
mkdir -vp esp/EFI/BOOT mkdir -vp esp/EFI/BOOT
cp $1 esp/EFI/BOOT/BOOTX64.EFI cp $1 esp/EFI/BOOT/BOOTX64.EFI
shift
exec qemu-system-x86_64 -accel kvm \ echo "$(pwd)"
qemu-system-x86_64 -accel kvm \
-m 4G \ -m 4G \
-cpu host \ -cpu host \
-smp 2,sockets=1,dies=1,cores=2,threads=1 \ -smp 2,sockets=1,dies=1,cores=2,threads=1 \
-vga virtio \ -vga virtio \
-nodefaults \
-no-reboot \ -no-reboot \
-serial stdio \ -serial stdio \
-usb -device usb-mouse \ -usb -device usb-mouse \
-drive if=pflash,format=raw,readonly=on,file=/usr/share/ovmf/x64/OVMF_CODE.fd \ -drive if=pflash,format=raw,readonly=on,file=/usr/share/ovmf/x64/OVMF_CODE.fd \
-drive if=pflash,format=raw,readonly=on,file=/usr/share/ovmf/x64/OVMF_VARS.fd \ -drive if=pflash,format=raw,readonly=on,file=/usr/share/ovmf/x64/OVMF_VARS.fd \
-drive format=raw,file=fat:rw:esp -device isa-debug-exit,iobase=0xf4,iosize=0x04 \
-drive format=qcow2,file=btrfs.qcow2 \
-drive format=qcow2,file=ntfs.qcow2 \
-drive format=raw,file=fat:rw:esp $@ \
-drive format=qcow2,file=windows.qcow2
case $? in
33)
exit 0;;
*)
exit $?;;
esac