Skip to content

Commit

Permalink
Monitor work.
Browse files Browse the repository at this point in the history
  • Loading branch information
dbittman committed Jul 23, 2024
1 parent dd8fd3b commit c317856
Show file tree
Hide file tree
Showing 12 changed files with 310 additions and 5 deletions.
46 changes: 46 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ initrd = [
"crate:netmgr",
"crate:nettest",
"crate:pager",
#"lib:twz-rt",
#"lib:monitor",
"lib:twz-rt",
"lib:monitor",
#"third-party:hello-world-rs"
]

Expand Down
2 changes: 1 addition & 1 deletion src/kernel/src/initrd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub fn init(modules: &[BootModule]) {
}
let obj = Arc::new(obj);
obj::register_object(obj.clone());
if e.filename().as_str() == "init" {
if e.filename().as_str() == "bootstrap" {
boot_objects.init = Some(obj.clone());
}
boot_objects
Expand Down
20 changes: 19 additions & 1 deletion src/runtime/monitor-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::{
};

use dynlink::tls::{Tcb, TlsRegion};
use twizzler_abi::object::ObjID;
use twizzler_abi::object::{ObjID, MAX_SIZE, NULLPAGE_SIZE};

mod gates {
include! {"../../monitor/secapi/gates.rs"}
Expand Down Expand Up @@ -163,3 +163,21 @@ impl SharedCompConfig {
}

pub use gates::LibraryInfo;

/// Contains raw mapping addresses, for use when translating to object handles for the runtime.
#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq)]
pub struct MappedObjectAddrs {
pub slot: usize,
pub start: usize,
pub meta: usize,
}

impl MappedObjectAddrs {
pub fn new(slot: usize) -> Self {
Self {
start: slot * MAX_SIZE,
meta: (slot + 1) * MAX_SIZE - NULLPAGE_SIZE,
slot,
}
}
}
2 changes: 2 additions & 0 deletions src/runtime/monitor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ monitor-api = { path = "../monitor-api" }
static_assertions = "1.1"
lazy_static = "1.4"
talc = "3.1"
happylock = "0.3"
parking_lot = "*"

[features]
secgate-impl = []
Expand Down
4 changes: 3 additions & 1 deletion src/runtime/monitor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ mod state;
mod thread;
mod upcall;

mod mon;

#[path = "../secapi/gates.rs"]
mod gates;

Expand Down Expand Up @@ -95,7 +97,7 @@ fn monitor_init(state: Arc<Mutex<MonitorState>>) -> miette::Result<()> {
}
}

load_hello_world_test(&state).unwrap();
//load_hello_world_test(&state).unwrap();

Ok(())
}
Expand Down
1 change: 1 addition & 0 deletions src/runtime/monitor/src/mon/compartment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub struct CompartmentMgr {}
29 changes: 29 additions & 0 deletions src/runtime/monitor/src/mon/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use std::sync::OnceLock;

use happylock::RwLock;

use self::space::Unmapper;

mod compartment;
mod space;
mod thread;

pub struct Monitor {
space: RwLock<space::Space>,
thread_mgr: RwLock<thread::ThreadMgr>,
compartments: RwLock<compartment::CompartmentMgr>,
dynlink: RwLock<dynlink::context::Context>,
unmapper: Unmapper,
}

static MONITOR: OnceLock<Monitor> = OnceLock::new();

pub fn get_monitor() -> &'static Monitor {
MONITOR.get().unwrap()
}

pub fn set_monitor(monitor: Monitor) {
if MONITOR.set(monitor).is_err() {
panic!("second call to set_monitor");
}
}
119 changes: 119 additions & 0 deletions src/runtime/monitor/src/mon/space.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use std::{collections::HashMap, sync::Arc};

use monitor_api::MappedObjectAddrs;
use twizzler_abi::syscall::{sys_object_map, sys_object_unmap, UnmapFlags};
use twizzler_object::Protections;
use twizzler_runtime_api::{MapError, MapFlags, ObjID};

use self::handle::{MapHandle, MapHandleInner};

mod handle;
mod unmapper;

pub use unmapper::Unmapper;

#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
pub struct MapInfo {
pub(crate) id: ObjID,
pub(crate) flags: MapFlags,
}

#[derive(Default)]
pub struct Space {
maps: HashMap<MapInfo, MappedObject>,
}

struct MappedObject {
addrs: MappedObjectAddrs,
handle_count: usize,
}

fn mapflags_into_prot(flags: MapFlags) -> Protections {
let mut prot = Protections::empty();
if flags.contains(MapFlags::READ) {
prot.insert(Protections::READ);
}
if flags.contains(MapFlags::WRITE) {
prot.insert(Protections::WRITE);
}
if flags.contains(MapFlags::EXEC) {
prot.insert(Protections::EXEC);
}
prot
}

