Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • pigeonmoelleux/skavos
1 result
Show changes
This diff is collapsed.
//! Interface to manage storage devices and controllers
use alloc::sync::Arc;
use alloc::vec::Vec;
use spin::Mutex;
use super::block::Manipulation;
/// Type alias representing a device UUID
pub type Uuid = [u8; 20];
/// Represents storage devices such as hard drive, SSDs, etc.
pub trait Device: Manipulation {
/// Returns the size of the device in blocks
fn size_in_blocks(&self) -> usize;
/// Returns a unique identifier for the device
///
/// This allows to be sure a same device will not be found several times.
fn uuid(&self) -> Uuid;
}
/// Represents a storage controller
pub trait Controller {
/// Returns the list of the [`Device`] controlled by this structure
fn devices<'device>(&self) -> Vec<Arc<Mutex<dyn Device + Send + 'device>>>;
}
...@@ -48,6 +48,7 @@ impl Display for Rtc { ...@@ -48,6 +48,7 @@ impl Display for Rtc {
/// See the [OSdev wiki](https://wiki.osdev.org/CMOS#Getting_Current_Date_and_Time_from_RTC) for more details /// See the [OSdev wiki](https://wiki.osdev.org/CMOS#Getting_Current_Date_and_Time_from_RTC) for more details
#[repr(u8)] #[repr(u8)]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[allow(unused)]
enum Register { enum Register {
/// Second register /// Second register
Second = 0x00, Second = 0x00,
...@@ -213,6 +214,7 @@ impl Cmos { ...@@ -213,6 +214,7 @@ impl Cmos {
} }
/// Waits until the CMOS is updated /// Waits until the CMOS is updated
#[allow(unused)]
fn wait_while_updating(&mut self) { fn wait_while_updating(&mut self) {
while self.is_updating() { while self.is_updating() {
spin_loop(); spin_loop();
...@@ -220,6 +222,7 @@ impl Cmos { ...@@ -220,6 +222,7 @@ impl Cmos {
} }
/// Returns the current Real-Time Clock /// Returns the current Real-Time Clock
#[allow(unused)]
pub fn rtc(&mut self) -> Rtc { pub fn rtc(&mut self) -> Rtc {
/// Believe in the docs /// Believe in the docs
const SRB_BCD_MODE: u8 = 0x04; const SRB_BCD_MODE: u8 = 0x04;
......
...@@ -24,6 +24,12 @@ pub(super) enum InterruptIndex { ...@@ -24,6 +24,12 @@ pub(super) enum InterruptIndex {
/// Real-time controller interrupt /// Real-time controller interrupt
Rtc = PIC2_OFFSET, Rtc = PIC2_OFFSET,
/// Standard ATA primary interrupt (0xE above base offset)
AtaPrimary = PIC1_OFFSET + 0x0E,
/// Standard ATA primary interrupt (0xF above base offset)
AtaSecondary = PIC1_OFFSET + 0x0F,
} }
impl From<InterruptIndex> for u8 { impl From<InterruptIndex> for u8 {
...@@ -46,6 +52,8 @@ pub(super) static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| { ...@@ -46,6 +52,8 @@ pub(super) static IDT: Lazy<InterruptDescriptorTable> = Lazy::new(|| {
set_handler_fn(&mut idt, InterruptIndex::Timer, timer_interrupt_handler); set_handler_fn(&mut idt, InterruptIndex::Timer, timer_interrupt_handler);
set_handler_fn(&mut idt, InterruptIndex::Keyboard, keyboard_interrupt_handler); set_handler_fn(&mut idt, InterruptIndex::Keyboard, keyboard_interrupt_handler);
set_handler_fn(&mut idt, InterruptIndex::Rtc, rtc_interrupt_handler); set_handler_fn(&mut idt, InterruptIndex::Rtc, rtc_interrupt_handler);
set_handler_fn(&mut idt, InterruptIndex::AtaPrimary, primary_ata_handler);
set_handler_fn(&mut idt, InterruptIndex::AtaSecondary, secondary_ata_handler);
idt idt
}); });
...@@ -102,7 +110,7 @@ extern "x86-interrupt" fn rtc_interrupt_handler(_stack_frame: InterruptStackFram ...@@ -102,7 +110,7 @@ extern "x86-interrupt" fn rtc_interrupt_handler(_stack_frame: InterruptStackFram
LAST_RTC_UPDATE.store(pit::ticks(), Ordering::Relaxed); LAST_RTC_UPDATE.store(pit::ticks(), Ordering::Relaxed);
CMOS.notify_end_of_interrupt(); CMOS.notify_end_of_interrupt();
// SAFETY: Timer index is the same everywhere it should // SAFETY: RTC index is the same everywhere it should
unsafe { unsafe {
PICS.lock().notify_end_of_interrupt(InterruptIndex::Rtc.into()); PICS.lock().notify_end_of_interrupt(InterruptIndex::Rtc.into());
}; };
...@@ -112,12 +120,28 @@ extern "x86-interrupt" fn rtc_interrupt_handler(_stack_frame: InterruptStackFram ...@@ -112,12 +120,28 @@ extern "x86-interrupt" fn rtc_interrupt_handler(_stack_frame: InterruptStackFram
extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) { extern "x86-interrupt" fn keyboard_interrupt_handler(_stack_frame: InterruptStackFrame) {
KeyQueue::handle_interrupt(); KeyQueue::handle_interrupt();
// SAFETY: Timer index is the same everywhere it should // SAFETY: Keyboard index is the same everywhere it should
unsafe { unsafe {
PICS.lock().notify_end_of_interrupt(InterruptIndex::Keyboard.into()); PICS.lock().notify_end_of_interrupt(InterruptIndex::Keyboard.into());
}; };
} }
/// Primary ATA interrupt handler
extern "x86-interrupt" fn primary_ata_handler(_stack_frame: InterruptStackFrame) {
// SAFETY: ATA primary index is the standard one
unsafe {
PICS.lock().notify_end_of_interrupt(InterruptIndex::AtaPrimary.into());
};
}
/// Secondary ATA interrupt handler
extern "x86-interrupt" fn secondary_ata_handler(_stack_frame: InterruptStackFrame) {
// SAFETY: ATA secondary index is the standard one
unsafe {
PICS.lock().notify_end_of_interrupt(InterruptIndex::AtaSecondary.into());
};
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use x86_64::instructions::interrupts; use x86_64::instructions::interrupts;
......
...@@ -151,7 +151,8 @@ impl KeyQueue { ...@@ -151,7 +151,8 @@ impl KeyQueue {
/// ///
/// Moreover, the following keys combinations are used : /// Moreover, the following keys combinations are used :
/// - `CTRL` + `ALT` + `DEL`: reboots the computer (not implemented yet) /// - `CTRL` + `ALT` + `DEL`: reboots the computer (not implemented yet)
/// - `ALT` + `L`: flushes the logger /// - `ALT` + `P`: displays all logs and clears the logger
/// - `ALT` + `L`: displays the oldest log then removes it from the logger
#[allow(clippy::wildcard_enum_match_arm)] #[allow(clippy::wildcard_enum_match_arm)]
pub fn handle_key(key: DecodedKey) { pub fn handle_key(key: DecodedKey) {
/// Tabulation char /// Tabulation char
...@@ -171,11 +172,16 @@ impl KeyQueue { ...@@ -171,11 +172,16 @@ impl KeyQueue {
DecodedKey::RawKey(KeyCode::ArrowLeft) => Self::send_csi("1D"), DecodedKey::RawKey(KeyCode::ArrowLeft) => Self::send_csi("1D"),
DecodedKey::Unicode(TAB) if shift_pressed => Self::send_csi("2"), DecodedKey::Unicode(TAB) if shift_pressed => Self::send_csi("2"),
DecodedKey::Unicode(DEL) if alt_pressed && ctrl_pressed => warn!("TODO: implement reboot"), DecodedKey::Unicode(DEL) if alt_pressed && ctrl_pressed => warn!("TODO: implement reboot"),
DecodedKey::Unicode('l') if alt_pressed => { DecodedKey::Unicode('p') if alt_pressed => {
let mut logger = SYS_LOGGER.lock(); let mut logger = SYS_LOGGER.lock();
logger.display_messages(); logger.display_messages();
logger.clear(); logger.clear();
}, },
DecodedKey::Unicode('l') if alt_pressed => {
let mut logger = SYS_LOGGER.lock();
logger.display_next_message();
logger.remove_oldest();
},
DecodedKey::Unicode(key) => Self::push_key(key), DecodedKey::Unicode(key) => Self::push_key(key),
_ => {}, _ => {},
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
//! //!
//! This kernel is meant to be minimal and make easy the loading of other external modules //! This kernel is meant to be minimal and make easy the loading of other external modules
pub mod device;
pub mod interrupt; pub mod interrupt;
pub mod memory; pub mod memory;
pub mod screen; pub mod screen;
...@@ -15,9 +16,7 @@ use x86_64::VirtAddr; ...@@ -15,9 +16,7 @@ use x86_64::VirtAddr;
use self::memory::paging::{PhysFrameAllocator, MAPPER}; use self::memory::paging::{PhysFrameAllocator, MAPPER};
use self::memory::vmm::VIRTUAL_MEMORY_MANAGER; use self::memory::vmm::VIRTUAL_MEMORY_MANAGER;
use crate::kernel::interrupt::cmos::CMOS;
use crate::kernel::screen::buffer::Buffer; use crate::kernel::screen::buffer::Buffer;
use crate::println;
/// Initializes the kernel /// Initializes the kernel
pub fn init(boot_info: &'static mut BootInfo) { pub fn init(boot_info: &'static mut BootInfo) {
...@@ -65,9 +64,10 @@ pub fn init(boot_info: &'static mut BootInfo) { ...@@ -65,9 +64,10 @@ pub fn init(boot_info: &'static mut BootInfo) {
// Initialization of the CPU interruptions // Initialization of the CPU interruptions
interrupt::init(rsdp_addr); interrupt::init(rsdp_addr);
info!("Interruptions initialized"); info!("Interruptions initialized");
println!("Hello world!"); // Initialization of the devices
println!("It is currently {}.", CMOS.rtc()); device::init();
info!("Devices initialized");
} }
//! Implementation of a simple competitive task executor //! Implementation of a simple cooperative task executor
use alloc::collections::BTreeMap; use alloc::collections::BTreeMap;
use alloc::sync::Arc; use alloc::sync::Arc;
......
...@@ -57,14 +57,22 @@ ...@@ -57,14 +57,22 @@
#![feature(const_mut_refs)] #![feature(const_mut_refs)]
#![feature(const_trait_impl)] #![feature(const_trait_impl)]
#![feature(custom_test_frameworks)] #![feature(custom_test_frameworks)]
#![feature(error_in_core)]
#![feature(extend_one)]
#![feature(int_roundings)]
#![feature(iter_advance_by)]
#![feature(new_uninit)]
#![feature(no_coverage)] #![feature(no_coverage)]
#![feature(strict_provenance)] #![feature(strict_provenance)]
#![feature(trait_upcasting)]
#![feature(vec_into_raw_parts)]
#![reexport_test_harness_main = "test_main"] #![reexport_test_harness_main = "test_main"]
#![test_runner(test::runner)] #![test_runner(test::runner)]
extern crate alloc; extern crate alloc;
mod encoding; mod encoding;
mod fs;
mod kernel; mod kernel;
mod macros; mod macros;
mod mutex; mod mutex;
...@@ -74,13 +82,18 @@ mod user; ...@@ -74,13 +82,18 @@ mod user;
#[cfg(test)] #[cfg(test)]
mod test; mod test;
use alloc::sync::Arc;
use alloc::vec::Vec;
use core::alloc::Layout; use core::alloc::Layout;
use bootloader_api::config::{Mapping, Mappings}; use bootloader_api::config::{Mapping, Mappings};
use bootloader_api::{entry_point, BootInfo, BootloaderConfig}; use bootloader_api::{entry_point, BootInfo, BootloaderConfig};
use kernel::device::storage::Device;
use kernel::device::{STORAGE_CONTROLLERS, UEFI_UUID};
use kernel::task::executor::Executor; use kernel::task::executor::Executor;
use kernel::task::Task; use kernel::task::Task;
use log::{logger, set_logger, set_max_level, LevelFilter}; use log::{logger, set_logger, set_max_level, LevelFilter};
use spin::Mutex;
#[cfg(test)] #[cfg(test)]
use test::exit; use test::exit;
use user::tty::print_key; use user::tty::print_key;
...@@ -88,6 +101,7 @@ use user::tty::print_key; ...@@ -88,6 +101,7 @@ use user::tty::print_key;
use x86_64::instructions; use x86_64::instructions;
use self::syslog::SYS_LOGGER; use self::syslog::SYS_LOGGER;
use crate::kernel::interrupt::cmos::CMOS;
/// Configuration of the bootloader /// Configuration of the bootloader
/// ///
...@@ -108,12 +122,31 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! { ...@@ -108,12 +122,31 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
kernel::init(boot_info); kernel::init(boot_info);
let storage_devices = STORAGE_CONTROLLERS
.get()
.expect("Storage controllers have not been initialized yet")
.iter()
.flat_map(|controller| controller.lock().devices())
.collect::<Vec<Arc<Mutex<dyn Device + Send>>>>()
.into_iter()
.filter(|device| device.lock().uuid() != UEFI_UUID)
.collect::<Vec<Arc<Mutex<dyn Device + Send>>>>();
if let Some(device) = storage_devices.first() {
fs::init(&Arc::clone(device));
}
#[cfg(test)] #[cfg(test)]
{ {
test_main(); test_main();
exit(); exit();
}; };
println!("Hello world!");
let rtc = CMOS.rtc();
println!("It is currently : {:0>2}:{:0>2}:{:0>2} (UTC+0)", rtc.hour, rtc.minute, rtc.second);
let mut executor = Executor::new(); let mut executor = Executor::new();
executor.spawn(Task::new(print_key())); executor.spawn(Task::new(print_key()));
executor.run(); executor.run();
......
//! Simple logger for `SkavOS` //! Simple logger for `SkavOS`
use alloc::collections::BTreeMap;
use alloc::format; use alloc::format;
use alloc::string::String; use alloc::string::String;
use core::fmt::Display; use core::fmt::Display;
use core::sync::atomic::{AtomicU64, Ordering}; use core::sync::atomic::{AtomicU64, Ordering};
use circular_buffer::CircularBuffer;
use log::{Level, Log, Metadata, Record}; use log::{Level, Log, Metadata, Record};
use crate::kernel::screen::color::{Color, CYAN, ORANGE, RED, WHITE, YELLOW}; use crate::kernel::screen::color::{Color, CYAN, ORANGE, RED, WHITE, YELLOW};
...@@ -85,19 +85,32 @@ impl Message { ...@@ -85,19 +85,32 @@ impl Message {
#[derive(Debug)] #[derive(Debug)]
pub struct SysLog { pub struct SysLog {
/// Messages that have not been flushed yet /// Messages that have not been flushed yet
messages: BTreeMap<MessageId, Message>, messages: CircularBuffer<100, Message>,
} }
impl SysLog { impl SysLog {
/// Creates a new logger /// Creates a new logger
const fn new() -> Self { const fn new() -> Self {
Self { Self {
messages: BTreeMap::new(), messages: CircularBuffer::new(),
} }
} }
/// Prints the next message that have not been displayed yet
pub fn display_next_message(&mut self) {
if self.messages.is_empty() {
println!("Empty logger");
return;
}
// SAFETY: `self.messages` is not empty
unsafe {
self.messages.front().unwrap_unchecked().print();
};
}
/// Prints all messages contained in the logger /// Prints all messages contained in the logger
pub fn display_messages(&mut self) { pub fn display_messages(&self) {
if self.messages.is_empty() { if self.messages.is_empty() {
println!("Empty logger"); println!("Empty logger");
return; return;
...@@ -105,11 +118,16 @@ impl SysLog { ...@@ -105,11 +118,16 @@ impl SysLog {
println!("Logs:"); println!("Logs:");
for message in self.messages.values() { for message in &self.messages {
message.print(); message.print();
} }
} }
/// Removes the oldest message saved in the logger
pub fn remove_oldest(&mut self) {
self.messages.pop_front();
}
/// Removes all the messages saved in the logger /// Removes all the messages saved in the logger
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.messages.clear(); self.messages.clear();
...@@ -124,12 +142,7 @@ impl Log for Locked<SysLog> { ...@@ -124,12 +142,7 @@ impl Log for Locked<SysLog> {
fn log(&self, record: &Record) { fn log(&self, record: &Record) {
let content = format!("{}", record.args()); let content = format!("{}", record.args());
let message = Message::new(record.level(), content); let message = Message::new(record.level(), content);
let message_id = message.id; self.lock().messages.push_back(message);
assert!(
self.lock().messages.insert(message.id, message).is_none(),
"The message with ID {message_id} has already been logged"
);
} }
fn flush(&self) {} fn flush(&self) {}
...@@ -182,14 +195,15 @@ mod test { ...@@ -182,14 +195,15 @@ mod test {
.args(format_args!("Hello world! {}", 42_usize)) .args(format_args!("Hello world! {}", 42_usize))
.build(), .build(),
); );
let previous_message_id = NEXT_MESSAGE_ID.load(Ordering::Relaxed) - 1; let previous_message_id = NEXT_MESSAGE_ID.load(Ordering::Relaxed) - 1;
assert_eq!(&syslog.lock().messages[&MessageId(previous_message_id)], &Message { assert_eq!(syslog.lock().messages.back().unwrap(), &Message {
id: MessageId(previous_message_id), id: MessageId(previous_message_id),
level: Level::Info, level: Level::Info,
content: "Hello world! 42".to_owned() content: "Hello world! 42".to_owned()
}); });
syslog.log(&Record::builder().level(Level::Warn).args(format_args!("1 + {} = 2", 1_usize)).build()); syslog.log(&Record::builder().level(Level::Warn).args(format_args!("1 + {} = 2", 1_usize)).build());
assert_eq!(&syslog.lock().messages[&MessageId(previous_message_id + 1)], &Message { assert_eq!(syslog.lock().messages.back().unwrap(), &Message {
id: MessageId(previous_message_id + 1), id: MessageId(previous_message_id + 1),
level: Level::Warn, level: Level::Warn,
content: "1 + 1 = 2".to_owned() content: "1 + 1 = 2".to_owned()
......