Merge branch 'master' into master

This commit is contained in:
IntoTheNight 2023-07-13 14:25:20 +00:00
commit bea92d996c
12 changed files with 1800 additions and 221 deletions

1704
Cargo.lock generated

File diff suppressed because it is too large Load diff

0
a.out
View file

View file

@ -7,7 +7,7 @@ version = "0.2.0"
[dependencies] [dependencies]
hbvm = { git = "https://git.ablecorp.us/ableos/holey-bytes" } hbvm = { git = "https://git.ablecorp.us/ableos/holey-bytes" }
hbasm = { git = "https://git.ablecorp.us/ableos/holey-bytes" } # hbasm = { git = "https://git.ablecorp.us/ableos/holey-bytes" }
embedded-graphics = "0.7.1" embedded-graphics = "0.7.1"

View file

@ -48,7 +48,7 @@ SECTIONS
. = ALIGN(4K); . = ALIGN(4K);
PROVIDE(_initial_kernel_heap_start = .); PROVIDE(_initial_kernel_heap_start = .);
/* PROVIDE(_initial_kernel_heap_size = 1024 * 1024); */ /* PROVIDE(_initial_kernel_heap_size = 1024 * 1024); */
PROVIDE(_initial_kernel_heap_size = 1024 * 4096); PROVIDE(_initial_kernel_heap_size = 1024 * 4096 * 100);
. += _initial_kernel_heap_size; . += _initial_kernel_heap_size;
} :data } :data
} }

View file