impl Space {
pub fn map(&mut self, info: MapInfo) -> Result<MapHandle, MapError> {
// Can't use the entry API here because the closure may fail.
let item = match self.maps.get_mut(&info) {
Some(item) => item,
None => {
// Not yet mapped, so allocate a slot and map it.
let slot = twz_rt::OUR_RUNTIME
.allocate_slot()
.ok_or(MapError::OutOfResources)?;

let Ok(_) = sys_object_map(
None,
info.id,
slot,
mapflags_into_prot(info.flags),
twizzler_abi::syscall::MapFlags::empty(),
) else {
twz_rt::OUR_RUNTIME.release_slot(slot);
return Err(MapError::InternalError);
};

let map = MappedObject {
addrs: MappedObjectAddrs::new(slot),
handle_count: 0,
};
self.maps.insert(info, map);
// Unwrap-Ok: just inserted.
self.maps.get_mut(&info).unwrap()
}
};

// New maps will be set to zero, so this is unconditional.
item.handle_count += 1;
Ok(Arc::new(MapHandleInner::new(info, item.addrs)))
}

pub fn handle_drop(&mut self, info: MapInfo) -> Option<UnmapOnDrop> {
// Missing maps in unmap should be ignored.
let Some(item) = self.maps.get_mut(&info) else {
tracing::warn!("unmap called for missing object {:?}", info);
return None;
};
if item.handle_count == 0 {
tracing::error!("unmap called for unmapped object {:?}", info);
return None;
}

// Decrement and maybe actually unmap.
item.handle_count -= 1;
if item.handle_count == 0 {
let slot = item.addrs.slot;
self.maps.remove(&info);
Some(UnmapOnDrop { slot })
} else {
None
}
}
}

// Allows us to call handle_drop and do all the hard work in the caller, since
// the caller probably had to hold a lock to call these functions.
pub(crate) struct UnmapOnDrop {
slot: usize,
}

impl Drop for UnmapOnDrop {
fn drop(&mut self) {
if sys_object_unmap(None, self.slot, UnmapFlags::empty()).is_ok() {
twz_rt::OUR_RUNTIME.release_slot(self.slot);
} else {
tracing::warn!("failed to unmap slot {}", self.slot);
}
}
}
40 changes: 40 additions & 0 deletions src/runtime/monitor/src/mon/space/handle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use std::sync::Arc;

use monitor_api::MappedObjectAddrs;
use twizzler_abi::object::NULLPAGE_SIZE;

use super::MapInfo;
use crate::mon::get_monitor;

pub struct MapHandleInner {
info: MapInfo,
map: MappedObjectAddrs,
}

pub type MapHandle = Arc<MapHandleInner>;

impl MapHandleInner {
pub(crate) fn new(info: MapInfo, map: MappedObjectAddrs) -> Self {
Self { info, map }
}

pub fn addrs(&self) -> MappedObjectAddrs {
self.map
}

pub fn monitor_data_null(&self) -> *mut u8 {
self.map.start as *mut u8
}

pub fn monitor_data_base(&self) -> *mut u8 {
(self.map.start + NULLPAGE_SIZE) as *mut u8
}
}

impl Drop for MapHandleInner {
fn drop(&mut self) {
// Toss this work onto a background thread.
let monitor = get_monitor();
monitor.unmapper.background_unmap_info(self.info);
}
}
47 changes: 47 additions & 0 deletions src/runtime/monitor/src/mon/space/unmapper.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use std::{panic::catch_unwind, sync::mpsc::Sender, thread::JoinHandle};

use super::MapInfo;
use crate::mon::get_monitor;

pub struct Unmapper {
sender: Sender<MapInfo>,
thread: JoinHandle<()>,
}

impl Unmapper {
pub fn new(cb: fn(MapInfo)) -> Self {
let (sender, receiver) = std::sync::mpsc::channel();
Self {
thread: std::thread::spawn(move || loop {
let key = happylock::ThreadKey::get().unwrap();
match receiver.recv() {
Ok(info) => {
if let Err(_) = catch_unwind(|| {
let monitor = get_monitor();
let mut space = monitor.space.write(key);
space.handle_drop(info);
}) {
tracing::error!("clean_call panicked -- exiting map cleaner thread");
break;
}
}
Err(_) => {
// If receive fails, we can't recover, but this probably doesn't happen
// since the sender won't get dropped since this
// struct is used in the MapMan static.
break;
}
}
}),
sender,
}
}

pub(super) fn background_unmap_info(&self, info: MapInfo) {
// If the receiver is down, this will fail, but that also shouldn't happen, unless the
// call to clean_call above panics. In any case, handle this gracefully.
if self.sender.send(info).is_err() {
tracing::warn!("failed to enqueue {:?} onto cleaner thread", info);
}
}
}
1 change: 1 addition & 0 deletions src/runtime/monitor/src/mon/thread.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub struct ThreadMgr {}

0 comments on commit c317856

Please sign in to comment.