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

View File

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

View File

@ -30,6 +30,16 @@ PROFILE = "dev"
PROFILEDIR = "debug"
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]
PROFILE = "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.
- [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.
- [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.
- [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.

View File

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

View File

@ -35,3 +35,6 @@ pub static FRAMEBUFFER_REQUEST: FramebufferRequest = limine::request::Framebuffe
#[used]
#[unsafe(link_section = ".requests")]
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 spin::Mutex;
#[macro_export]
macro_rules! log_info {
($($arg:tt)*) => {
LOGGER.log(LogLevel::Info, &format!($($arg)*))
};
}
#[macro_export]
macro_rules! log_trace {
($($arg:tt)*) => {
LOGGER.log(LogLevel::Trace, &format!($($arg)*))
};
}
#[macro_export]
#[allow(unused_macros)]
macro_rules! log_warning {
($($arg:tt)*) => {
@ -29,6 +32,7 @@ macro_rules! log_warning {
};
}
#[macro_export]
#[allow(unused_macros)]
macro_rules! log_error {
($($arg:tt)*) => {
@ -36,6 +40,7 @@ macro_rules! log_error {
};
}
#[macro_export]
#[allow(unused_macros)]
macro_rules! log_critical {
($($arg:tt)*) => {
@ -71,10 +76,10 @@ pub struct EnumParseError {}
pub struct LoggerInner {
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);
}

View File

@ -9,6 +9,7 @@
mod arch;
mod boot;
mod constants;
mod device;
#[macro_use]
mod log;
mod memory;
@ -16,12 +17,12 @@ mod panic;
mod params;
mod process;
mod resources;
mod syscall_runner;
use core::ptr;
use arch::x86_64::gdt::{self, GDT};
#[cfg(target_arch = "x86_64")]
use arch::x86_64::gdt;
#[cfg(target_arch = "x86_64")]
use arch::x86_64::serial::Serialport;
use boot::*;
use constants::*;
use log::*;
@ -38,9 +39,6 @@ unsafe extern "C" fn main() -> ! {
// Assert supported bootloader version
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
.get_response()
.expect("Bootloader did not return executable data");
@ -61,7 +59,9 @@ unsafe extern "C" fn main() -> ! {
// Append display console to log subs
}
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");
}
@ -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
.get_response()
@ -142,80 +152,80 @@ unsafe extern "C" fn main() -> ! {
}
.expect("initramfs not found in modules list");
if let Some(mmap_response) = MEMMAP_REQUEST.get_response() {
log_info!("Boot: Memory map received");
if !mmap_response.entries().is_empty() {
let mut log_msg: String = String::from("Boot: Memory map:");
let mut usable: u64 = 0;
let mut reclaimable: u64 = 0;
let mut hardware: u64 = 0;
let mut unusable: u64 = 0;
for entry in mmap_response.entries() {
log_msg.push_str(&format!(
"\n\t\t0x{:x} bytes @ 0x{:x}: {}",
entry.length,
entry.base,
match entry.entry_type {
EntryType::ACPI_NVS => {
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",
// Panic if this is absent. It's needed to set up the GDT and paging
let mmap_response = MEMMAP_REQUEST.get_response().expect("Bootloader did not supply memory map");
log_info!("Boot: Memory map received");
if !mmap_response.entries().is_empty() {
let mut log_msg: String = String::from("Boot: Memory map:");
let mut usable: u64 = 0;
let mut reclaimable: u64 = 0;
let mut hardware: u64 = 0;
let mut unusable: u64 = 0;
for entry in mmap_response.entries() {
log_msg.push_str(&format!(
"\n\t\t0x{:x} bytes @ 0x{:x}: {}",
entry.length,
entry.base,
match entry.entry_type {
EntryType::ACPI_NVS => {
hardware += entry.length;
"ACPI (reserved)"
}
));
}
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
);
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",
}
));
}
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!(
"GDT: Setting up global descriptor table at 0x{:x}",
ptr::addr_of!(GDT) as usize
);
#[cfg(target_arch = "x86_64")]
gdt::setup_gdt();
#[allow(unreachable_code)]
loop {
for _i in 0..50000000 {
for _i in 0..50000000u64 {
unsafe {
core::arch::asm!("nop");
}
}
core::hint::black_box(());
log_trace!("Heartbeat");
}
}