diff --git a/src/context/context.rs b/src/context/context.rs
index aed8a03a77491e41dd624877b032475c255bf75e..bcd42f65efae7b6313e09cfca72869aa9b4939bd 100644
--- a/src/context/context.rs
+++ b/src/context/context.rs
@@ -35,10 +35,27 @@ int_like!(ContextId, AtomicContextId, usize, AtomicUsize);
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum Status {
     Runnable,
+
+    // TODO: Rename to SoftBlocked and move status_reason to this variant.
+
+    /// Not currently runnable, typically due to some blocking syscall, but it can be trivially
+    /// unblocked by e.g. signals.
     Blocked,
+
+    /// Not currently runnable, and cannot be runnable until manually unblocked, depending on what
+    /// reason.
+    HardBlocked { reason: HardBlockedReason },
+
     Stopped(usize),
     Exited(usize),
 }
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum HardBlockedReason {
+    AwaitingMmap,
+    // TODO: PageFaultOom?
+    // TODO: NotYetStarted/ManuallyBlocked (when new contexts are created)
+    // TODO: ptrace_stop?
+}
 
 #[derive(Copy, Clone, Debug)]
 pub struct WaitpidKey {
diff --git a/src/scheme/sys/context.rs b/src/scheme/sys/context.rs
index 2a5aaca7aaa26c24c4cc4740d99959184b988b57..632b2e0ea7ef7b09febeb06892f1d8c77e2f5f12 100644
--- a/src/scheme/sys/context.rs
+++ b/src/scheme/sys/context.rs
@@ -43,7 +43,7 @@ pub fn resource() -> Result<Vec<u8>> {
                 context::Status::Runnable => {
                     stat_string.push('R');
                 },
-                context::Status::Blocked => if context.wake.is_some() {
+                context::Status::Blocked | context::Status::HardBlocked { .. } => if context.wake.is_some() {
                     stat_string.push('S');
                 } else {
                     stat_string.push('B');