asdf idk uhhhhh
This commit is contained in:
parent
354012852a
commit
c22758f860
|
@ -6,7 +6,8 @@ build-std = ["core", "compiler_builtins", "alloc"]
|
|||
build-std-features = ["compiler-builtins-mem"]
|
||||
|
||||
[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']
|
||||
rustflags = ["-Ctarget-feature=+sse,+mmx,+sse2,-soft-float"]
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
[workspace]
|
||||
members = ["bootloader"]
|
||||
members = ["bootloader", "kibble", "btrfs"]
|
|
@ -5,8 +5,13 @@ edition = "2021"
|
|||
|
||||
# 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"
|
||||
anyhow = {version = "1.0", 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"
|
||||
bitfield = "0.14"
|
||||
bytemuck = "1.12.3"
|
||||
bitflags = "1.3.1"
|
||||
|
||||
num-complex = {version = "0.4", default-features = false, features = ["libm"]}
|
||||
fontdue = {version = "0.7"}
|
||||
goblin = {version = "0.6", default-features = false, features = ["alloc", "pe32", "pe64"]}
|
||||
|
||||
uefi = { version = "0.18", features = ["alloc", "logger", "exts"] }
|
||||
uefi-services = "0.15"
|
||||
# uefi = { version = "0.19", features = ["alloc", "logger", "unstable"] }
|
||||
# uefi-services = "0.16"
|
||||
uefi = {path = "../../../uefi-rs/uefi", features = ["alloc", "logger", "unstable"] }
|
||||
uefi-services = {path = "../../../uefi-rs/uefi-services" }
|
||||
raw-cpuid = "10.0"
|
||||
x86_64 = "0.14"
|
||||
|
||||
ucs2 = {path = "../../nostd/ucs2-rs"}
|
||||
terminal = {path = "../../nostd/terminal"}
|
||||
serde_ini = {path = "../../nostd/serde-ini"}
|
||||
serde = {version = "1.0", default-features = false, features = ["alloc", "derive"]}
|
||||
toml = {path = "../../nostd/toml/crates/toml", default-features = false}
|
||||
serde = {version = "1.0", default-features = false, features = ["alloc", "derive"]}
|
||||
|
||||
[dev-dependencies]
|
||||
x86_64 = "0.14"
|
|
@ -1,8 +1,14 @@
|
|||
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> {
|
||||
handle: Handle,
|
||||
|
@ -20,4 +26,57 @@ impl<'a> Context<'a> {
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,10 @@ pub enum Error {
|
|||
NoAlignedSubslice,
|
||||
#[error("No Mode found for this GOP")]
|
||||
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}")]
|
||||
FontError(&'static str),
|
||||
#[error(transparent)]
|
||||
|
@ -23,6 +27,10 @@ pub enum Error {
|
|||
AllocError(#[from] alloc::alloc::AllocError),
|
||||
#[error("FromStrWithBufError: {0:?}")]
|
||||
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)]
|
||||
|
@ -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 {
|
||||
fn from(inner: uefi::Error) -> Self {
|
||||
Self::UefiError(UefiError { inner })
|
||||
|
|
|
@ -1,85 +1,26 @@
|
|||
use core::{
|
||||
alloc::{AllocError, Allocator, Layout},
|
||||
borrow::{Borrow, BorrowMut},
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
mem::MaybeUninit,
|
||||
ops::{Deref, DerefMut},
|
||||
ptr::NonNull,
|
||||
};
|
||||
use core::cell::{Ref, RefCell, RefMut};
|
||||
|
||||
use alloc::{borrow::ToOwned, boxed::Box, sync::Arc, vec, vec::Vec};
|
||||
use log::{debug, info};
|
||||
use alloc::{boxed::Box, sync::Arc, vec};
|
||||
use uefi::{
|
||||
data_types::Align,
|
||||
proto::media::{
|
||||
file::{Directory as UefiDirectory, File, FileAttribute, FileHandle, FileInfo, FileMode},
|
||||
fs::SimpleFileSystem,
|
||||
},
|
||||
table::boot::ScopedProtocol,
|
||||
CStr16, ResultExt, Status,
|
||||
CStr16,
|
||||
};
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::error::Result;
|
||||
|
||||
pub struct FileSystem<'a> {
|
||||
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 {
|
||||
use core::{
|
||||
alloc::{AllocError, Allocator, Layout},
|
||||
ops::Deref,
|
||||
};
|
||||
use core::ops::Deref;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use uefi::{
|
||||
data_types::Align,
|
||||
proto::media::file::{File, FileAttribute, FileHandle, FileInfo, FileMode},
|
||||
ResultExt, Status,
|
||||
};
|
||||
use uefi::proto::media::file::{File, FileAttribute, FileHandle, FileInfo, FileMode};
|
||||
|
||||
use crate::Result;
|
||||
|
||||
|
@ -130,37 +71,7 @@ pub mod dir {
|
|||
|
||||
impl Directory {
|
||||
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.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)
|
||||
}
|
||||
Ok(self.get_entry()?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)]
|
||||
#[derive(Clone)]
|
||||
pub struct Directory {
|
||||
|
@ -211,11 +114,8 @@ impl Directory {
|
|||
self.get_mut().open(filename, open_mode, attributes)
|
||||
}
|
||||
|
||||
pub fn read_entry<'buf>(
|
||||
&mut self,
|
||||
buffer: &'buf mut [u8],
|
||||
) -> uefi::Result<Option<&'buf mut FileInfo>, Option<usize>> {
|
||||
self.get_mut().read_entry(buffer)
|
||||
pub fn get_entry(&mut self) -> uefi::Result<Option<Box<FileInfo>>> {
|
||||
self.get_mut().read_entry_boxed()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,58 +1,50 @@
|
|||
#![feature(abi_efiapi)]
|
||||
#![feature(allocator_api)]
|
||||
#![feature(error_in_core)]
|
||||
#![feature(alloc_error_handler)]
|
||||
#![feature(negative_impls)]
|
||||
#![feature(int_roundings)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(iter_intersperse)]
|
||||
#![feature(
|
||||
allocator_api,
|
||||
ptr_metadata,
|
||||
error_in_core,
|
||||
alloc_error_handler,
|
||||
negative_impls,
|
||||
int_roundings,
|
||||
core_intrinsics
|
||||
)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use alloc::{collections::BTreeMap, string::String, vec};
|
||||
use graphics::GraphicsOutput;
|
||||
use alloc::{collections::BTreeMap, vec};
|
||||
use log::info;
|
||||
use serde::Deserialize;
|
||||
use uefi::{
|
||||
prelude::*,
|
||||
proto::{
|
||||
console::gop,
|
||||
media::file::{File, FileAttribute, FileMode},
|
||||
device_path::DevicePath,
|
||||
loaded_image::LoadedImage,
|
||||
media::{
|
||||
file::{File, FileAttribute, FileInfo, FileMode},
|
||||
fs::SimpleFileSystem,
|
||||
},
|
||||
},
|
||||
table::{
|
||||
boot::{OpenProtocolAttributes, OpenProtocolParams, SearchType},
|
||||
Boot, SystemTable,
|
||||
},
|
||||
Identify, Status,
|
||||
CString16, Identify, Status,
|
||||
};
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod context;
|
||||
mod error;
|
||||
mod fpu;
|
||||
mod fs;
|
||||
mod graphics;
|
||||
mod input;
|
||||
|
||||
use error::{Error, Result};
|
||||
|
||||
use crate::fpu::enable_fpu;
|
||||
use bootloader::{
|
||||
device_path::{DevicePathBuf, DevicePathBufBuilder},
|
||||
fpu::enable_fpu,
|
||||
fs,
|
||||
graphics::GraphicsOutput,
|
||||
Result,
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct Config {
|
||||
#[serde(rename = "FREELOADER")]
|
||||
freeloader: FreeLoaderConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct FreeLoaderConfig {
|
||||
timeout: u64,
|
||||
#[serde(rename = "DefaultOS")]
|
||||
default_os: String,
|
||||
font_path: String,
|
||||
timeout: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -63,10 +55,24 @@ pub struct Context {
|
|||
|
||||
impl Context {
|
||||
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 })
|
||||
}
|
||||
|
||||
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> {
|
||||
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)
|
||||
}
|
||||
|
||||
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> {
|
||||
info!("Hello, UEFI!");
|
||||
self.system_table_mut().stdin().reset(false)?;
|
||||
|
||||
enable_fpu().expect("no FPU/SSE/SSE2!");
|
||||
|
||||
let fs = self.fs()?;
|
||||
|
||||
for entry in fs.root_dir()?.into_iter() {
|
||||
info!("{:#?}", entry);
|
||||
if !entry.attribute().contains(FileAttribute::DIRECTORY) {
|
||||
let mut file = entry
|
||||
.open(FileMode::Read, None)?
|
||||
.into_regular_file()
|
||||
.unwrap();
|
||||
let filename = CString16::try_from("config.toml").unwrap();
|
||||
let mut config_file =
|
||||
fs.root_dir()?
|
||||
.open(&filename, FileMode::Read, FileAttribute::empty())?;
|
||||
|
||||
let mut buf = vec![0u8; entry.file_size() as usize];
|
||||
_ = file.read(&mut buf).unwrap();
|
||||
let s = String::from_utf8_lossy(&buf);
|
||||
info!("{:?}", s);
|
||||
}
|
||||
let mut buffer = vec![0; config_file.get_boxed_info::<FileInfo>()?.file_size() as usize];
|
||||
config_file
|
||||
.into_regular_file()
|
||||
.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()?;
|
||||
let (width, height) = display.resolution();
|
||||
|
||||
info!("creating terminal");
|
||||
|
||||
info!("done");
|
||||
loop {}
|
||||
|
||||
Ok(Status::SUCCESS)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[FREELOADER]
|
||||
TimeOut=10
|
||||
DefaultOS=Windows
|
20
qemu.sh
20
qemu.sh
|
@ -2,15 +2,31 @@
|
|||
|
||||
mkdir -vp esp/EFI/BOOT
|
||||
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 \
|
||||
-cpu host \
|
||||
-smp 2,sockets=1,dies=1,cores=2,threads=1 \
|
||||
-vga virtio \
|
||||
-nodefaults \
|
||||
-no-reboot \
|
||||
-serial stdio \
|
||||
-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_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
|
||||
|
||||
|
|
Loading…
Reference in a new issue