@ -63,49 +63,26 @@ pub enum HostError {
// // pub fn rpc_register(_engine: &mut Engine) {} // // pub fn rpc_register(_engine: &mut Engine) {}
// // pub fn rpc_call(_engine: &mut Engine) {} // // pub fn rpc_call(_engine: &mut Engine) {}
use log::error; use {hbvm::vm::mem::HandlePageFault, log::error};
use hbvm::vm::{
mem::{Memory, MemoryAccessReason, PageSize},
trap::HandleTrap,
value::Value,
};
/// AbleOS HBVM traphandler /// AbleOS HBVM traphandler
pub struct TrapHandler; pub struct TrapHandler;
impl HandleTrap for TrapHandler { impl HandlePageFault for TrapHandler {
fn page_fault( fn page_fault(
&mut self, &mut self,
mar: MemoryAccessReason, reason: hbvm::vm::mem::MemoryAccessReason,
memory: &mut Memory, memory: &mut hbvm::vm::mem::Memory,
vaddr: u64, vaddr: u64,
size: PageSize, size: hbvm::vm::mem::PageSize,
dataptr: *mut u8, dataptr: *mut u8,
) -> bool { ) -> bool {
error!( error!(
"MemoryAccessReason: {} "REASON: {}
Memory: {:?} memory: {:?}
VAddr: {} vaddr: {}
Size: {:?} size: {:?}
DataPTR: {:?}", Dataptr {:?}",
mar, memory, vaddr, size, dataptr reason, memory, vaddr, size, dataptr
); );
false false
} }
fn invalid_op(&mut self, _: &mut [Value; 256], _: &mut usize, _: &mut Memory, _: u8) -> bool
where
Self: Sized,
{
log::trace!("Invalid opcode");
false
}
fn ecall(&mut self, _: &mut [Value; 256], _: &mut usize, _: &mut Memory)
where
Self: Sized,
{
log::trace!("ableOS system call made");
}
} }

View file

@ -1,15 +1,12 @@
//! AbleOS Kernel Entrypoint //! AbleOS Kernel Entrypoint
use crate::capabilities;
// use crate::arch::sloop; // use crate::arch::sloop;
use { use {
crate::{ crate::{
arch::logging::SERIAL_CONSOLE,
bootmodules::{build_cmd, BootModules}, bootmodules::{build_cmd, BootModules},
capabilities,
device_tree::DeviceTree, device_tree::DeviceTree,
scheduler::Scheduler, scheduler::Scheduler,
}, },
alloc::format, alloc::format,
log::{debug, info, trace}, log::{debug, info, trace},
@ -43,69 +40,12 @@ pub fn kmain(cmdline: &str, boot_modules: BootModules) -> ! {
capabilities::example(); capabilities::example();
// TODO: change this to a driver
{
let mut prog = alloc::vec![];
let mut code = alloc::string::String::new();
let mut sc = SERIAL_CONSOLE.lock();
loop {
match sc.receive() {
b'\r' => {
code.push('\n');
sc.send(b'\r');
sc.send(b'\n');
match hbasm::assembly(&code, &mut prog) {
Ok(_) => {
use hbvm::validate::validate;
match validate(&prog) {
Err(_e) => {
// log::error!("Program validation error: {e:?}");
}
Ok(_) => {
// log::info!("valid program");
// use {crate::host::TrapHandler, hbvm::vm::Vm};
let mut sched = Scheduler::new(); let mut sched = Scheduler::new();
sched.new_process(prog.clone()); // AHEM that isn't a valid HBVM program
sched.scheduler_run(); sched.new_process(boot_modules[0].bytes.clone());
// let mut vm; sched.new_process(boot_modules[1].bytes.clone());
// unsafe {
// vm = Vm::new_unchecked(&prog, TrapHandler);
// vm.memory.insert_test_page();
// }
// log::info!("Program interrupt: {:?}", vm.run());
// log::debug!("{:?}", vm.registers);
}
}
sc.send(b'>');
}
Err(_e) => {
// log::error!(
// "Error {:?} at {:?} (`{}`)",
// e.kind,
// e.span.clone(),
// &code[e.span],
// );
for x in "err".as_bytes() {
sc.send(*x);
}
}
}
code = alloc::string::String::new();
}
byte => {
code.push(byte as char);
sc.send(byte);
}
}
}
}
sched.run();
// sloop(); // sloop();
} }

View file

@ -16,16 +16,17 @@ impl log::Log for Logger {
fn log(&self, record: &log::Record) { fn log(&self, record: &log::Record) {
let lvl = record.level(); let lvl = record.level();
crate::arch::log(format_args!( let lvl_color = match lvl {
"\x1b[38;5;{}m{lvl}\x1b[0m [{}]: {}\r\n",
match lvl {
Level::Error => "160", Level::Error => "160",
Level::Warn => "172", Level::Warn => "172",
Level::Info => "47", Level::Info => "47",
Level::Debug => "25", Level::Debug => "25",
Level::Trace => "103", Level::Trace => "103",
}, };
record.module_path().unwrap_or_default(), let module = record.module_path().unwrap_or_default();
let line = record.line().unwrap_or_default();
crate::arch::log(format_args!(
"\x1b[38;5;{lvl_color}m{lvl}\x1b[0m [{module}:{line}]: {}\r\n",
record.args(), record.args(),
)) ))
.expect("write to serial console"); .expect("write to serial console");

View file

@ -4,21 +4,19 @@ use {
}; };
use {crate::host::TrapHandler, hbvm::vm::Vm}; use {crate::host::TrapHandler, hbvm::vm::Vm};
const TIMER_QUOTIENT: usize = 100;
pub struct Scheduler<'a> { pub struct Scheduler<'a> {
data: VecDeque<Vm<'a, TrapHandler>>, data: VecDeque<Vm<'a, TrapHandler, TIMER_QUOTIENT>>,
} }
// NOTE: This is a very simple schduler and it sucks and should be replaced with a better one // NOTE: This is a very simple schduler and it sucks and should be replaced with a better one
// Written By Yours Truly: Munir // Written By Yours Truly: Munir
impl Scheduler<'_> { impl Scheduler<'_> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
data: VecDeque::new(), data: VecDeque::new(),
} }
} }
pub fn new_process(&mut self, program: Vec<u8>) { pub fn new_process(&mut self, program: Vec<u8>) {
@ -41,10 +39,19 @@ impl Scheduler<'_> {
} }
} }
pub fn scheduler_run(&mut self) -> Option<u32> { pub fn run(&mut self) -> ! {
loop { loop {
// If there are no programs to run then sleep.
if self.data.is_empty() {
use crate::arch::sloop;
sloop();
}
let mut prog = self.data.pop_front().unwrap(); let mut prog = self.data.pop_front().unwrap();
prog.run().unwrap(); prog.run().unwrap();
// log::info!("VM registers {:?}", prog.registers);
log::info!("Scheduled program");
self.data.push_back(prog); self.data.push_back(prog);
} }
} }

