1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! Placeholder no-op HAL implementation

use core::default::Default;
use lazy_static::lazy_static;
use slos_helpers::UnsafeContainer;

use crate::{SystemConsole, SystemCpu, SystemHardware, SystemKmainHooks};

mod console;
pub use self::console::{NullConsole, NULL_CONSOLE};

#[cfg(test)]
mod tests;

lazy_static! {
	/// Global instance of the [`NullSystem`]
	pub static ref SYSTEM: UnsafeContainer<NullSystem> = UnsafeContainer::new(Default::default());
}

/// A [`SystemHardware`] implementation where (almost) everything has no-op
/// implementations
///
/// # Behaviour
///
/// The following general rules apply:
///
/// Methods on HAL traits that return `&'static mut T` references to other HAL
/// trait objects return references to valid things, but those things are also
/// all no-op implementations (for example, [`NullConsole`]).
///
/// All methods that do not return a value are implemented as empty functions.
///
/// All methods that return a value will return either (a) a "sensible" value,
/// in the case where the value is critical to the kernel, (b) the same value
/// that [`Default::default`] would return, where `Default` is implemented for
/// the type, or (c) a manually-constructed default value for the type that
/// will make any operations on that type into no-ops.
///
/// ## Exceptions to the rules
///
/// - [`SystemHardware::system_name`] returns "slos-hal-nullsystem".
///
/// - [`SystemHardware::has_requested_return`] will return the value of the
///   `has_requested_return` field of the struct - this field is set to
///   `false` in the constructor, and set to `true` on every call to the
///   [`SystemKmainHooks::hook_kmain_loop_head`] method. This is done so that
///   `kmain` will iterate exactly **once** before returning.
///
/// - If the `is_virtualized` field of this struct is set to `true`, the
///   [`SystemHardware::virtualization`] method will return a value indicating
///   that the system is virtualized (the "virtualization type" field of the
///   value is set to [`SystemHardware::system_name`]). If the field is set to
///   `false`, [`None`][Option::None] is returned.
///
/// # Default values
///
/// This struct implements the [`Default`] trait, these are the values that
/// are set in that constructor:
///
/// ```
/// # use slos_hal::null_system::NullSystem;
/// # let sys: NullSystem = {
/// NullSystem {
///     has_requested_return: false,
///     is_virtualized: true,
/// }
/// # };
/// #
/// # // let's check that the documentation is actually correct, huh
/// # assert_eq!(sys, core::default::Default::default());
/// ```
///
/// # Safety
///
/// This implementation will never panic directly.
#[derive(Debug, PartialEq)]
pub struct NullSystem {
	/// Whether to request a `kmain` return
	pub has_requested_return: bool,

	/// Whether to indicate the system is virtualized
	pub is_virtualized: bool,
}

impl Default for NullSystem {
	fn default() -> Self {
		Self {
			has_requested_return: false,
			is_virtualized: true,
		}
	}
}

impl SystemCpu for NullSystem {
	fn interrupts_disable(&mut self) {}
	fn interrupts_enable(&mut self) {}
	fn halt(&mut self) {}

	fn interrupts_are_enabled(&self) -> bool {
		false
	}
}

impl SystemKmainHooks for NullSystem {
	fn hook_kmain_loop_head(&mut self) {
		self.has_requested_return = true;
	}
}

impl SystemHardware for NullSystem {
	fn system_name(&self) -> &'static str {
		concat!(env!("CARGO_PKG_NAME"), "-nullsystem")
	}

	fn console(&mut self) -> &'static mut dyn SystemConsole {
		NULL_CONSOLE.get()
	}

	fn has_requested_return(&self) -> bool {
		self.has_requested_return
	}

	fn current_cpu(&mut self) -> &'static mut dyn SystemCpu {
		SYSTEM.get()
	}

	fn virtualization(&self) -> Option<(&'static str, ())> {
		match self.is_virtualized {
			true => Some((self.system_name(), ())),
			false => None,
		}
	}
}