cfg: allow passing cmdline options to the kernel

This commit is contained in:
Mark Poliakov 2024-12-17 19:12:39 +02:00
parent cb5814a5ce
commit 49b918e2ac
27 changed files with 571 additions and 75 deletions

2
.gitignore vendored
View File

@ -1,3 +1,5 @@
/target
/toolchain
/xtask.toml
/qemu.toml
/etc/boot/yboot.cfg

View File

@ -15,6 +15,9 @@ pub struct LoadProtocol {
pub memory_map: MemoryMap,
pub cmdline: u64,
pub cmdline_len: u64,
pub rsdp_address: u64,
pub initrd_address: u64,
pub initrd_size: u64,

39
boot/yboot/src/config.rs Normal file
View File

@ -0,0 +1,39 @@
use uefi::{
proto::media::file::{Directory, File, FileAttribute, FileMode},
CStr16, Result, Status,
};
#[derive(Debug)]
pub struct Config {
pub cmdline: [u8; 4096],
pub cmdline_len: usize,
}
impl Default for Config {
fn default() -> Self {
Self {
cmdline: [0; 4096],
cmdline_len: 0,
}
}
}
impl Config {
pub fn load(root: &mut Directory, path: &CStr16) -> Result<Self> {
let file = match root.open(path, FileMode::Read, FileAttribute::empty()) {
Ok(file) => file,
Err(error) => {
root.reset_entry_readout().ok();
log::warn!("Couldn't open {path:?}: {error:?}");
return Ok(Self::default());
}
};
root.reset_entry_readout().ok();
let mut this = Self::default();
let mut file = file.into_regular_file().ok_or(Status::INVALID_PARAMETER)?;
this.cmdline_len = file.read(&mut this.cmdline)?;
Ok(this)
}
}

View File

@ -2,6 +2,7 @@
#![no_std]
#![no_main]
pub mod config;
pub mod elf;
pub mod initrd;
pub mod mem;
@ -9,6 +10,7 @@ pub mod protocol_ext;
use core::{arch::asm, mem::size_of, ops::Deref};
use config::Config;
use elf::Object;
use log::{debug, error, info};
use uefi::{
@ -17,7 +19,7 @@ use uefi::{
console::gop::{GraphicsOutput, PixelFormat},
device_path::DevicePath,
loaded_image::LoadedImage,
media::fs::SimpleFileSystem,
media::{file::Directory, fs::SimpleFileSystem},
},
table::{
boot::{AllocateType, MemoryType, ScopedProtocol},
@ -94,27 +96,45 @@ fn boot_partition(
bs.open_protocol_exclusive::<SimpleFileSystem>(fs_handle)
}
fn open_root(image: Handle, bs: &BootServices) -> Result<Directory, Error> {
let mut boot_partition = boot_partition(image, bs)?;
boot_partition.open_volume()
}
fn load_kernel<'a>(
ih: Handle,
config: &Config,
root: &mut Directory,
st: &SystemTable<Boot>,
) -> Result<(u64, u64, &'a mut LoadProtocolV1), Error> {
let bs = st.boot_services();
let mut fs = boot_partition(ih, bs)?;
let mut root = fs.open_volume()?;
let mut kernel_obj = Object::open(&mut root, cstr16!("kernel.elf"))?;
let mut kernel_obj = Object::open(root, cstr16!("kernel.elf"))?;
let loaded_obj = kernel_obj.load(bs)?;
debug!("Loaded object: {:#x?}", loaded_obj);
// Load initrd
let (initrd_start, initrd_size) = initrd::load_somewhere(bs, &mut root, cstr16!("initrd.img"))?;
let (initrd_start, initrd_size) = initrd::load_somewhere(bs, root, cstr16!("initrd.img"))?;
debug!(
"Loaded initrd: {:#x?}",
initrd_start..initrd_start + initrd_size
);
// Load cmdline
let cmdline = if config.cmdline_len != 0 {
let address = bs.allocate_pages(AllocateType::AnyPages, MemoryType::LOADER_DATA, 1)?;
let dst =
unsafe { core::slice::from_raw_parts_mut(address as *mut u8, config.cmdline_len) };
dst.copy_from_slice(&config.cmdline[..config.cmdline_len]);
debug!("Cmdline at {:#x?}", address);
address
} else {
0
};
// Other versions are not existent yet
assert_eq!(loaded_obj.protocol_version, 1);
let proto_data = unsafe { &mut *(loaded_obj.protocol_struct_paddr as *mut LoadProtocolV1) };
@ -125,6 +145,9 @@ fn load_kernel<'a>(
})?;
info!("RSDP at {:#x}", rsdp);
proto_data.cmdline = cmdline;
proto_data.cmdline_len = config.cmdline_len as _;
proto_data.rsdp_address = rsdp;
proto_data.initrd_address = initrd_start;
proto_data.initrd_size = initrd_size;
@ -190,9 +213,35 @@ unsafe fn map_and_enter_kernel(
#[entry]
fn efi_main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
uefi_services::init(&mut system_table).unwrap();
if uefi_services::init(&mut system_table).is_err() {
return Status::LOAD_ERROR;
}
let (entry, mmap_memory, proto_data) = load_kernel(image_handle, &system_table).unwrap();
let bs = system_table.boot_services();
let mut root = match open_root(image_handle, bs) {
Ok(root) => root,
Err(error) => {
error!("Could not open boot partition root: {error:?}");
return Status::LOAD_ERROR;
}
};
let config = match Config::load(&mut root, cstr16!("yboot.cfg")) {
Ok(config) => config,
Err(error) => {
error!("Malformed yboot.cfg: {error:?}");
return Status::LOAD_ERROR;
}
};
let (entry, mmap_memory, proto_data) = match load_kernel(&config, &mut root, &system_table) {
Ok(e) => e,
Err(error) => {
error!("Failed to load the kernel/initrd: {error:?}");
return Status::LOAD_ERROR;
}
};
unsafe {
map_and_enter_kernel(system_table, proto_data, mmap_memory, entry);

View File

@ -536,7 +536,7 @@ impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
for TaskContextImpl<K, PA>
{
fn drop(&mut self) {
log::info!("Drop Context {:#p}", self);
log::trace!("Drop Context {:#p}", self);
assert_eq!(self.stack_size % 0x1000, 0);
for offset in (0..self.stack_size).step_by(0x1000) {

View File

@ -18,8 +18,8 @@ use device_api::{
};
use drive::NvmeNamespace;
use libk::{
devfs,
device::manager::probe_partitions,
fs::devfs,
task::{cpu_count, cpu_index, runtime},
};
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo, L3_PAGE_SIZE};

View File

@ -66,10 +66,9 @@ impl Node {
// Don't even try if `status = "disabled"`
if let Some(status) = self.property("status") {
let status = status.as_str();
match status {
Some("disabled") => return (None, parent_bus),
_ => (),
let status = status.as_str().unwrap_or("");
if status == "disabled" {
return (None, parent_bus);
}
}
@ -127,7 +126,7 @@ impl Node {
/// Performs a lazy initialization of the node:
///
/// 1. If the node hasn't yet been probed for a device, a driver is looked up
/// (see [Node::probe]).
/// (see [Node::probe]).
/// 2. If the node hasn't yet been initialized, initialization is performed.
///
/// Returns:

View File

@ -80,6 +80,11 @@ impl<'a> DeviceTree<'a> {
self.index.root()
}
/// Dump the device tree into the debug log
pub fn dump(&self) {
dump(self.root(), 0)
}
/// Looks up a node by its `/absolute/path`.
pub fn find_absolute(&'a self, path: &str) -> Option<TNode<'a>> {
let mut path = path.trim_start_matches('/');
@ -159,6 +164,11 @@ impl<'a> DeviceTree<'a> {
))
}
/// Returns the value of `/chosen/bootargs` interpreted as a string
pub fn chosen_bootargs(&self) -> Option<&str> {
self.root().child("chosen")?.prop_string("bootargs")
}
/// Returns an iterator over the memory regions specified by this device tree
pub fn memory_regions(&self) -> DeviceTreeMemoryRegionIter {
DeviceTreeMemoryRegionIter::new(self)
@ -178,3 +188,103 @@ impl<'a> DeviceTree<'a> {
}
unsafe impl Sync for DeviceTree<'_> {}
fn indent(amount: usize) {
log::info!(target: "raw", "{0:1$}", "", amount * 2);
}
fn dump_property(node: &TNode, prop: TProp, level: usize) {
enum Type {
String,
Cells,
Bytes,
}
let node_name = node.name().unwrap_or("");
let name = prop.name().unwrap_or("<unknown-prop>");
indent(level);
log::info!(target: "raw", "{name}");
if prop.len() == 0 {
log::info!(target: "raw", ";\n");
return;
}
log::info!(target: "raw", " = ");
let ty = match name {
"model" | "compatible" | "clock-output-names" | "clock-names" | "device_type"
| "enable-method" | "status" | "label" | "method" => Type::String,
"stdout-path" | "bootargs" if node_name == "chosen" => Type::String,
_ if node_name == "aliases" => Type::String,
_ if prop.len() % size_of::<u32>() == 0 => Type::Cells,
_ => Type::Bytes,
};
match ty {
Type::String => {
// "..."
for (i, string) in prop.as_str_list().enumerate() {
if i != 0 {
log::info!(target: "raw", ", ");
}
log::info!(target: "raw", "{string:?}");
}
}
Type::Cells => {
// <...>
log::info!(target: "raw", "<");
let mut i = 0;
while let Some(value) = prop.read_cell(i, 1) {
if i != 0 {
log::info!(target: "raw", ", ");
}
log::info!(target: "raw", "{value:#x}");
i += 1;
}
log::info!(target: "raw", ">");
}
Type::Bytes => {
// <...>
log::info!(target: "raw", "<");
for (i, byte) in prop.raw().iter().enumerate() {
if i != 0 {
log::info!(target: "raw", ", ");
}
log::info!(target: "raw", "{byte:#x}");
}
log::info!(target: "raw", ">");
}
}
log::info!(target: "raw", ";\n");
}
fn dump(node: TNode, level: usize) {
let name = node.name().unwrap_or("<unknown>");
indent(level);
if name.is_empty() {
log::info!(target: "raw", "{{\n");
} else {
log::info!(target: "raw", "{name}: {{\n");
}
let mut do_break = false;
for property in node.props() {
dump_property(&node, property, level + 1);
do_break = true;
}
for child in node.children() {
if do_break {
log::info!(target: "raw", "\n");
do_break = false;
}
dump(child, level + 1);
}
indent(level);
log::info!(target: "raw", "}}\n");
}

View File

@ -0,0 +1,57 @@
use core::str::FromStr;
use crate::debug::LogLevel;
use super::SetOption;
/// Debugging/logging-related options
#[derive(Debug)]
pub struct DebugOptions {
/// Default log level used for serial devices
pub serial_level: LogLevel,
/// Default log level used for proper display devices
pub display_level: LogLevel,
/// If set, logs produced by the `debug_trace` syscall are ignored
pub disable_program_trace: bool,
}
impl Default for DebugOptions {
fn default() -> Self {
Self {
serial_level: LogLevel::Info,
display_level: LogLevel::Info,
disable_program_trace: false,
}
}
}
impl SetOption for DebugOptions {
fn set_key_value(&mut self, key: &str, value: &str) -> bool {
match key {
"serial-level" if let Ok(level) = LogLevel::from_str(value) => {
self.serial_level = level;
true
}
"display-level" if let Ok(level) = LogLevel::from_str(value) => {
self.display_level = level;
true
}
"log_level" if let Ok(level) = LogLevel::from_str(value) => {
self.serial_level = level;
self.display_level = level;
true
}
_ => false,
}
}
fn set_flag(&mut self, value: &str) -> bool {
match value {
"disable-program-trace" => {
self.disable_program_trace = true;
true
}
_ => false,
}
}
}

View File

@ -0,0 +1,118 @@
//! Kernel commandline parameters handling
use alloc::string::String;
use libk_util::OneTimeInit;
use yggdrasil_abi::error::Error;
use crate::fs::sysfs::{
self,
attribute::{StringAttribute, StringAttributeOps},
};
#[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))]
mod x86;
#[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))]
pub use x86::X86Options;
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
mod x86_64;
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
pub use x86_64::X86_64Options;
mod general;
pub use general::DebugOptions;
trait SetOption {
fn set_key_value(&mut self, key: &str, value: &str) -> bool;
fn set_flag(&mut self, value: &str) -> bool;
}
/// Kernel commandline options
#[derive(Debug, Default)]
pub struct Options {
pub debug: DebugOptions,
#[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))]
pub x86: X86Options,
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
pub x86_64: X86_64Options,
}
impl SetOption for Options {
fn set_flag(&mut self, value: &str) -> bool {
match value {
_ if let Some(value) = value.strip_prefix("debug.") => self.debug.set_flag(value),
#[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))]
_ if let Some(value) = value.strip_prefix("x86.") => self.x86.set_flag(value),
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
_ if let Some(value) = value.strip_prefix("x86_64.") => self.x86_64.set_flag(value),
_ => false,
}
}
fn set_key_value(&mut self, key: &str, value: &str) -> bool {
match key {
_ if let Some(key) = key.strip_prefix("debug.") => self.debug.set_key_value(key, value),
#[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))]
_ if let Some(key) = key.strip_prefix("x86.") => self.x86.set_key_value(key, value),
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
_ if let Some(key) = key.strip_prefix("x86_64.") => {
self.x86_64.set_key_value(key, value)
}
_ => false,
}
}
}
static OPTIONS: OneTimeInit<Options> = OneTimeInit::new();
static OPTIONS_STRING: OneTimeInit<String> = OneTimeInit::new();
pub fn get() -> &'static Options {
OPTIONS.get()
}
fn parse_argument(options: &mut Options, arg: &str) -> bool {
let arg = arg.trim();
if let Some((key, value)) = arg.split_once('=') {
options.set_key_value(key.trim_end(), value.trim_start())
} else {
options.set_flag(arg)
}
}
/// Sets up kernel options from an argument list
pub fn parse_boot_argument_list<'a, I: Iterator<Item = &'a str>>(args: I) {
let mut options = Default::default();
let mut string = String::new();
args.for_each(|arg| {
if parse_argument(&mut options, arg) {
string.push_str(arg);
string.push('\n');
}
});
OPTIONS.init(options);
OPTIONS_STRING.init(string);
// Add to sysfs
if let Some(kernel) = sysfs::kernel() {
struct Cmdline;
impl StringAttributeOps for Cmdline {
const NAME: &'static str = "cmdline";
const NEWLINE: bool = false;
fn read(_state: &Self::Data) -> Result<String, Error> {
Ok(OPTIONS_STRING.get().into())
}
}
kernel.add_attribute(StringAttribute::from(Cmdline)).ok();
}
}
/// Sets up kernel options from an argument string, where options are separated by whitespace
pub fn parse_boot_arguments(args: &str) {
parse_boot_argument_list(args.trim().split(' '));
}

View File

@ -0,0 +1,30 @@
use super::SetOption;
#[derive(Debug)]
pub struct X86Options {
pub disable_boot_fb: bool,
}
impl Default for X86Options {
fn default() -> Self {
Self {
disable_boot_fb: false,
}
}
}
impl SetOption for X86Options {
fn set_flag(&mut self, value: &str) -> bool {
match value {
"disable-boot-fb" => {
self.disable_boot_fb = true;
true
}
_ => false,
}
}
fn set_key_value(&mut self, _key: &str, _value: &str) -> bool {
false
}
}

View File

@ -0,0 +1,30 @@
use super::SetOption;
#[derive(Debug)]
pub struct X86_64Options {
pub disable_hpet: bool,
}
impl Default for X86_64Options {
fn default() -> Self {
Self {
disable_hpet: false,
}
}
}
impl SetOption for X86_64Options {
fn set_key_value(&mut self, _key: &str, _value: &str) -> bool {
false
}
fn set_flag(&mut self, value: &str) -> bool {
match value {
"disable-hpet" => {
self.disable_hpet = true;
true
}
_ => false,
}
}
}

View File

@ -25,6 +25,7 @@ use libk_util::{
use yggdrasil_abi::error::Error;
use crate::{
config,
fs::sysfs::{
self,
attribute::{StringAttribute, StringAttributeOps},
@ -56,7 +57,7 @@ pub struct RingLoggerSink {
}
/// Defines the severity of the message
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum LogLevel {
/// Very verbose low-level debugging information
Trace,
@ -138,7 +139,14 @@ impl DebugSinkWrapper {
impl log::Log for DebugSinkWrapper {
fn enabled(&self, metadata: &log::Metadata) -> bool {
LogLevel::from(metadata.level()) >= self.level()
if LogLevel::from(metadata.level()) < self.level() {
return false;
}
if metadata.target() == "program" && config::get().debug.disable_program_trace {
return false;
}
true
}
fn log(&self, record: &log::Record) {

View File

@ -9,7 +9,8 @@ use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
use yggdrasil_abi::error::Error;
use crate::{
debug::{self, DebugSink, LogLevel},
config,
debug::{self, DebugSink},
fs::devfs,
vfs::NodeRef,
};
@ -92,12 +93,12 @@ impl SerialTerminalRegistry {
pub fn register(
&self,
terminal: Arc<dyn CharDevice>,
sink_level: Option<(Arc<dyn DebugSink>, LogLevel)>,
sink: Option<Arc<dyn DebugSink>>,
) -> Result<u32, Error> {
let id = self.registry.register(terminal.clone())?;
devfs::add_named_char_device(terminal, format!("ttyS{id}")).ok();
if let Some((sink, sink_level)) = sink_level {
debug::add_serial_sink(sink, sink_level);
if let Some(sink) = sink {
debug::add_serial_sink(sink, config::get().debug.serial_level);
}
Ok(id)
}

View File

@ -24,6 +24,7 @@ pub trait StringAttributeOps: Sync + Send + 'static {
const WRITEABLE: bool = false;
const NAME: &'static str;
const LIMIT: usize = 4096;
const NEWLINE: bool = true;
fn read(state: &Self::Data) -> Result<String, Error> {
let _ = state;
@ -69,7 +70,9 @@ impl<V: StringAttributeOps> RegularImpl for StringAttributeNode<V> {
}
let mut value = V::read(self.object.data())?.into_bytes();
value.push(b'\n');
if V::NEWLINE {
value.push(b'\n');
}
let instance = StringAttributeState {
value: IrqSafeRwLock::new(value),

View File

@ -35,6 +35,7 @@ pub use yggdrasil_abi::error;
pub mod task;
pub mod arch;
pub mod config;
pub mod debug;
pub mod device;
pub mod fs;

View File

@ -18,7 +18,7 @@ use kernel_arch_aarch64::{
},
ArchitectureImpl, PerCpuData,
};
use libk::{arch::Cpu, debug, device::external_interrupt_controller};
use libk::{arch::Cpu, config, debug, device::external_interrupt_controller};
use libk_mm::{
address::PhysicalAddress,
phys::{self, reserved::reserve_region, PhysicalMemoryRegion},
@ -252,37 +252,11 @@ impl AArch64 {
atomic::compiler_fence(Ordering::SeqCst);
// TODO
// ygg_driver_pci::register_vendor_driver(
// "Virtio PCI GPU Device",
// 0x1AF4,
// 0x1050,
// ygg_driver_virtio_gpu::probe,
// );
// ygg_driver_pci::register_vendor_driver(
// "Virtio PCI Network Device",
// 0x1AF4,
// 0x1000,
// ygg_driver_virtio_net::probe,
// );
// ygg_driver_pci::register_class_driver(
// "AHCI SATA Controller",
// 0x01,
// Some(0x06),
// Some(0x01),
// ygg_driver_ahci::probe,
// );
// ygg_driver_pci::register_class_driver(
// "USB xHCI",
// 0x0C,
// Some(0x03),
// Some(0x30),
// ygg_driver_usb_xhci::probe,
// );
debug::init();
let dt = self.dt.get();
let bootargs = dt.chosen_bootargs().unwrap_or("");
config::parse_boot_arguments(bootargs);
// Create device tree sysfs nodes
device_tree::util::create_sysfs_nodes(dt);
@ -302,6 +276,7 @@ impl AArch64 {
log::info!("Running on {machine:?}");
MACHINE_NAME.init(machine.into());
}
log::info!("Boot arguments: {bootargs:?}");
log::info!("Initializing aarch64 platform");

View File

@ -1,3 +1,5 @@
use core::ffi::CStr;
use libk_mm::{
address::{PhysicalAddress, Virtualize},
phys::PhysicalMemoryRegion,
@ -87,6 +89,16 @@ impl MultibootInfo {
let base = PhysicalAddress::from_u32(self.mods_addr).virtualize();
unsafe { core::slice::from_raw_parts(base as *const _, self.mods_count as usize) }
}
pub fn cmdline(&self) -> &str {
if self.cmdline == 0 {
""
} else {
let address = PhysicalAddress::from_u32(self.cmdline).virtualize();
let data = unsafe { CStr::from_ptr(core::ptr::with_exposed_provenance(address)) };
data.to_str().unwrap_or("")
}
}
}
impl MultibootMemoryMapEntry {

View File

@ -13,7 +13,7 @@ use kernel_arch_i686::{gdt, mem::table::L3, PerCpuData};
use kernel_arch_x86::cpuid::{self, CpuFeatures, EcxFeatures, EdxFeatures};
use libk::{
arch::Cpu,
debug::{self, LogLevel},
config, debug,
device::{
display::{
console::{add_console_autoflush, ConsoleWrapper},
@ -130,7 +130,7 @@ impl I686 {
80,
25,
)?);
debug::add_sink(textfb.clone(), LogLevel::Info);
debug::add_sink(textfb.clone(), config::get().debug.display_level);
add_console_autoflush(textfb.clone());
let textfb_console = Arc::new(Terminal::from_parts(
@ -155,14 +155,19 @@ impl I686 {
self.init_memory_management(multiboot_info)
.expect("Could not initialize memory management");
// Set kernel commandline
let cmdline = multiboot_info.cmdline();
self.init_cpu().expect("Could not initialize CPU");
x86::register_pci_drivers();
let early = x86::init_platform_devices_early()?;
let early = x86::init_platform_early(cmdline)?;
if let Err(error) = self.init_framebuffer() {
log::error!("Could not initialize boot framebuffer: {error:?}");
if !config::get().x86.disable_boot_fb {
if let Err(error) = self.init_framebuffer() {
log::error!("Could not initialize boot framebuffer: {error:?}");
}
}
x86::add_legacy_pci();

View File

@ -5,7 +5,11 @@
use abi::error::Error;
use alloc::{sync::Arc, vec::Vec};
use device_api::{device::Device, interrupt::Irq};
use libk::{debug, devfs, task::runtime};
use libk::{
config, debug,
fs::{devfs, sysfs},
task::runtime,
};
use libk_mm::{
address::{PhysicalAddress, Virtualize},
phys::{self, PhysicalMemoryRegion},
@ -96,10 +100,13 @@ pub fn register_pci_drivers() {
// Initialize the bare minimum required to:
// * Allocate/manage interrupts
// * Print debug output
pub fn init_platform_devices_early() -> Result<EarlyPlatformDevices, Error> {
pub fn init_platform_early(cmdline: &str) -> Result<EarlyPlatformDevices, Error> {
sysfs::init();
devfs::init();
debug::init();
config::parse_boot_arguments(cmdline);
// Initialize async executor queue
runtime::init_task_queue();

View File

@ -6,7 +6,7 @@ use device_api::{
interrupt::{InterruptHandler, Irq},
};
use libk::{
debug::{DebugSink, LogLevel},
debug::DebugSink,
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
vfs::{Terminal, TerminalInput, TerminalOutput},
};
@ -117,7 +117,7 @@ impl Device for Port {
unsafe fn init(self: Arc<Self>) -> Result<(), Error> {
DEVICE_REGISTRY
.serial_terminal
.register(self.terminal.clone(), Some((self.clone(), LogLevel::Debug)))
.register(self.terminal.clone(), Some(self.clone()))
.ok();
Ok(())
}

View File

@ -3,6 +3,7 @@ use core::{arch::global_asm, sync::atomic::Ordering};
use kernel_arch_x86::registers::MSR_IA32_KERNEL_GS_BASE;
use kernel_arch_x86_64::CPU_COUNT;
use libk_mm::address::{PhysicalAddress, Virtualize};
use tock_registers::interfaces::Writeable;
use yboot_proto::{
v1::{FramebufferOption, MemoryMap},
@ -17,6 +18,29 @@ pub enum BootData {
YBoot(&'static LoadProtocolV1),
}
impl BootData {
pub fn cmdline(&self) -> &str {
match self {
&Self::YBoot(data) => {
if data.cmdline != 0 && data.cmdline_len != 0 {
let address = PhysicalAddress::from_u64(data.cmdline).virtualize();
let len = data.cmdline_len as usize;
let raw = unsafe {
core::slice::from_raw_parts(
core::ptr::with_exposed_provenance(address),
len,
)
};
core::str::from_utf8(raw).unwrap_or("")
} else {
""
}
}
}
}
}
const BOOT_STACK_SIZE: usize = 1024 * 1024;
#[repr(C, align(0x20))]
@ -40,6 +64,9 @@ static YBOOT_DATA: LoadProtocolV1 = LoadProtocolV1 {
memory_map: MemoryMap { address: 0, len: 0 },
cmdline: 0,
cmdline_len: 0,
rsdp_address: 0,
initrd_address: 0,
initrd_size: 0,

View File

@ -21,13 +21,13 @@ use kernel_arch_x86_64::{
};
use libk::{
arch::Cpu,
debug::{self, LogLevel},
devfs,
config, debug,
device::{
display::{fb_console::FramebufferConsole, DriverFlags, PixelFormat},
manager::DEVICE_REGISTRY,
register_external_interrupt_controller,
},
fs::devfs,
};
use libk_mm::{
address::PhysicalAddress,
@ -259,17 +259,25 @@ impl X86_64 {
self.setup_from_boot_data()?;
let mut early = x86::init_platform_devices_early()?;
// TODO yboot doesn't yet pass any command line options
let cmdline = self.boot_data.get().cmdline();
let mut early = x86::init_platform_early(cmdline)?;
if let Err(error) = self.init_framebuffer() {
log::error!("Could not initialize boot framebuffer: {error:?}");
if !config::get().x86.disable_boot_fb {
if let Err(error) = self.init_framebuffer() {
log::error!("Could not initialize boot framebuffer: {error:?}");
}
}
if let Some(acpi) = self.acpi.try_get() {
self.init_platform_from_acpi(acpi)?;
}
early.add_preferred_clock_source("hpet", Self::setup_hpet);
if !config::get().x86_64.disable_hpet {
early.add_preferred_clock_source("hpet", Self::setup_hpet);
} else {
log::info!("HPET disabled by config");
}
x86::init_platform_devices(early);
}
@ -434,7 +442,7 @@ impl X86_64 {
true,
)?));
debug::add_sink(fbconsole.clone(), LogLevel::Info);
debug::add_sink(fbconsole.clone(), config::get().debug.display_level);
Ok(())
}

View File

@ -16,7 +16,7 @@ use device_tree::{
DeviceTreePropertyRead,
};
use libk::{
debug::{DebugSink, LogLevel},
debug::DebugSink,
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
vfs::{Terminal, TerminalInput, TerminalOutput},
};
@ -170,7 +170,7 @@ impl Device for Bcm2835AuxUart {
DEVICE_REGISTRY
.serial_terminal
.register(inner.clone(), Some((self.clone(), LogLevel::Debug)))
.register(inner.clone(), Some(self.clone()))
.ok();
Ok(())

View File

@ -7,7 +7,7 @@ use device_api::{
};
use device_tree::driver::{device_tree_driver, Node, ProbeContext};
use libk::{
debug::{DebugSink, LogLevel},
debug::DebugSink,
device::{external_interrupt_controller, manager::DEVICE_REGISTRY},
vfs::{Terminal, TerminalInput, TerminalOutput},
};
@ -158,7 +158,7 @@ impl Device for Pl011 {
DEVICE_REGISTRY
.serial_terminal
.register(terminal.clone(), Some((self.clone(), LogLevel::Info)))
.register(terminal.clone(), Some(self.clone()))
.ok();
Ok(())

View File

@ -37,6 +37,7 @@ pub enum CargoBuilder<'e> {
impl<'e> CargoBuilder<'e> {
pub fn run<P: AsRef<Path>, S: AsRef<OsStr>>(self, dir: P, arg: S) -> Result<(), Error> {
let arg = arg.as_ref();
let mut command = Command::new("cargo");
command.current_dir(dir);
@ -134,12 +135,17 @@ impl<'e> CargoBuilder<'e> {
.join(env.kernel_triple)
.display()
);
let artifact_dir_arg =
format!("--artifact-dir={}", env.kernel_output_dir.display());
command.arg(target_spec_arg);
command.arg(target_dir_arg);
command.arg(artifact_dir_arg);
if arg != "clippy" && arg != "check" {
let artifact_dir_arg =
format!("--artifact-dir={}", env.kernel_output_dir.display());
command.arg(artifact_dir_arg);
}
command.args([
"-Z",
"build-std=core,alloc,compiler_builtins",

View File

@ -49,6 +49,7 @@ fn build_uefi_image(
) -> Result<ImageBuilt, Error> {
log::info!("Building x86-64 UEFI image");
let image_path = env.kernel_output_dir.join("image.fat32");
let yboot_cfg = env.workspace_root.join("etc/boot/yboot.cfg");
if !image_path.exists() {
util::run_external_command(
@ -81,6 +82,11 @@ fn build_uefi_image(
copy_into_fat(&boot_dir, &yboot.0, "BootX64.efi")?;
copy_into_fat(&root_dir, &kernel.0 .0, "kernel.elf")?;
copy_into_fat(&root_dir, &initrd.0, "initrd.img")?;
if yboot_cfg.exists() {
copy_into_fat(&root_dir, &yboot_cfg, "yboot.cfg")?;
} else {
root_dir.remove("yboot.cfg").ok();
}
Ok(ImageBuilt(image_path))
}