mango_rt/
lib.rs

1#![no_std]
2#![warn(missing_docs)]
3#![deny(warnings)]
4
5//! mango_rt: mango runtime
6//!
7//! This crate contains the support for defining a mango kernel and its applications.
8//! Kernels are defined with the macro [kernel!].
9//!
10
11extern crate alloc;
12
13mod application;
14pub mod panic_wait;
15pub mod schedulers;
16
17pub use application::Application;
18
19/// A kernel is defined with the `mango_rt::kernel!` macro. This defines:
20/// * the name of the initialisation function (`name`)
21/// * the name of the static instance (`instance`). It is recommended that this is set to `KERNEL_INSTANCE`.
22/// * the arguments from the bootloader given to the main function (`main_arguments`).
23/// * the list of devices defined by the kernel (`devices`).
24/// * the device used for stdout (`stdout`).
25/// * the scheduler used (`scheduler`).
26/// * the list of applications (`applications`).
27///
28/// Example of use:
29/// ```rust
30/// mango_rt::kernel!(
31///   name: hello_world_kernel,
32///   instance: KERNEL_INSTANCE,
33///   main_arguments: (boot_info: &'static bootloader::BootInfo),
34///   devices: {
35///     system: mango_hal::systems::x86_64::System => () / (boot_info),
36///     vga_output: mango_hal::io::VgaTextBuffer => () / (),
37///   },
38///   stdout: Some(&KERNEL_INSTANCE.vga_output),
39///   scheduler: mango_rt::schedulers::NoScheduler => (),
40///   applications: {
41///     hello_world: HelloWorld => ()
42///   }
43/// );
44/// ```
45
46#[macro_export]
47macro_rules! kernel
48{
49  (
50    name: $kernel_name:ident,
51    instance: $kernel_instance:ident,
52    main_arguments: ( $($main_arg_name:ident : $main_arg_type:ty),* $(,)? ),
53    devices: { $($dev_name:ident : $dev_type:ty => ($($dev_create_arg:tt)*) / ($($dev_init_arg:tt)*)),+ $(,)? },
54    stdout: None,
55    scheduler: $scheduler_type:ty => ($($scheduler_create_args:tt)*) / ($($scheduler_init_args:tt)*),
56    applications: { $($app_name:ident : $app_type:ty => ($($app_create_arg:tt)*)),+ $(,)? }
57  ) => (
58    mango_os::boot::entry_point!($kernel_name);
59
60    pub struct Kernel
61    {
62      $(pub $dev_name: spin::Mutex<$dev_type>,)+
63      pub scheduler: spin::Mutex<$scheduler_type>,
64    }
65
66    lazy_static! {
67      pub static ref $kernel_instance: Kernel = Kernel {
68        $($dev_name: spin::Mutex::new(<$dev_type>::new($($dev_create_arg, )*)),)+
69        scheduler: spin::Mutex::new(<$scheduler_type>::new($($scheduler_create_args, )*)),
70      };
71    }
72
73    fn $kernel_name($($main_arg_name: $main_arg_type,)*) -> !
74    {
75      $($kernel_instance.$dev_name.lock().initialise($($dev_init_arg, )*);)+
76      $kernel_instance.scheduler.lock().initialise($($scheduler_init_args)*);
77      $(let mut $app_name = <$app_type>::new($($app_create_arg)*);)+
78      $($app_name.start();)+
79
80      $kernel_instance.scheduler.lock().run();
81    }
82  );
83  (
84    name: $kernel_name:ident,
85    instance: $kernel_instance:ident,
86    main_arguments: ( $($main_arg_name:ident : $main_arg_type:ty),* $(,)? ),
87    devices: { $($dev_name:ident : $dev_type:ty => ($($dev_create_arg:tt)*) / ($($dev_init_arg:tt)*)),+ $(,)? },
88    stdout: $stdout_name:expr,
89    scheduler: $scheduler_type:ty => ($($scheduler_create_args:tt)*) / ($($scheduler_init_args:tt)*),
90    applications: { $($app_name:ident : $app_type:ty => ($($app_create_arg:tt)*)),* $(,)? }
91  ) => (
92    mango_os::boot::entry_point!($kernel_name);
93
94    pub struct Kernel
95    {
96      $(pub $dev_name: spin::Mutex<$dev_type>,)+
97      pub scheduler: spin::Mutex<$scheduler_type>,
98    }
99
100    lazy_static! {
101      pub static ref $kernel_instance: Kernel = Kernel {
102        $($dev_name: spin::Mutex::new(<$dev_type>::new($($dev_create_arg, )*)),)+
103        scheduler: spin::Mutex::new(<$scheduler_type>::new($($scheduler_create_args, )*)),
104      };
105    }
106
107    fn $kernel_name($($main_arg_name: $main_arg_type,)*) -> !
108    {
109      $($kernel_instance.$dev_name.lock().initialise($($dev_init_arg, )*);)+
110      $kernel_instance.scheduler.lock().initialise($($scheduler_init_args)*);
111      mango_os::core::STDOUT.lock().set_printer_fn(
112        |x| {
113          if let Some(dev) = $stdout_name
114          {
115            use core::fmt::Write;
116            dev.lock().write_str(x)
117          } else {
118            Ok(())
119          }
120        });
121      $(let mut $app_name = <$app_type>::new($($app_create_arg)*);)*
122      $($app_name.start();)*
123
124      $kernel_instance.scheduler.lock().run();
125    }
126    #[panic_handler]
127    fn panic_handler(info: &core::panic::PanicInfo) -> !
128    {
129      $crate::panic_wait::panic_handler(info, &$kernel_instance.system)
130    }
131  );
132}