Some device discovery support

This commit is contained in:
River 2025-05-20 00:52:19 -04:00
parent 154c9512dc
commit 24524c104f
Signed by: shibedrill
GPG Key ID: 5FE0CB25945EFAA2
9 changed files with 140 additions and 73 deletions

6
Cargo.lock generated
View File

@ -87,6 +87,11 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "fdt"
version = "0.2.0-alpha1"
source = "git+https://github.com/repnop/fdt#059bb2383873f8001959456e36ec123228f67642"
[[package]] [[package]]
name = "flagset" name = "flagset"
version = "0.4.7" version = "0.4.7"
@ -99,6 +104,7 @@ version = "0.3.0"
dependencies = [ dependencies = [
"acpi", "acpi",
"enumflags2", "enumflags2",
"fdt",
"flagset", "flagset",
"lazy_static", "lazy_static",
"limine", "limine",

View File

@ -6,6 +6,7 @@ edition = "2024"
[dependencies] [dependencies]
acpi = "5.1.0" acpi = "5.1.0"
enumflags2 = "0.7.11" enumflags2 = "0.7.11"
fdt = { git = "https://github.com/repnop/fdt", version = "0.2.0-alpha1" }
flagset = "0.4.7" flagset = "0.4.7"
lazy_static = { version = "1.5.0", default-features = false, features = ["spin_no_std"] } lazy_static = { version = "1.5.0", default-features = false, features = ["spin_no_std"] }
limine = "0.4.0" limine = "0.4.0"

View File

@ -30,6 +30,16 @@ PROFILE = "dev"
PROFILEDIR = "debug" PROFILEDIR = "debug"
ARTIFACTDIR = "target/${TARGET}/${PROFILEDIR}" ARTIFACTDIR = "target/${TARGET}/${PROFILEDIR}"
[env.dev]
PROFILE = "dev"
PROFILEDIR = "debug"
ARTIFACTDIR = "target/${TARGET}/${PROFILEDIR}"
[env.debug]
PROFILE = "dev"
PROFILEDIR = "debug"
ARTIFACTDIR = "target/${TARGET}/${PROFILEDIR}"
[env.release] [env.release]
PROFILE = "release" PROFILE = "release"
PROFILEDIR = "release" PROFILEDIR = "release"

View File

@ -47,6 +47,7 @@ Licensed under the GNU Public License v3. See [LICENSE](LICENSE) for details.
- [arch/](src/kernel/arch/): Architecture specific features like the display, serial, and interrupts. Each architecture is a subfolder, containing a file or module for each feature. - [arch/](src/kernel/arch/): Architecture specific features like the display, serial, and interrupts. Each architecture is a subfolder, containing a file or module for each feature.
- [boot.rs](src/kernel/boot.rs): Handles bootloader-managed data structures. Gila uses Limine. Other bootloaders are NOT supported. - [boot.rs](src/kernel/boot.rs): Handles bootloader-managed data structures. Gila uses Limine. Other bootloaders are NOT supported.
- [constants.rs](src/kernel/constants.rs): Constants referenced elsewhere in the kernel. - [constants.rs](src/kernel/constants.rs): Constants referenced elsewhere in the kernel.
- [device.rs](src/kernel/device.rs): Functions for discovering hardware and assigning drivers.
- [log.rs](src/kernel/log.rs): Logging structures, macros, and singletons for logging to serial or the display. - [log.rs](src/kernel/log.rs): Logging structures, macros, and singletons for logging to serial or the display.
- [main.rs](src/kernel/main.rs): The entry point that gets called by the bootloader. - [main.rs](src/kernel/main.rs): The entry point that gets called by the bootloader.
- [memory.rs](src/kernel/memory.rs): Types relating to memory regions and allocation. - [memory.rs](src/kernel/memory.rs): Types relating to memory regions and allocation.

View File

@ -4,6 +4,9 @@ use lazy_static::lazy_static;
use super::asm::*; use super::asm::*;
use crate::{log_trace, format};
use crate::log::{LogLevel, LOGGER};
lazy_static! { lazy_static! {
pub static ref GDT: GlobalDescriptorTable = { pub static ref GDT: GlobalDescriptorTable = {
let mut gdt = GlobalDescriptorTable::new(); let mut gdt = GlobalDescriptorTable::new();
@ -17,6 +20,10 @@ pub fn setup_gdt() {
interrupt_disable(); interrupt_disable();
} }
GDT.load(); GDT.load();
log_trace!(
"GDT: Setting up global descriptor table at 0x{:x}",
core::ptr::addr_of!(GDT) as usize
);
unsafe { unsafe {
interrupt_enable(); interrupt_enable();
} }

View File

@ -35,3 +35,6 @@ pub static FRAMEBUFFER_REQUEST: FramebufferRequest = limine::request::Framebuffe
#[used] #[used]
#[unsafe(link_section = ".requests")] #[unsafe(link_section = ".requests")]
pub static MEMMAP_REQUEST: MemoryMapRequest = limine::request::MemoryMapRequest::new(); pub static MEMMAP_REQUEST: MemoryMapRequest = limine::request::MemoryMapRequest::new();
#[used]
#[unsafe(link_section = ".requests")]
pub static DTB_REQUEST: DeviceTreeBlobRequest = limine::request::DeviceTreeBlobRequest::new();

24
src/kernel/device.rs Normal file
View File

@ -0,0 +1,24 @@
use fdt::*;
use lazy_static::lazy_static;
use limine::response::{DeviceTreeBlobResponse, RsdpResponse};
use crate::boot::{DTB_REQUEST, RSDP_REQUEST};
use crate::log::{LOGGER, LogLevel};
use crate::{format, log_trace};
lazy_static! {
pub static ref DTB: Option<&'static DeviceTreeBlobResponse> = DTB_REQUEST.get_response();
pub static ref RDSP: Option<&'static RsdpResponse> = RSDP_REQUEST.get_response();
}
#[allow(dead_code)]
pub fn device_tree_parsed() -> Option<Fdt<'static>> {
if let Some(ok_dtb) = *DTB
&& let Ok(ok_parsed_dt) = unsafe { fdt::Fdt::from_ptr(ok_dtb.dtb_ptr() as *const u8) }
{
log_trace!("Device: Parsed device tree");
Some(ok_parsed_dt)
} else {
None
}
}

View File

@ -10,18 +10,21 @@ use alloc::string::*;
use alloc::vec::*; use alloc::vec::*;
use spin::Mutex; use spin::Mutex;
#[macro_export]
macro_rules! log_info { macro_rules! log_info {
($($arg:tt)*) => { ($($arg:tt)*) => {
LOGGER.log(LogLevel::Info, &format!($($arg)*)) LOGGER.log(LogLevel::Info, &format!($($arg)*))
}; };
} }
#[macro_export]
macro_rules! log_trace { macro_rules! log_trace {
($($arg:tt)*) => { ($($arg:tt)*) => {
LOGGER.log(LogLevel::Trace, &format!($($arg)*)) LOGGER.log(LogLevel::Trace, &format!($($arg)*))
}; };
} }
#[macro_export]
#[allow(unused_macros)] #[allow(unused_macros)]
macro_rules! log_warning { macro_rules! log_warning {
($($arg:tt)*) => { ($($arg:tt)*) => {
@ -29,6 +32,7 @@ macro_rules! log_warning {
}; };
} }
#[macro_export]
#[allow(unused_macros)] #[allow(unused_macros)]
macro_rules! log_error { macro_rules! log_error {
($($arg:tt)*) => { ($($arg:tt)*) => {
@ -36,6 +40,7 @@ macro_rules! log_error {
}; };
} }
#[macro_export]
#[allow(unused_macros)] #[allow(unused_macros)]
macro_rules! log_critical { macro_rules! log_critical {
($($arg:tt)*) => { ($($arg:tt)*) => {
@ -71,10 +76,10 @@ pub struct EnumParseError {}
pub struct LoggerInner { pub struct LoggerInner {
pub level: LogLevel, pub level: LogLevel,
pub subscriber: Vec<Mutex<Box<dyn LogSubscriber + Send + Sync>>>, pub subscriber: Vec<Mutex<Box<dyn LogSubscriber>>>,
} }
pub trait LogSubscriber { pub trait LogSubscriber: Send + Sync {
fn write(&self, msg: &str); fn write(&self, msg: &str);
} }

View File

@ -9,6 +9,7 @@
mod arch; mod arch;
mod boot; mod boot;
mod constants; mod constants;
mod device;
#[macro_use] #[macro_use]
mod log; mod log;
mod memory; mod memory;
@ -16,12 +17,12 @@ mod panic;
mod params; mod params;
mod process; mod process;
mod resources; mod resources;
mod syscall_runner;
use core::ptr; #[cfg(target_arch = "x86_64")]
use arch::x86_64::gdt;
use arch::x86_64::gdt::{self, GDT}; #[cfg(target_arch = "x86_64")]
use arch::x86_64::serial::Serialport; use arch::x86_64::serial::Serialport;
use boot::*; use boot::*;
use constants::*; use constants::*;
use log::*; use log::*;
@ -38,9 +39,6 @@ unsafe extern "C" fn main() -> ! {
// Assert supported bootloader version // Assert supported bootloader version
assert!(BASE_REVISION.is_supported()); assert!(BASE_REVISION.is_supported());
// TODO: This is hacky and will not work on any other machine.
let qemu_serial = Serialport::new(0x3f8);
let executable_file_response = FILE_REQUEST let executable_file_response = FILE_REQUEST
.get_response() .get_response()
.expect("Bootloader did not return executable data"); .expect("Bootloader did not return executable data");
@ -61,7 +59,9 @@ unsafe extern "C" fn main() -> ! {
// Append display console to log subs // Append display console to log subs
} }
if log_device_list.contains(&"serial") { if log_device_list.contains(&"serial") {
LOGGER.add_subscriber(qemu_serial); // TODO: Set up device discovery
#[cfg(target_arch = "x86_64")]
LOGGER.add_subscriber(Serialport::new(0x3f8));
} }
log_trace!("Boot: Configured kernel logging devices"); log_trace!("Boot: Configured kernel logging devices");
} }
@ -101,7 +101,17 @@ unsafe extern "C" fn main() -> ! {
} }
} }
let _rsdp_response = RSDP_REQUEST.get_response(); // Try to obtain ACPI information first. If not available, fall back to
// flattened device tree.
let rsdp_response = RSDP_REQUEST.get_response();
let dtb_response = DTB_REQUEST.get_response();
if let Some(rdsp) = rsdp_response {
log_info!("Boot: RDSP response received");
log_trace!("Boot: RDSP located at 0x{:x}", rdsp.address());
} else if let Some(dtb) = dtb_response {
log_info!("Boot: DTB response received");
log_trace!("Boot: DTB located at 0x{:x}", dtb.dtb_ptr() as usize)
}
let module_response = MODULE_REQUEST let module_response = MODULE_REQUEST
.get_response() .get_response()
@ -142,80 +152,80 @@ unsafe extern "C" fn main() -> ! {
} }
.expect("initramfs not found in modules list"); .expect("initramfs not found in modules list");
if let Some(mmap_response) = MEMMAP_REQUEST.get_response() { // Panic if this is absent. It's needed to set up the GDT and paging
log_info!("Boot: Memory map received"); let mmap_response = MEMMAP_REQUEST.get_response().expect("Bootloader did not supply memory map");
if !mmap_response.entries().is_empty() { log_info!("Boot: Memory map received");
let mut log_msg: String = String::from("Boot: Memory map:"); if !mmap_response.entries().is_empty() {
let mut usable: u64 = 0; let mut log_msg: String = String::from("Boot: Memory map:");
let mut reclaimable: u64 = 0; let mut usable: u64 = 0;
let mut hardware: u64 = 0; let mut reclaimable: u64 = 0;
let mut unusable: u64 = 0; let mut hardware: u64 = 0;
for entry in mmap_response.entries() { let mut unusable: u64 = 0;
log_msg.push_str(&format!( for entry in mmap_response.entries() {
"\n\t\t0x{:x} bytes @ 0x{:x}: {}", log_msg.push_str(&format!(
entry.length, "\n\t\t0x{:x} bytes @ 0x{:x}: {}",
entry.base, entry.length,
match entry.entry_type { entry.base,
EntryType::ACPI_NVS => { match entry.entry_type {
hardware += entry.length; EntryType::ACPI_NVS => {
"ACPI (reserved)" hardware += entry.length;
} "ACPI (reserved)"
EntryType::ACPI_RECLAIMABLE => {
reclaimable += entry.length;
"ACPI (reclaimable)"
}
EntryType::BAD_MEMORY => {
unusable += entry.length;
"damaged/unusable"
}
EntryType::BOOTLOADER_RECLAIMABLE => {
reclaimable += entry.length;
"bootloader (reclaimable)"
}
#[allow(unreachable_patterns, deprecated)]
EntryType::EXECUTABLE_AND_MODULES | EntryType::KERNEL_AND_MODULES => {
unusable += entry.length;
"executable & modules"
}
EntryType::FRAMEBUFFER => {
hardware += entry.length;
"framebuffer"
}
EntryType::RESERVED => {
unusable += entry.length;
"reserved"
}
EntryType::USABLE => {
usable += entry.length;
"usable"
}
_ => "unidentified",
} }
)); EntryType::ACPI_RECLAIMABLE => {
} reclaimable += entry.length;
log_trace!("{log_msg}"); "ACPI (reclaimable)"
let total = usable + reclaimable + hardware + unusable; }
log_info!( EntryType::BAD_MEMORY => {
"Boot: Memory report:\n\t\tFree: {usable}\n\t\tAvailable: {reclaimable}\n\t\tUsable: {}\n\t\tHardware: {hardware}\n\t\tUnusable: {unusable}\n\t\tTotal: {}", unusable += entry.length;
usable + reclaimable, "damaged/unusable"
total }
); EntryType::BOOTLOADER_RECLAIMABLE => {
reclaimable += entry.length;
"bootloader (reclaimable)"
}
#[allow(unreachable_patterns, deprecated)]
EntryType::EXECUTABLE_AND_MODULES | EntryType::KERNEL_AND_MODULES => {
unusable += entry.length;
"executable & modules"
}
EntryType::FRAMEBUFFER => {
hardware += entry.length;
"framebuffer"
}
EntryType::RESERVED => {
unusable += entry.length;
"reserved"
}
EntryType::USABLE => {
usable += entry.length;
"usable"
}
_ => "unidentified",
}
));
} }
log_trace!("{log_msg}");
let total = usable + reclaimable + hardware + unusable;
log_info!(
"Boot: Memory report:\n\t\tFree: {usable}\n\t\tAvailable: {reclaimable}\n\t\tUsable: {}\n\t\tHardware: {hardware}\n\t\tUnusable: {unusable}\n\t\tTotal: {}",
usable + reclaimable,
total
);
} else {
panic!("Memory map contains no entries");
} }
log_trace!( #[cfg(target_arch = "x86_64")]
"GDT: Setting up global descriptor table at 0x{:x}",
ptr::addr_of!(GDT) as usize
);
gdt::setup_gdt(); gdt::setup_gdt();
#[allow(unreachable_code)] #[allow(unreachable_code)]
loop { loop {
for _i in 0..50000000 { for _i in 0..50000000u64 {
unsafe { unsafe {
core::arch::asm!("nop"); core::arch::asm!("nop");
} }
} }
core::hint::black_box(());
log_trace!("Heartbeat"); log_trace!("Heartbeat");
} }
} }