View file

@ -4,7 +4,16 @@ version = "0.2.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
cpio_reader = "0.1"
derive_more = "0.99"
env_logger = "0.10" env_logger = "0.10"
error-stack = "0.2" error-stack = "0.2"
fatfs = "0.3" fatfs = "0.3"
log = "0.4" log = "0.4"
rpm = "0.11"
zstd = "0.12"
[dependencies.reqwest]
version = "0.11"
default-features = false
features = ["rustls-tls", "blocking"]

BIN
repbuild/inf_loop.hb Normal file

Binary file not shown.

View file

@ -18,8 +18,8 @@ TERM_BACKDROP=008080
# Setting a default resolution for the framebuffer # Setting a default resolution for the framebuffer
RESOLUTION=1024x768x24 RESOLUTION=1024x768x24
MODULE_PATH=boot:///background.bmp MODULE_PATH=boot:///inf_loop.hb
MODULE_CMDLINE="diskid=123456789" MODULE_CMDLINE="diskid=123456789"
MODULE_PATH=boot:///background.bmp MODULE_PATH=boot:///inf_loop.hb
MODULE_CMDLINE="" MODULE_CMDLINE=""

View file

@ -1,9 +1,14 @@
use std::fs;
use { use {
error_stack::{bail, report, Context, IntoReport, Result, ResultExt}, derive_more::{Deref, DerefMut, Display},
error_stack::{bail, ensure, report, Context, IntoReport, Result, ResultExt},
fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek}, fatfs::{FileSystem, FormatVolumeOptions, FsOptions, ReadWriteSeek},
std::{fmt::Display, fs::File, io, path::Path, process::Command}, std::{
fmt::Display,
fs::File,
io::{self, Write},
path::Path,
process::Command,
},
}; };
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
@ -110,12 +115,18 @@ fn get_fs() -> Result<FileSystem<impl ReadWriteSeek>, io::Error> {
&mut File::open("repbuild/background.bmp")?, &mut File::open("repbuild/background.bmp")?,
&mut fs.root_dir().create_file("background.bmp")?, &mut fs.root_dir().create_file("background.bmp")?,
)?; )?;
io::copy(
&mut File::open("repbuild/inf_loop.hb")?,
&mut fs.root_dir().create_file("inf_loop.hb")?,
)?;
drop(bootdir); drop(bootdir);
Ok(fs) Ok(fs)
} }
fn build(release: bool, target: Target) -> Result<(), Error> { fn build(release: bool, target: Target) -> Result<(), Error> {
fetch_ovmf().change_context(Error::OvmfFetch)?;
let fs = get_fs().change_context(Error::Io)?; let fs = get_fs().change_context(Error::Io)?;
let mut com = Command::new("cargo"); let mut com = Command::new("cargo");
com.current_dir("kernel"); com.current_dir("kernel");
@ -124,12 +135,9 @@ fn build(release: bool, target: Target) -> Result<(), Error> {
com.arg("-r"); com.arg("-r");
} }
match target { if target == Target::Riscv64Virt {
Target::Riscv64Virt => {
com.args(["--target", "targets/riscv64-virt-ableos.json"]); com.args(["--target", "targets/riscv64-virt-ableos.json"]);
} }
_ => {}
}
match com.status() { match com.status() {
Ok(s) if s.code() != Some(0) => bail!(Error::Build), Ok(s) if s.code() != Some(0) => bail!(Error::Build),
@ -165,10 +173,7 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
if target == Target::X86_64 { if target == Target::X86_64 {
#[rustfmt::skip] #[rustfmt::skip]
com.args([ com.args([
"-bios", "-bios", "target/OVMF_CODE.fd",
std::env::var("REPBUILD_QEMU_FIRMWARE_PATH")
.as_deref()
.unwrap_or("/usr/share/ovmf/x64/OVMF_CODE.fd"),
"-drive", "file=target/disk.img,format=raw", "-drive", "file=target/disk.img,format=raw",
"-m", "4G", "-m", "4G",
// "-serial", "stdio", // "-serial", "stdio",
@ -217,33 +222,121 @@ fn run(release: bool, target: Target) -> Result<(), Error> {
} }
} }
fn fetch_ovmf() -> Result<(), OvmfFetchError> {
const OVMF_RPM_URL: &str = "https://kojipkgs.fedoraproject.org/packages/edk2/20230524/3.fc38/noarch/edk2-ovmf-20230524-3.fc38.noarch.rpm";
let mut file = match std::fs::metadata("target/OVMF_CODE.fd") {
Err(e) if e.kind() == std::io::ErrorKind::NotFound => std::fs::OpenOptions::new()
.create(true)
.write(true)
.read(true)
.open("target/OVMF_CODE.fd")
.into_report()
.change_context(OvmfFetchError::Io)?,
Ok(_) => return Ok(()),
Err(e) => return Err(report!(e).change_context(OvmfFetchError::Io)),
};
log::info!("No OVMF found, downloading…");
let rpm = rpm::RPMPackage::parse(
&mut std::convert::identity::<reqwest::Result<_>>((|| {
reqwest::blocking::get(OVMF_RPM_URL)?.bytes()
})())
.into_report()
.change_context(OvmfFetchError::Fetch)?
.as_ref(),
)
.map_err(RpmError)
.into_report()
.change_context(OvmfFetchError::RpmParse)?;
ensure!(
rpm.metadata
.get_payload_compressor()
.map_err(RpmError)
.into_report()
.change_context(OvmfFetchError::RpmParse)?
== rpm::CompressionType::Zstd,
OvmfFetchError::UnsupportedCompression,
);
file.write_all(
cpio_reader::iter_files(
&zstd::decode_all(std::io::Cursor::new(rpm.content))
.into_report()
.change_context(OvmfFetchError::Zstd)?,
)
.find(|file| file.name() == "./usr/share/edk2/ovmf/OVMF_CODE.fd")
.ok_or_else(|| report!(OvmfFetchError::NoFileFound))?
.file(),
)
.into_report()
.change_context(OvmfFetchError::Io)?;
Ok(())
}
#[derive(Debug, Display, Deref, DerefMut)]
struct RpmError(rpm::RPMError);
impl Context for RpmError {}
// Ehhh?? I am pretty sure they just forgot :ferrisClueless:
unsafe impl Sync for RpmError {}
unsafe impl Send for RpmError {}
#[derive(Debug, Display)]
enum OvmfFetchError {
#[display(fmt = "Failed to fetch OVMF package")]
Fetch,
#[display(fmt = "RPM parse error")]
RpmParse,
#[display(fmt = "Unsupported compression (ZSTD is the only supported one)")]
UnsupportedCompression,
#[display(fmt = "Decompression error")]
Zstd,
#[display(fmt = "Requested file not found in package")]
NoFileFound,
#[display(fmt = "IO Error")]
Io,
}
impl Context for OvmfFetchError {}
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
enum Target { enum Target {
X86_64, X86_64,
Riscv64Virt, Riscv64Virt,
} }
#[derive(Debug)] #[derive(Debug, Display)]
enum Error { enum Error {
#[display(fmt = "Failed to build the kernel")]
Build, Build,
#[display(fmt = "Missing or invalid subcommand (available: build, run)")]
InvalidSubCom, InvalidSubCom,
#[display(fmt = "IO Error")]
Io, Io,
#[display(fmt = "Failed to spawn a process")]
ProcessSpawn, ProcessSpawn,
#[display(fmt = "Failed to fetch UEFI firmware")]
OvmfFetch,
#[display(fmt = "QEMU Error: {}", "fmt_qemu_err(*_0)")]
Qemu(Option<i32>), Qemu(Option<i32>),
} }
impl Context for Error {} impl Context for Error {}
impl Display for Error {
fn fmt_qemu_err(e: Option<i32>) -> impl Display {
struct W(Option<i32>);
impl Display for W {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { if let Some(c) = self.0 {
Self::Build => f.write_str("failed to build the kernel"), c.fmt(f)
Self::InvalidSubCom => { } else {
f.write_str("missing or invalid subcommand (available: build, run)") f.write_str("Interrupted by signal")
}
Self::Io => f.write_str("IO error"),
Self::ProcessSpawn => f.write_str("failed to spawn a process"),
Self::Qemu(Some(c)) => write!(f, "QEMU Error: {c}"),
Self::Qemu(None) => write!(f, "QEMU Error: interrupted by signal"),
} }
} }
}
W(e)
} }