about summary refs log tree commit diff
diff options
context:
space:
mode:
authorStefan Lankes <slankes@eonerc.rwth-aachen.de>2019-10-06 15:26:14 +0000
committerStefan Lankes <slankes@eonerc.rwth-aachen.de>2019-10-06 15:26:14 +0000
commitc1e440a90f472468c8069ba6254b23c6feedc32e (patch)
tree6e7920b36e0ecd63e8b7b1a6ec236ff5e86a5a01
parent7870050796e5904a0fc85ecbe6fa6dde1cfe0c91 (diff)
downloadrust-c1e440a90f472468c8069ba6254b23c6feedc32e.tar.gz
rust-c1e440a90f472468c8069ba6254b23c6feedc32e.zip
redesign of the interface to the unikernel HermitCore
- the old interface between HermitCore and the Rust Standard Library
  based on a small C library (newlib)
- remove this interface and call directly the unikernel
- remove the dependency to the HermitCore linker
- use rust-lld as linker
-rw-r--r--src/bootstrap/lib.rs2
-rw-r--r--src/libpanic_abort/lib.rs3
-rw-r--r--src/libpanic_unwind/hermit.rs21
-rw-r--r--src/libpanic_unwind/lib.rs3
-rw-r--r--src/librustc_target/spec/hermit_base.rs24
-rw-r--r--src/librustc_target/spec/x86_64_unknown_hermit.rs8
-rw-r--r--src/librustdoc/clean/cfg.rs1
-rw-r--r--src/libstd/build.rs2
-rw-r--r--src/libstd/os/hermit/fs.rs377
-rw-r--r--src/libstd/os/hermit/mod.rs6
-rw-r--r--src/libstd/os/hermit/raw.rs17
-rw-r--r--src/libstd/os/mod.rs1
-rw-r--r--src/libstd/rt.rs3
-rw-r--r--src/libstd/sys/hermit/alloc.rs40
-rw-r--r--src/libstd/sys/hermit/args.rs82
-rw-r--r--src/libstd/sys/hermit/cmath.rs29
-rw-r--r--src/libstd/sys/hermit/condvar.rs68
-rw-r--r--src/libstd/sys/hermit/env.rs9
-rw-r--r--src/libstd/sys/hermit/fast_thread_local.rs4
-rw-r--r--src/libstd/sys/hermit/fd.rs87
-rw-r--r--src/libstd/sys/hermit/fs.rs389
-rw-r--r--src/libstd/sys/hermit/io.rs46
-rw-r--r--src/libstd/sys/hermit/memchr.rs1
-rw-r--r--src/libstd/sys/hermit/mod.rs148
-rw-r--r--src/libstd/sys/hermit/mutex.rs88
-rw-r--r--src/libstd/sys/hermit/net.rs364
-rw-r--r--src/libstd/sys/hermit/os.rs178
-rw-r--r--src/libstd/sys/hermit/path.rs19
-rw-r--r--src/libstd/sys/hermit/pipe.rs33
-rw-r--r--src/libstd/sys/hermit/process.rs154
-rw-r--r--src/libstd/sys/hermit/rwlock.rs51
-rw-r--r--src/libstd/sys/hermit/stack_overflow.rs15
-rw-r--r--src/libstd/sys/hermit/stdio.rs122
-rw-r--r--src/libstd/sys/hermit/thread.rs121
-rw-r--r--src/libstd/sys/hermit/thread_local.rs61
-rw-r--r--src/libstd/sys/hermit/time.rs188
-rw-r--r--src/libstd/sys/mod.rs4
-rw-r--r--src/libstd/sys/unix/alloc.rs2
-rw-r--r--src/libstd/sys/unix/args.rs1
-rw-r--r--src/libstd/sys/unix/condvar.rs7
-rw-r--r--src/libstd/sys/unix/env.rs11
-rw-r--r--src/libstd/sys/unix/fs.rs8
-rw-r--r--src/libstd/sys/unix/mod.rs1
-rw-r--r--src/libstd/sys/unix/os.rs3
-rw-r--r--src/libstd/sys/unix/thread.rs1
-rw-r--r--src/libstd/sys/unix/time.rs4
-rw-r--r--src/libstd/sys_common/mod.rs2
-rw-r--r--src/libtest/lib.rs7
-rw-r--r--src/libunwind/build.rs2
-rw-r--r--src/libunwind/libunwind.rs19
-rw-r--r--src/tools/build-manifest/src/main.rs2
51 files changed, 2388 insertions, 451 deletions
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 9203a558f64..c2aa75fd88f 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -160,7 +160,7 @@ mod job {
     }
 }
 
-#[cfg(any(target_os = "haiku", not(any(unix, windows))))]
+#[cfg(any(target_os = "haiku", target_os = "hermit", not(any(unix, windows))))]
 mod job {
     pub unsafe fn setup(_build: &mut crate::Build) {
     }
diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs
index fd144d6b67e..5509f47bc88 100644
--- a/src/libpanic_abort/lib.rs
+++ b/src/libpanic_abort/lib.rs
@@ -54,7 +54,8 @@ pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 {
         core::intrinsics::abort();
     }
 
-    #[cfg(all(target_vendor="fortanix", target_env="sgx"))]
+    #[cfg(any(target_os = "hermit",
+              all(target_vendor="fortanix", target_env="sgx")))]
     unsafe fn abort() -> ! {
         // call std::sys::abort_internal
         extern "C" { pub fn __rust_abort() -> !; }
diff --git a/src/libpanic_unwind/hermit.rs b/src/libpanic_unwind/hermit.rs
new file mode 100644
index 00000000000..8bee6ff09e5
--- /dev/null
+++ b/src/libpanic_unwind/hermit.rs
@@ -0,0 +1,21 @@
+//! Unwinding for *hermit* target.
+//!
+//! Right now we don't support this, so this is just stubs.
+
+use alloc::boxed::Box;
+use core::ptr;
+use core::any::Any;
+
+pub fn payload() -> *mut u8 {
+    ptr::null_mut()
+}
+
+pub unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> {
+    extern "C" { pub fn __rust_abort() -> !; }
+    __rust_abort();
+}
+
+pub unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 {
+    extern "C" { pub fn __rust_abort() -> !; }
+    __rust_abort();
+}
diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs
index 06e6e768f45..2089a02083c 100644
--- a/src/libpanic_unwind/lib.rs
+++ b/src/libpanic_unwind/lib.rs
@@ -43,6 +43,9 @@ cfg_if::cfg_if! {
     } else if #[cfg(target_arch = "wasm32")] {
         #[path = "dummy.rs"]
         mod imp;
+    } else if #[cfg(target_os = "hermit")] {
+        #[path = "hermit.rs"]
+        mod imp;
     } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] {
         #[path = "dummy.rs"]
         mod imp;
diff --git a/src/librustc_target/spec/hermit_base.rs b/src/librustc_target/spec/hermit_base.rs
index ee753393ddb..f31de4dbd51 100644
--- a/src/librustc_target/spec/hermit_base.rs
+++ b/src/librustc_target/spec/hermit_base.rs
@@ -1,26 +1,26 @@
-use crate::spec::{LinkArgs, LinkerFlavor, PanicStrategy, TargetOptions};
+use crate::spec::{LldFlavor, LinkArgs, LinkerFlavor, PanicStrategy, TargetOptions};
 use std::default::Default;
 
 pub fn opts() -> TargetOptions {
-    let mut args = LinkArgs::new();
-    args.insert(LinkerFlavor::Gcc, vec![
-        "-Wl,-Bstatic".to_string(),
-        "-Wl,--no-dynamic-linker".to_string(),
-        "-Wl,--gc-sections".to_string(),
-        "-Wl,--as-needed".to_string(),
+    let mut pre_link_args = LinkArgs::new();
+    pre_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), vec![
+        "--build-id".to_string(),
+        "--hash-style=gnu".to_string(),
+        "--Bstatic".to_string(),
     ]);
 
     TargetOptions {
+        linker: Some("rust-lld".to_owned()),
         executables: true,
         has_elf_tls: true,
         linker_is_gnu: true,
-        no_default_libraries: false,
+        pre_link_args,
+        no_default_libraries: true,
         panic_strategy: PanicStrategy::Abort,
-        position_independent_executables: false,
-        pre_link_args: args,
+        position_independent_executables: true,
         relocation_model: "static".to_string(),
-        target_family: Some("unix".to_string()),
-        tls_model: "local-exec".to_string(),
+        target_family: None,
+        tls_model: "initial-exec".to_string(),
         .. Default::default()
     }
 }
diff --git a/src/librustc_target/spec/x86_64_unknown_hermit.rs b/src/librustc_target/spec/x86_64_unknown_hermit.rs
index a696ee16d7c..b8be43be097 100644
--- a/src/librustc_target/spec/x86_64_unknown_hermit.rs
+++ b/src/librustc_target/spec/x86_64_unknown_hermit.rs
@@ -1,11 +1,11 @@
-use crate::spec::{LinkerFlavor, Target, TargetResult};
+use crate::spec::{LldFlavor, LinkerFlavor, Target, TargetResult};
 
 pub fn target() -> TargetResult {
     let mut base = super::hermit_base::opts();
     base.cpu = "x86-64".to_string();
-    base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string());
-    base.linker = Some("x86_64-hermit-gcc".to_string());
     base.max_atomic_width = Some(64);
+    base.features = "+rdrnd,+rdseed".to_string();
+    base.stack_probes = true;
 
     Ok(Target {
         llvm_target: "x86_64-unknown-hermit".to_string(),
@@ -17,7 +17,7 @@ pub fn target() -> TargetResult {
         target_os: "hermit".to_string(),
         target_env: String::new(),
         target_vendor: "unknown".to_string(),
-        linker_flavor: LinkerFlavor::Gcc,
+        linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld),
         options: base,
     })
 }
diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs
index 7de2583b9f6..cf440924b2e 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -346,6 +346,7 @@ impl<'a> fmt::Display for Html<'a> {
                         "freebsd" => "FreeBSD",
                         "fuchsia" => "Fuchsia",
                         "haiku" => "Haiku",
+                        "hermit" => "HermitCore",
                         "ios" => "iOS",
                         "l4re" => "L4Re",
                         "linux" => "Linux",
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 8db7bc12cd3..1f839f16532 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -54,5 +54,7 @@ fn main() {
         }
         println!("cargo:rustc-link-lib=c");
         println!("cargo:rustc-link-lib=compiler_rt");
+    } else if target.contains("hermit") {
+        println!("cargo:rustc-link-lib=hermit");
     }
 }
diff --git a/src/libstd/os/hermit/fs.rs b/src/libstd/os/hermit/fs.rs
deleted file mode 100644
index eb28a839ba8..00000000000
--- a/src/libstd/os/hermit/fs.rs
+++ /dev/null
@@ -1,377 +0,0 @@
-#![stable(feature = "metadata_ext", since = "1.1.0")]
-
-use crate::fs::Metadata;
-use crate::sys_common::AsInner;
-
-#[allow(deprecated)]
-use crate::os::hermit::raw;
-
-/// OS-specific extensions to [`fs::Metadata`].
-///
-/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-pub trait MetadataExt {
-    /// Gain a reference to the underlying `stat` structure which contains
-    /// the raw information returned by the OS.
-    ///
-    /// The contents of the returned [`stat`] are **not** consistent across
-    /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
-    /// cross-Unix abstractions contained within the raw stat.
-    ///
-    /// [`stat`]: ../../../../std/os/linux/raw/struct.stat.html
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     let stat = meta.as_raw_stat();
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext", since = "1.1.0")]
-    #[rustc_deprecated(since = "1.8.0",
-                       reason = "deprecated in favor of the accessor \
-                                 methods of this trait")]
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat;
-
-    /// Returns the device ID on which this file resides.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_dev());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_dev(&self) -> u64;
-    /// Returns the inode number.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_ino());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ino(&self) -> u64;
-    /// Returns the file type and mode.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_mode());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mode(&self) -> u32;
-    /// Returns the number of hard links to file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_nlink());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_nlink(&self) -> u64;
-    /// Returns the user ID of the file owner.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_uid());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_uid(&self) -> u32;
-    /// Returns the group ID of the file owner.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_gid());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_gid(&self) -> u32;
-    /// Returns the device ID that this file represents. Only relevant for special file.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_rdev());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_rdev(&self) -> u64;
-    /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
-    ///
-    /// The size of a symbolic link is the length of the pathname it contains,
-    /// without a terminating null byte.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_size());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_size(&self) -> u64;
-    /// Returns the last access time.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_atime());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime(&self) -> i64;
-    /// Returns the last access time, nano seconds part.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_atime_nsec());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_atime_nsec(&self) -> i64;
-    /// Returns the last modification time.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_mtime());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime(&self) -> i64;
-    /// Returns the last modification time, nano seconds part.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_mtime_nsec());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_mtime_nsec(&self) -> i64;
-    /// Returns the last status change time.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_ctime());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime(&self) -> i64;
-    /// Returns the last status change time, nano seconds part.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_ctime_nsec());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_ctime_nsec(&self) -> i64;
-    /// Returns the "preferred" blocksize for efficient filesystem I/O.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_blksize());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blksize(&self) -> u64;
-    /// Returns the number of blocks allocated to the file, 512-byte units.
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// use std::fs;
-    /// use std::io;
-    /// use std::os::linux::fs::MetadataExt;
-    ///
-    /// fn main() -> io::Result<()> {
-    ///     let meta = fs::metadata("some_file")?;
-    ///     println!("{}", meta.st_blocks());
-    ///     Ok(())
-    /// }
-    /// ```
-    #[stable(feature = "metadata_ext2", since = "1.8.0")]
-    fn st_blocks(&self) -> u64;
-}
-
-#[stable(feature = "metadata_ext", since = "1.1.0")]
-impl MetadataExt for Metadata {
-    #[allow(deprecated)]
-    fn as_raw_stat(&self) -> &raw::stat {
-        unsafe {
-            &*(self.as_inner().as_inner() as *const libc::stat64
-                                          as *const raw::stat)
-        }
-    }
-    fn st_dev(&self) -> u64 {
-        self.as_inner().as_inner().st_dev as u64
-    }
-    fn st_ino(&self) -> u64 {
-        self.as_inner().as_inner().st_ino as u64
-    }
-    fn st_mode(&self) -> u32 {
-        self.as_inner().as_inner().st_mode as u32
-    }
-    fn st_nlink(&self) -> u64 {
-        self.as_inner().as_inner().st_nlink as u64
-    }
-    fn st_uid(&self) -> u32 {
-        self.as_inner().as_inner().st_uid as u32
-    }
-    fn st_gid(&self) -> u32 {
-        self.as_inner().as_inner().st_gid as u32
-    }
-    fn st_rdev(&self) -> u64 {
-        self.as_inner().as_inner().st_rdev as u64
-    }
-    fn st_size(&self) -> u64 {
-        self.as_inner().as_inner().st_size as u64
-    }
-    fn st_atime(&self) -> i64 {
-        self.as_inner().as_inner().st_atime as i64
-    }
-    fn st_atime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_atime_nsec as i64
-    }
-    fn st_mtime(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime as i64
-    }
-    fn st_mtime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_mtime_nsec as i64
-    }
-    fn st_ctime(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime as i64
-    }
-    fn st_ctime_nsec(&self) -> i64 {
-        self.as_inner().as_inner().st_ctime_nsec as i64
-    }
-    fn st_blksize(&self) -> u64 {
-        self.as_inner().as_inner().st_blksize as u64
-    }
-    fn st_blocks(&self) -> u64 {
-        self.as_inner().as_inner().st_blocks as u64
-    }
-}
diff --git a/src/libstd/os/hermit/mod.rs b/src/libstd/os/hermit/mod.rs
deleted file mode 100644
index 4dee2a6d433..00000000000
--- a/src/libstd/os/hermit/mod.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//! HermitCore-specific definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-
-pub mod raw;
-pub mod fs;
diff --git a/src/libstd/os/hermit/raw.rs b/src/libstd/os/hermit/raw.rs
deleted file mode 100644
index 0e232a808a0..00000000000
--- a/src/libstd/os/hermit/raw.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//! HermitCore-specific raw type definitions
-
-#![stable(feature = "raw_ext", since = "1.1.0")]
-#![rustc_deprecated(since = "1.8.0",
-                    reason = "these type aliases are no longer supported by \
-                              the standard library, the `libc` crate on \
-                              crates.io should be used instead for the correct \
-                              definitions")]
-#![allow(deprecated)]
-#![allow(missing_debug_implementations)]
-
-#[stable(feature = "pthread_t", since = "1.8.0")]
-pub use libc::pthread_t;
-
-#[doc(inline)]
-#[stable(feature = "raw_ext", since = "1.1.0")]
-pub use libc::{dev_t, mode_t, off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs
index fcd81f0a1b2..d44c8ca544e 100644
--- a/src/libstd/os/mod.rs
+++ b/src/libstd/os/mod.rs
@@ -49,7 +49,6 @@ cfg_if::cfg_if! {
 #[cfg(target_os = "solaris")]    pub mod solaris;
 #[cfg(target_os = "emscripten")] pub mod emscripten;
 #[cfg(target_os = "fuchsia")]    pub mod fuchsia;
-#[cfg(target_os = "hermit")]     pub mod hermit;
 #[cfg(target_os = "redox")]      pub mod redox;
 #[cfg(target_os = "wasi")]       pub mod wasi;
 #[cfg(target_os = "vxworks")]    pub mod vxworks;
diff --git a/src/libstd/rt.rs b/src/libstd/rt.rs
index cf45eb0daba..7a5b46be252 100644
--- a/src/libstd/rt.rs
+++ b/src/libstd/rt.rs
@@ -59,7 +59,6 @@ fn lang_start_internal(main: &(dyn Fn() -> i32 + Sync + crate::panic::RefUnwindS
 #[cfg(not(test))]
 #[lang = "start"]
 fn lang_start<T: crate::process::Termination + 'static>
-    (main: fn() -> T, argc: isize, argv: *const *const u8) -> isize
-{
+    (main: fn() -> T, argc: isize, argv: *const *const u8) -> isize {
     lang_start_internal(&move || main().report(), argc, argv)
 }
diff --git a/src/libstd/sys/hermit/alloc.rs b/src/libstd/sys/hermit/alloc.rs
new file mode 100644
index 00000000000..802a179fb67
--- /dev/null
+++ b/src/libstd/sys/hermit/alloc.rs
@@ -0,0 +1,40 @@
+use crate::alloc::{GlobalAlloc, Layout, System};
+use crate::ptr;
+
+extern "C" {
+    fn sys_malloc(size: usize, align: usize) -> *mut u8;
+    fn sys_realloc(ptr: *mut u8, size: usize, align: usize, new_size: usize) -> *mut u8;
+    fn sys_free(ptr: *mut u8, size: usize, align: usize);
+}
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+    #[inline]
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        sys_malloc(layout.size(), layout.align())
+    }
+
+    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+        let addr = sys_malloc(layout.size(), layout.align());
+
+        if !addr.is_null() {
+            ptr::write_bytes(
+                addr,
+                0x00,
+                layout.size()
+            );
+        }
+
+        addr
+    }
+
+    #[inline]
+    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+        sys_free(ptr, layout.size(), layout.align())
+    }
+
+    #[inline]
+    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        sys_realloc(ptr, layout.size(), layout.align(), new_size)
+    }
+}
diff --git a/src/libstd/sys/hermit/args.rs b/src/libstd/sys/hermit/args.rs
new file mode 100644
index 00000000000..5b1f3add51f
--- /dev/null
+++ b/src/libstd/sys/hermit/args.rs
@@ -0,0 +1,82 @@
+use crate::ffi::OsString;
+use crate::marker::PhantomData;
+use crate::vec;
+
+/// One-time global initialization.
+pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
+
+/// One-time global cleanup.
+pub unsafe fn cleanup() { imp::cleanup() }
+
+/// Returns the command line arguments
+pub fn args() -> Args {
+    imp::args()
+}
+
+pub struct Args {
+    iter: vec::IntoIter<OsString>,
+    _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Args {
+    pub fn inner_debug(&self) -> &[OsString] {
+        self.iter.as_slice()
+    }
+}
+
+impl Iterator for Args {
+    type Item = OsString;
+    fn next(&mut self) -> Option<OsString> { self.iter.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+impl ExactSizeIterator for Args {
+    fn len(&self) -> usize { self.iter.len() }
+}
+
+impl DoubleEndedIterator for Args {
+    fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
+}
+
+mod imp {
+    use crate::sys_common::os_str_bytes::*;
+    use crate::ptr;
+    use crate::ffi::{CStr, OsString};
+    use crate::marker::PhantomData;
+    use super::Args;
+
+    use crate::sys_common::mutex::Mutex;
+
+    static mut ARGC: isize = 0;
+    static mut ARGV: *const *const u8 = ptr::null();
+    static LOCK: Mutex = Mutex::new();
+
+    pub unsafe fn init(argc: isize, argv: *const *const u8) {
+        let _guard = LOCK.lock();
+        ARGC = argc;
+        ARGV = argv;
+    }
+
+    pub unsafe fn cleanup() {
+        let _guard = LOCK.lock();
+        ARGC = 0;
+        ARGV = ptr::null();
+    }
+
+    pub fn args() -> Args {
+        Args {
+            iter: clone().into_iter(),
+            _dont_send_or_sync_me: PhantomData
+        }
+    }
+
+    fn clone() -> Vec<OsString> {
+        unsafe {
+            let _guard = LOCK.lock();
+            (0..ARGC).map(|i| {
+                let cstr = CStr::from_ptr(*ARGV.offset(i) as *const i8);
+                OsStringExt::from_vec(cstr.to_bytes().to_vec())
+            }).collect()
+        }
+    }
+}
diff --git a/src/libstd/sys/hermit/cmath.rs b/src/libstd/sys/hermit/cmath.rs
new file mode 100644
index 00000000000..fa7783122c2
--- /dev/null
+++ b/src/libstd/sys/hermit/cmath.rs
@@ -0,0 +1,29 @@
+// These symbols are all defined in `compiler-builtins`
+extern {
+    pub fn acos(n: f64) -> f64;
+    pub fn acosf(n: f32) -> f32;
+    pub fn asin(n: f64) -> f64;
+    pub fn asinf(n: f32) -> f32;
+    pub fn atan(n: f64) -> f64;
+    pub fn atan2(a: f64, b: f64) -> f64;
+    pub fn atan2f(a: f32, b: f32) -> f32;
+    pub fn atanf(n: f32) -> f32;
+    pub fn cbrt(n: f64) -> f64;
+    pub fn cbrtf(n: f32) -> f32;
+    pub fn cosh(n: f64) -> f64;
+    pub fn coshf(n: f32) -> f32;
+    pub fn expm1(n: f64) -> f64;
+    pub fn expm1f(n: f32) -> f32;
+    pub fn fdim(a: f64, b: f64) -> f64;
+    pub fn fdimf(a: f32, b: f32) -> f32;
+    pub fn hypot(x: f64, y: f64) -> f64;
+    pub fn hypotf(x: f32, y: f32) -> f32;
+    pub fn log1p(n: f64) -> f64;
+    pub fn log1pf(n: f32) -> f32;
+    pub fn sinh(n: f64) -> f64;
+    pub fn sinhf(n: f32) -> f32;
+    pub fn tan(n: f64) -> f64;
+    pub fn tanf(n: f32) -> f32;
+    pub fn tanh(n: f64) -> f64;
+    pub fn tanhf(n: f32) -> f32;
+}
diff --git a/src/libstd/sys/hermit/condvar.rs b/src/libstd/sys/hermit/condvar.rs
new file mode 100644
index 00000000000..1cd97d95ad2
--- /dev/null
+++ b/src/libstd/sys/hermit/condvar.rs
@@ -0,0 +1,68 @@
+use crate::cmp;
+use crate::sys::mutex::Mutex;
+use crate::time::Duration;
+
+pub struct Condvar {
+    identifier: usize,
+}
+
+extern "C" {
+   fn sys_notify(id: usize, count: i32) -> i32;
+   fn sys_add_queue(id: usize, timeout_ns: i64) -> i32;
+   fn sys_wait(id: usize) -> i32;
+   fn sys_destroy_queue(id: usize) -> i32;
+}
+
+impl Condvar {
+    pub const fn new() -> Condvar {
+        Condvar { identifier: 0 }
+    }
+
+    #[inline]
+    pub unsafe fn init(&mut self) {
+        // nothing to do
+    }
+
+    pub unsafe fn notify_one(&self) {
+         let _ = sys_notify(self.id(), 1);
+    }
+
+    #[inline]
+    pub unsafe fn notify_all(&self) {
+         let _ = sys_notify(self.id(), -1 /* =all */);
+    }
+
+    pub unsafe fn wait(&self, mutex: &Mutex) {
+        // add current task to the wait queue
+        let _ = sys_add_queue(self.id(), -1 /* no timeout */);
+        mutex.unlock();
+        let _ = sys_wait(self.id());
+        mutex.lock();
+    }
+
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        let nanos = dur.as_nanos();
+        let nanos = cmp::min(i64::max_value() as u128, nanos);
+
+        // add current task to the wait queue
+        let _ = sys_add_queue(self.id(), nanos as i64);
+
+        mutex.unlock();
+        // If the return value is !0 then a timeout happened, so we return
+        // `false` as we weren't actually notified.
+        let ret = sys_wait(self.id()) == 0;
+        mutex.lock();
+
+        ret
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        let _ = sys_destroy_queue(self.id());
+    }
+
+    #[inline]
+    fn id(&self) -> usize {
+        &self.identifier as *const usize as usize
+    }
+}
diff --git a/src/libstd/sys/hermit/env.rs b/src/libstd/sys/hermit/env.rs
new file mode 100644
index 00000000000..7a0fcb31ef2
--- /dev/null
+++ b/src/libstd/sys/hermit/env.rs
@@ -0,0 +1,9 @@
+pub mod os {
+    pub const FAMILY: &str = "";
+    pub const OS: &str = "hermit";
+    pub const DLL_PREFIX: &str = "";
+    pub const DLL_SUFFIX: &str = "";
+    pub const DLL_EXTENSION: &str = "";
+    pub const EXE_SUFFIX: &str = "";
+    pub const EXE_EXTENSION: &str = "";
+}
diff --git a/src/libstd/sys/hermit/fast_thread_local.rs b/src/libstd/sys/hermit/fast_thread_local.rs
new file mode 100644
index 00000000000..05464787a05
--- /dev/null
+++ b/src/libstd/sys/hermit/fast_thread_local.rs
@@ -0,0 +1,4 @@
+#![cfg(target_thread_local)]
+#![unstable(feature = "thread_local_internals", issue = "0")]
+
+pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor;
diff --git a/src/libstd/sys/hermit/fd.rs b/src/libstd/sys/hermit/fd.rs
new file mode 100644
index 00000000000..cbc167a677f
--- /dev/null
+++ b/src/libstd/sys/hermit/fd.rs
@@ -0,0 +1,87 @@
+#![unstable(reason = "not public", issue = "0", feature = "fd")]
+
+use crate::io::{self, Read, ErrorKind};
+use crate::mem;
+use crate::sys::cvt;
+use crate::sys_common::AsInner;
+
+extern {
+    fn sys_read(fd: i32, buf: *mut u8, len: usize) -> isize;
+    fn sys_write(fd: i32, buf: *const u8, len: usize) -> isize;
+    fn sys_close(fd: i32) -> i32;
+}
+
+#[derive(Debug)]
+pub struct FileDesc {
+    fd: i32,
+}
+
+impl FileDesc {
+    pub fn new(fd: i32) -> FileDesc {
+        FileDesc { fd }
+    }
+
+    pub fn raw(&self) -> i32 { self.fd }
+
+    /// Extracts the actual file descriptor without closing it.
+    pub fn into_raw(self) -> i32 {
+        let fd = self.fd;
+        mem::forget(self);
+        fd
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let result = unsafe { sys_read(self.fd, buf.as_mut_ptr(), buf.len()) };
+        cvt(result as i32)
+    }
+
+    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+        let mut me = self;
+        (&mut me).read_to_end(buf)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let result = unsafe { sys_write(self.fd, buf.as_ptr(), buf.len()) };
+        cvt(result as i32)
+    }
+
+    pub fn duplicate(&self) -> io::Result<FileDesc> {
+        self.duplicate_path(&[])
+    }
+    pub fn duplicate_path(&self, _path: &[u8]) -> io::Result<FileDesc> {
+        Err(io::Error::new(ErrorKind::Other, "duplicate isn't supported"))
+    }
+
+    pub fn nonblocking(&self) -> io::Result<bool> {
+        Ok(false)
+    }
+
+    pub fn set_cloexec(&self) -> io::Result<()> {
+        Err(io::Error::new(ErrorKind::Other, "cloexec isn't supported"))
+    }
+
+    pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> {
+        Err(io::Error::new(ErrorKind::Other, "nonblocking isn't supported"))
+    }
+}
+
+impl<'a> Read for &'a FileDesc {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        (**self).read(buf)
+    }
+}
+
+impl AsInner<i32> for FileDesc {
+    fn as_inner(&self) -> &i32 { &self.fd }
+}
+
+impl Drop for FileDesc {
+    fn drop(&mut self) {
+        // Note that errors are ignored when closing a file descriptor. The
+        // reason for this is that if an error occurs we don't actually know if
+        // the file descriptor was closed or not, and if we retried (for
+        // something like EINTR), we might close another valid file descriptor
+        // (opened after we closed ours.
+        let _ = unsafe { sys_close(self.fd) };
+    }
+}
diff --git a/src/libstd/sys/hermit/fs.rs b/src/libstd/sys/hermit/fs.rs
new file mode 100644
index 00000000000..2cec93e3e5e
--- /dev/null
+++ b/src/libstd/sys/hermit/fs.rs
@@ -0,0 +1,389 @@
+use crate::ffi::{OsString, CString, CStr};
+use crate::fmt;
+use crate::io::{self, Error, ErrorKind};
+use crate::hash::{Hash, Hasher};
+use crate::io::{SeekFrom, IoSlice, IoSliceMut};
+use crate::path::{Path, PathBuf};
+use crate::sys::time::SystemTime;
+use crate::sys::{unsupported, Void};
+use crate::sys::hermit::fd::FileDesc;
+use crate::sys::cvt;
+use crate::sys_common::os_str_bytes::OsStrExt;
+
+pub use crate::sys_common::fs::copy;
+//pub use crate::sys_common::fs::remove_dir_all;
+
+extern {
+    fn sys_open(name: *const i8, flags: i32, mode: i32) -> i32;
+    fn sys_unlink(name: *const i8) -> i32;
+}
+
+fn cstr(path: &Path) -> io::Result<CString> {
+    Ok(CString::new(path.as_os_str().as_bytes())?)
+}
+//const O_ACCMODE: i32 = 00000003;
+const O_RDONLY: i32 = 00000000;
+const O_WRONLY: i32 = 00000001;
+const O_RDWR: i32 = 00000002;
+const O_CREAT: i32 = 00000100;
+const O_EXCL: i32 = 00000200;
+const O_TRUNC: i32 = 00001000;
+const O_APPEND: i32 = 00002000;
+
+#[derive(Debug)]
+pub struct File(FileDesc);
+
+pub struct FileAttr(Void);
+
+pub struct ReadDir(Void);
+
+pub struct DirEntry(Void);
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {
+    // generic
+    read: bool,
+    write: bool,
+    append: bool,
+    truncate: bool,
+    create: bool,
+    create_new: bool,
+    // system-specific
+    mode: i32
+}
+
+pub struct FilePermissions(Void);
+
+pub struct FileType(Void);
+
+#[derive(Debug)]
+pub struct DirBuilder { }
+
+impl FileAttr {
+    pub fn size(&self) -> u64 {
+        match self.0 {}
+    }
+
+    pub fn perm(&self) -> FilePermissions {
+        match self.0 {}
+    }
+
+    pub fn file_type(&self) -> FileType {
+        match self.0 {}
+    }
+
+    pub fn modified(&self) -> io::Result<SystemTime> {
+        match self.0 {}
+    }
+
+    pub fn accessed(&self) -> io::Result<SystemTime> {
+        match self.0 {}
+    }
+
+    pub fn created(&self) -> io::Result<SystemTime> {
+        match self.0 {}
+    }
+}
+
+impl Clone for FileAttr {
+    fn clone(&self) -> FileAttr {
+        match self.0 {}
+    }
+}
+
+impl FilePermissions {
+    pub fn readonly(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn set_readonly(&mut self, _readonly: bool) {
+        match self.0 {}
+    }
+}
+
+impl Clone for FilePermissions {
+    fn clone(&self) -> FilePermissions {
+        match self.0 {}
+    }
+}
+
+impl PartialEq for FilePermissions {
+    fn eq(&self, _other: &FilePermissions) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Eq for FilePermissions {
+}
+
+impl fmt::Debug for FilePermissions {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl FileType {
+    pub fn is_dir(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn is_file(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn is_symlink(&self) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Clone for FileType {
+    fn clone(&self) -> FileType {
+        match self.0 {}
+    }
+}
+
+impl Copy for FileType {}
+
+impl PartialEq for FileType {
+    fn eq(&self, _other: &FileType) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Eq for FileType {
+}
+
+impl Hash for FileType {
+    fn hash<H: Hasher>(&self, _h: &mut H) {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for FileType {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for ReadDir {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl Iterator for ReadDir {
+    type Item = io::Result<DirEntry>;
+
+    fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        match self.0 {}
+    }
+}
+
+impl DirEntry {
+    pub fn path(&self) -> PathBuf {
+        match self.0 {}
+    }
+
+    pub fn file_name(&self) -> OsString {
+        match self.0 {}
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        match self.0 {}
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        match self.0 {}
+    }
+}
+
+impl OpenOptions {
+    pub fn new() -> OpenOptions {
+        OpenOptions {
+            // generic
+            read: false,
+            write: false,
+            append: false,
+            truncate: false,
+            create: false,
+            create_new: false,
+            // system-specific
+            mode: 0x777
+        }
+    }
+
+    pub fn read(&mut self, read: bool) { self.read = read; }
+    pub fn write(&mut self, write: bool) { self.write = write; }
+    pub fn append(&mut self, append: bool) { self.append = append; }
+    pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
+    pub fn create(&mut self, create: bool) { self.create = create; }
+    pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
+
+    fn get_access_mode(&self) -> io::Result<i32> {
+        match (self.read, self.write, self.append) {
+            (true,  false, false) => Ok(O_RDONLY),
+            (false, true,  false) => Ok(O_WRONLY),
+            (true,  true,  false) => Ok(O_RDWR),
+            (false, _,     true)  => Ok(O_WRONLY | O_APPEND),
+            (true,  _,     true)  => Ok(O_RDWR | O_APPEND),
+            (false, false, false) => Err(io::Error::new(ErrorKind::InvalidInput, "invalid access mode")),
+        }
+    }
+
+    fn get_creation_mode(&self) -> io::Result<i32> {
+        match (self.write, self.append) {
+            (true, false) => {}
+            (false, false) =>
+                if self.truncate || self.create || self.create_new {
+                    return Err(io::Error::new(ErrorKind::InvalidInput, "invalid creation mode"));
+                },
+            (_, true) =>
+                if self.truncate && !self.create_new {
+                    return Err(io::Error::new(ErrorKind::InvalidInput, "invalid creation mode"));
+                },
+        }
+
+        Ok(match (self.create, self.truncate, self.create_new) {
+                (false, false, false) => 0,
+                (true,  false, false) => O_CREAT,
+                (false, true,  false) => O_TRUNC,
+                (true,  true,  false) => O_CREAT | O_TRUNC,
+                (_,      _,    true)  => O_CREAT | O_EXCL,
+           })
+    }
+}
+
+impl File {
+    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+        let path = cstr(path)?;
+        File::open_c(&path, opts)
+    }
+
+    pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
+        let mut flags = opts.get_access_mode()?;
+        flags = flags | opts.get_creation_mode()?;
+
+        let mode;
+        if flags & O_CREAT == O_CREAT {
+            mode = opts.mode;
+        } else {
+            mode = 0;
+        }
+
+        let fd = unsafe { cvt(sys_open(path.as_ptr(), flags, mode))? };
+        Ok(File(FileDesc::new(fd as i32)))
+    }
+
+    pub fn file_attr(&self) -> io::Result<FileAttr> {
+        Err(Error::from_raw_os_error(22))
+    }
+
+    pub fn fsync(&self) -> io::Result<()> {
+        Err(Error::from_raw_os_error(22))
+    }
+
+    pub fn datasync(&self) -> io::Result<()> {
+        self.fsync()
+    }
+
+    pub fn truncate(&self, _size: u64) -> io::Result<()> {
+        Err(Error::from_raw_os_error(22))
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        crate::io::default_read_vectored(|buf| self.read(buf), bufs)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        crate::io::default_write_vectored(|buf| self.write(buf), bufs)
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        Ok(())
+    }
+
+    pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
+        Err(Error::from_raw_os_error(22))
+    }
+
+    pub fn duplicate(&self) -> io::Result<File> {
+        Err(Error::from_raw_os_error(22))
+    }
+
+    pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+        Err(Error::from_raw_os_error(22))
+    }
+
+    pub fn diverge(&self) -> ! {
+        loop {}
+    }
+}
+
+impl DirBuilder {
+    pub fn new() -> DirBuilder {
+        DirBuilder { }
+    }
+
+    pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
+        unsupported()
+    }
+}
+
+pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
+    unsupported()
+}
+
+pub fn unlink(path: &Path) -> io::Result<()> {
+    let name = cstr(path)?;
+    let _ = unsafe { cvt(sys_unlink(name.as_ptr()))? };
+    Ok(())
+}
+
+pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
+    match perm.0 {}
+}
+
+pub fn rmdir(_p: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
+    //unsupported()
+    Ok(())
+}
+
+pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub fn stat(_p: &Path) -> io::Result<FileAttr> {
+    unsupported()
+}
+
+pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
+    unsupported()
+}
+
+pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
diff --git a/src/libstd/sys/hermit/io.rs b/src/libstd/sys/hermit/io.rs
new file mode 100644
index 00000000000..976e122463d
--- /dev/null
+++ b/src/libstd/sys/hermit/io.rs
@@ -0,0 +1,46 @@
+use crate::mem;
+
+pub struct IoSlice<'a>(&'a [u8]);
+
+impl<'a> IoSlice<'a> {
+    #[inline]
+    pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
+        IoSlice(buf)
+    }
+
+    #[inline]
+    pub fn advance(&mut self, n: usize) {
+        self.0 = &self.0[n..]
+    }
+
+    #[inline]
+    pub fn as_slice(&self) -> &[u8] {
+        self.0
+    }
+}
+
+pub struct IoSliceMut<'a>(&'a mut [u8]);
+
+impl<'a> IoSliceMut<'a> {
+    #[inline]
+    pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
+        IoSliceMut(buf)
+    }
+
+    #[inline]
+    pub fn advance(&mut self, n: usize) {
+        let slice = mem::replace(&mut self.0, &mut []);
+        let (_, remaining) = slice.split_at_mut(n);
+        self.0 = remaining;
+    }
+
+    #[inline]
+    pub fn as_slice(&self) -> &[u8] {
+        self.0
+    }
+
+    #[inline]
+    pub fn as_mut_slice(&mut self) -> &mut [u8] {
+        self.0
+    }
+}
diff --git a/src/libstd/sys/hermit/memchr.rs b/src/libstd/sys/hermit/memchr.rs
new file mode 100644
index 00000000000..9967482197e
--- /dev/null
+++ b/src/libstd/sys/hermit/memchr.rs
@@ -0,0 +1 @@
+pub use core::slice::memchr::{memchr, memrchr};
diff --git a/src/libstd/sys/hermit/mod.rs b/src/libstd/sys/hermit/mod.rs
new file mode 100644
index 00000000000..c413b3e5323
--- /dev/null
+++ b/src/libstd/sys/hermit/mod.rs
@@ -0,0 +1,148 @@
+//! System bindings for HermitCore
+//!
+//! This module contains the facade (aka platform-specific) implementations of
+//! OS level functionality for HermitCore.
+//!
+//! This is all super highly experimental and not actually intended for
+//! wide/production use yet, it's still all in the experimental category. This
+//! will likely change over time.
+//!
+//! Currently all functions here are basically stubs that immediately return
+//! errors. The hope is that with a portability lint we can turn actually just
+//! remove all this and just omit parts of the standard library if we're
+//! compiling for wasm. That way it's a compile time error for something that's
+//! guaranteed to be a runtime error!
+
+use crate::os::raw::c_char;
+use crate::intrinsics;
+
+pub mod alloc;
+pub mod args;
+pub mod condvar;
+pub mod stdio;
+pub mod memchr;
+pub mod io;
+pub mod mutex;
+pub mod rwlock;
+pub mod os;
+pub mod cmath;
+pub mod thread;
+pub mod env;
+pub mod fs;
+pub mod fd;
+pub mod net;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod stack_overflow;
+pub mod time;
+pub mod thread_local;
+pub mod fast_thread_local;
+
+pub use crate::sys_common::os_str_bytes as os_str;
+use crate::io::ErrorKind;
+
+pub fn unsupported<T>() -> crate::io::Result<T> {
+    Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> crate::io::Error {
+    crate::io::Error::new(crate::io::ErrorKind::Other,
+           "operation not supported on HermitCore yet")
+}
+
+// This enum is used as the storage for a bunch of types which can't actually
+// exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
+pub unsafe fn strlen(start: *const c_char) -> usize {
+    let mut str = start;
+
+    while *str != 0 {
+        str = str.offset(1);
+    }
+
+    (str as usize) - (start as usize)
+}
+
+#[no_mangle]
+pub extern "C" fn floor(x: f64) -> f64 {
+    unsafe {
+        intrinsics::floorf64(x)
+    }
+}
+
+pub unsafe fn abort_internal() -> ! {
+    extern "C" {
+        fn sys_abort() ->!;
+    }
+
+    sys_abort();
+}
+
+// TODO: just a workaround to test the system
+pub fn hashmap_random_keys() -> (u64, u64) {
+    (1, 2)
+}
+
+// This function is needed by the panic runtime. The symbol is named in
+// pre-link args for the target specification, so keep that in sync.
+#[cfg(not(test))]
+#[no_mangle]
+// NB. used by both libunwind and libpanic_abort
+pub unsafe extern "C" fn __rust_abort() {
+    abort_internal();
+}
+
+#[cfg(not(test))]
+pub fn init() {
+    unsafe {
+        let _ = net::init();
+    }
+}
+
+#[cfg(not(test))]
+#[no_mangle]
+pub unsafe extern "C" fn runtime_entry(argc: i32, argv: *const *const c_char, env: *const *const c_char) -> ! {
+    extern "C" {
+        fn main(argc: isize, argv: *const *const c_char) -> i32;
+        fn sys_exit(arg: i32) ->!;
+    }
+
+    // initialize environment
+    os::init_environment(env as *const *const i8);
+
+    let result = main(argc as isize, argv);
+
+    sys_exit(result);
+}
+
+pub fn decode_error_kind(errno: i32) -> ErrorKind {
+    match errno {
+        x if x == 13 as i32 => ErrorKind::PermissionDenied,
+        x if x == 98 as i32 => ErrorKind::AddrInUse,
+        x if x == 99 as i32 => ErrorKind::AddrNotAvailable,
+        x if x == 11 as i32 => ErrorKind::WouldBlock,
+        x if x == 103 as i32 => ErrorKind::ConnectionAborted,
+        x if x == 111 as i32 => ErrorKind::ConnectionRefused,
+        x if x == 104 as i32 => ErrorKind::ConnectionReset,
+        x if x == 17 as i32 => ErrorKind::AlreadyExists,
+        x if x == 4 as i32 => ErrorKind::Interrupted,
+        x if x == 22 as i32 => ErrorKind::InvalidInput,
+        x if x == 2 as i32 => ErrorKind::NotFound,
+        x if x == 107 as i32 => ErrorKind::NotConnected,
+        x if x == 1 as i32 => ErrorKind::PermissionDenied,
+        x if x == 32 as i32 => ErrorKind::BrokenPipe,
+        x if x == 110 as i32 => ErrorKind::TimedOut,
+        _ => ErrorKind::Other,
+    }
+}
+
+pub fn cvt(result: i32) -> crate::io::Result<usize> {
+    if result < 0 {
+        Err(crate::io::Error::from_raw_os_error(-result))
+    } else {
+        Ok(result as usize)
+    }
+}
diff --git a/src/libstd/sys/hermit/mutex.rs b/src/libstd/sys/hermit/mutex.rs
new file mode 100644
index 00000000000..f119c66a6dc
--- /dev/null
+++ b/src/libstd/sys/hermit/mutex.rs
@@ -0,0 +1,88 @@
+use crate::ptr;
+use crate::ffi::c_void;
+
+extern "C" {
+    fn sys_sem_init(sem: *mut *const c_void, value: u32) -> i32;
+    fn sys_sem_destroy(sem: *const c_void) -> i32;
+    fn sys_sem_post(sem: *const c_void) -> i32;
+    fn sys_sem_trywait(sem: *const c_void) -> i32;
+    fn sys_sem_timedwait(sem: *const c_void, ms: u32) -> i32;
+    fn sys_recmutex_init(recmutex: *mut *const c_void) -> i32;
+    fn sys_recmutex_destroy(recmutex: *const c_void) -> i32;
+    fn sys_recmutex_lock(recmutex: *const c_void) -> i32;
+    fn sys_recmutex_unlock(recmutex: *const c_void) -> i32;
+}
+
+pub struct Mutex {
+    inner: *const c_void
+}
+
+unsafe impl Send for Mutex {}
+unsafe impl Sync for Mutex {}
+
+impl Mutex {
+    pub const fn new() -> Mutex {
+        Mutex { inner: ptr::null() }
+    }
+
+    #[inline]
+    pub unsafe fn init(&mut self) {
+        let _ = sys_sem_init(&mut self.inner as *mut *const c_void, 1);
+    }
+
+    #[inline]
+    pub unsafe fn lock(&self) {
+        let _ = sys_sem_timedwait(self.inner, 0);
+    }
+
+    #[inline]
+    pub unsafe fn unlock(&self) {
+        let _ = sys_sem_post(self.inner);
+    }
+
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        let result = sys_sem_trywait(self.inner);
+        result == 0
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        let _ = sys_sem_destroy(self.inner);
+    }
+}
+
+pub struct ReentrantMutex {
+    inner: *const c_void
+}
+
+impl ReentrantMutex {
+    pub unsafe fn uninitialized() -> ReentrantMutex {
+        ReentrantMutex { inner: ptr::null() }
+    }
+
+    #[inline]
+    pub unsafe fn init(&mut self) {
+        let _ = sys_recmutex_init(&mut self.inner as *mut *const c_void);
+    }
+
+    #[inline]
+    pub unsafe fn lock(&self) {
+        let _ = sys_recmutex_lock(self.inner);
+    }
+
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        true
+    }
+
+    #[inline]
+    pub unsafe fn unlock(&self) {
+        let _ = sys_recmutex_unlock(self.inner);
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        let _ = sys_recmutex_destroy(self.inner);
+    }
+}
diff --git a/src/libstd/sys/hermit/net.rs b/src/libstd/sys/hermit/net.rs
new file mode 100644
index 00000000000..5b7ff642271
--- /dev/null
+++ b/src/libstd/sys/hermit/net.rs
@@ -0,0 +1,364 @@
+use crate::fmt;
+use crate::convert::TryFrom;
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
+use crate::str;
+use crate::sys::{unsupported, Void};
+use crate::time::Duration;
+
+//// Iinitializes HermitCore's network stack
+pub unsafe fn init() -> io::Result<()> {
+    Ok(())
+}
+
+pub struct TcpStream(Void);
+
+impl TcpStream {
+    pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+        unsupported()
+    }
+
+    pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+        unsupported()
+    }
+
+    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpStream> {
+        match self.0 {}
+    }
+
+    pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        match self.0 {}
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for TcpStream {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct TcpListener(Void);
+
+impl TcpListener {
+    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+        unsupported()
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpListener> {
+        match self.0 {}
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn only_v6(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        match self.0 {}
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for TcpListener {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct UdpSocket(Void);
+
+impl UdpSocket {
+    pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+        unsupported()
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        match self.0 {}
+    }
+
+    pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        match self.0 {}
+    }
+
+    pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        match self.0 {}
+    }
+
+    pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn duplicate(&self) -> io::Result<UdpSocket> {
+        match self.0 {}
+    }
+
+    pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+        match self.0 {}
+    }
+
+    pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn broadcast(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+        match self.0 {}
+    }
+
+    pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+                         -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+                         -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+                          -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+                          -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn ttl(&self) -> io::Result<u32> {
+        match self.0 {}
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        match self.0 {}
+    }
+
+    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+        match self.0 {}
+    }
+}
+
+impl fmt::Debug for UdpSocket {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+pub struct LookupHost(Void);
+
+impl LookupHost {
+    pub fn port(&self) -> u16 {
+        match self.0 {}
+    }
+}
+
+impl Iterator for LookupHost {
+    type Item = SocketAddr;
+    fn next(&mut self) -> Option<SocketAddr> {
+        match self.0 {}
+    }
+}
+
+impl TryFrom<&str> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(_v: &str) -> io::Result<LookupHost> {
+        unsupported()
+    }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+    type Error = io::Error;
+
+    fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+        unsupported()
+    }
+}
+
+#[allow(nonstandard_style)]
+pub mod netc {
+    pub const AF_INET: u8 = 0;
+    pub const AF_INET6: u8 = 1;
+    pub type sa_family_t = u8;
+
+    #[derive(Copy, Clone)]
+    pub struct in_addr {
+        pub s_addr: u32,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr_in {
+        pub sin_family: sa_family_t,
+        pub sin_port: u16,
+        pub sin_addr: in_addr,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct in6_addr {
+        pub s6_addr: [u8; 16],
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr_in6 {
+        pub sin6_family: sa_family_t,
+        pub sin6_port: u16,
+        pub sin6_addr: in6_addr,
+        pub sin6_flowinfo: u32,
+        pub sin6_scope_id: u32,
+    }
+
+    #[derive(Copy, Clone)]
+    pub struct sockaddr {
+    }
+
+    pub type socklen_t = usize;
+}
diff --git a/src/libstd/sys/hermit/os.rs b/src/libstd/sys/hermit/os.rs
new file mode 100644
index 00000000000..cdac1c74dcb
--- /dev/null
+++ b/src/libstd/sys/hermit/os.rs
@@ -0,0 +1,178 @@
+use crate::error::Error as StdError;
+use crate::ffi::{CStr, OsString, OsStr};
+use crate::fmt;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::memchr;
+use crate::path::{self, PathBuf};
+use crate::ptr;
+use crate::str;
+use crate::sys::{unsupported, Void};
+use crate::collections::HashMap;
+use crate::vec;
+use crate::sync::Mutex;
+use crate::sys_common::os_str_bytes::*;
+
+extern "C" {
+    fn sys_getpid() -> u32;
+    fn sys_exit(arg: i32) ->!;
+}
+
+pub fn errno() -> i32 {
+    0
+}
+
+pub fn error_string(_errno: i32) -> String {
+    "operation successful".to_string()
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub struct SplitPaths<'a>(&'a Void);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+    panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = PathBuf;
+    fn next(&mut self) -> Option<PathBuf> {
+        match *self.0 {}
+    }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+    where I: Iterator<Item=T>, T: AsRef<OsStr>
+{
+    Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "not supported on hermit yet".fmt(f)
+    }
+}
+
+impl StdError for JoinPathsError {
+    fn description(&self) -> &str {
+        "not supported on hermit yet"
+    }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+static mut ENV: Option<Mutex<HashMap<OsString, OsString>>> = None;
+
+pub fn init_environment(env: *const *const i8) {
+    unsafe {
+        ENV = Some(Mutex::new(HashMap::new()));
+
+        let mut guard = ENV.as_ref().unwrap().lock().unwrap();
+        let mut environ = env;
+        while environ != ptr::null() && *environ != ptr::null() {
+            if let Some((key,value)) = parse(CStr::from_ptr(*environ).to_bytes()) {
+                guard.insert(key, value);
+            }
+            environ = environ.offset(1);
+        }
+    }
+
+    fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
+        // Strategy (copied from glibc): Variable name and value are separated
+        // by an ASCII equals sign '='. Since a variable name must not be
+        // empty, allow variable names starting with an equals sign. Skip all
+        // malformed lines.
+        if input.is_empty() {
+            return None;
+        }
+        let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
+        pos.map(|p| (
+            OsStringExt::from_vec(input[..p].to_vec()),
+            OsStringExt::from_vec(input[p+1..].to_vec()),
+        ))
+    }
+}
+
+pub struct Env {
+    iter: vec::IntoIter<(OsString, OsString)>,
+    _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Iterator for Env {
+    type Item = (OsString, OsString);
+    fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+/// Returns a vector of (variable, value) byte-vector pairs for all the
+/// environment variables of the current process.
+pub fn env() -> Env {
+   unsafe {
+        let guard = ENV.as_ref().unwrap().lock().unwrap();
+        let mut result = Vec::new();
+
+        for (key, value) in guard.iter() {
+            result.push((key.clone(), value.clone()));
+        }
+
+        return Env {
+            iter: result.into_iter(),
+            _dont_send_or_sync_me: PhantomData,
+        }
+    }
+}
+
+pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
+    unsafe {
+        match ENV.as_ref().unwrap().lock().unwrap().get_mut(k) {
+            Some(value) => { Ok(Some(value.clone())) },
+            None => { Ok(None) },
+        }
+    }
+}
+
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+    unsafe {
+        let (k, v) = (k.to_owned(), v.to_owned());
+        ENV.as_ref().unwrap().lock().unwrap().insert(k, v);
+    }
+    Ok(())
+}
+
+pub fn unsetenv(k: &OsStr) -> io::Result<()> {
+    unsafe {
+        ENV.as_ref().unwrap().lock().unwrap().remove(k);
+    }
+    Ok(())
+}
+
+pub fn temp_dir() -> PathBuf {
+    panic!("no filesystem on hermit")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+    None
+}
+
+pub fn exit(code: i32) -> ! {
+    unsafe {
+        sys_exit(code);
+    }
+}
+
+pub fn getpid() -> u32 {
+    unsafe {
+        sys_getpid()
+    }
+}
diff --git a/src/libstd/sys/hermit/path.rs b/src/libstd/sys/hermit/path.rs
new file mode 100644
index 00000000000..7a183956107
--- /dev/null
+++ b/src/libstd/sys/hermit/path.rs
@@ -0,0 +1,19 @@
+use crate::path::Prefix;
+use crate::ffi::OsStr;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+    b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+    b == b'/'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
+    None
+}
+
+pub const MAIN_SEP_STR: &str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/hermit/pipe.rs b/src/libstd/sys/hermit/pipe.rs
new file mode 100644
index 00000000000..9f07f054362
--- /dev/null
+++ b/src/libstd/sys/hermit/pipe.rs
@@ -0,0 +1,33 @@
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::sys::Void;
+
+pub struct AnonPipe(Void);
+
+impl AnonPipe {
+    pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        match self.0 {}
+    }
+
+    pub fn diverge(&self) -> ! {
+        match self.0 {}
+    }
+}
+
+pub fn read2(p1: AnonPipe,
+             _v1: &mut Vec<u8>,
+             _p2: AnonPipe,
+             _v2: &mut Vec<u8>) -> io::Result<()> {
+    match p1.0 {}
+}
diff --git a/src/libstd/sys/hermit/process.rs b/src/libstd/sys/hermit/process.rs
new file mode 100644
index 00000000000..edf933d10e0
--- /dev/null
+++ b/src/libstd/sys/hermit/process.rs
@@ -0,0 +1,154 @@
+use crate::ffi::OsStr;
+use crate::fmt;
+use crate::io;
+use crate::sys::fs::File;
+use crate::sys::pipe::AnonPipe;
+use crate::sys::{unsupported, Void};
+use crate::sys_common::process::CommandEnv;
+
+pub use crate::ffi::OsString as EnvKey;
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+    env: CommandEnv,
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+    pub stdin: Option<AnonPipe>,
+    pub stdout: Option<AnonPipe>,
+    pub stderr: Option<AnonPipe>,
+}
+
+pub enum Stdio {
+    Inherit,
+    Null,
+    MakePipe,
+}
+
+impl Command {
+    pub fn new(_program: &OsStr) -> Command {
+        Command {
+            env: Default::default()
+        }
+    }
+
+    pub fn arg(&mut self, _arg: &OsStr) {
+    }
+
+    pub fn env_mut(&mut self) -> &mut CommandEnv {
+        &mut self.env
+    }
+
+    pub fn cwd(&mut self, _dir: &OsStr) {
+    }
+
+    pub fn stdin(&mut self, _stdin: Stdio) {
+    }
+
+    pub fn stdout(&mut self, _stdout: Stdio) {
+    }
+
+    pub fn stderr(&mut self, _stderr: Stdio) {
+    }
+
+    pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool)
+        -> io::Result<(Process, StdioPipes)> {
+        unsupported()
+    }
+}
+
+impl From<AnonPipe> for Stdio {
+    fn from(pipe: AnonPipe) -> Stdio {
+        pipe.diverge()
+    }
+}
+
+impl From<File> for Stdio {
+    fn from(file: File) -> Stdio {
+        file.diverge()
+    }
+}
+
+impl fmt::Debug for Command {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        Ok(())
+    }
+}
+
+pub struct ExitStatus(Void);
+
+impl ExitStatus {
+    pub fn success(&self) -> bool {
+        match self.0 {}
+    }
+
+    pub fn code(&self) -> Option<i32> {
+        match self.0 {}
+    }
+}
+
+impl Clone for ExitStatus {
+    fn clone(&self) -> ExitStatus {
+        match self.0 {}
+    }
+}
+
+impl Copy for ExitStatus {}
+
+impl PartialEq for ExitStatus {
+    fn eq(&self, _other: &ExitStatus) -> bool {
+        match self.0 {}
+    }
+}
+
+impl Eq for ExitStatus {
+}
+
+impl fmt::Debug for ExitStatus {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+impl fmt::Display for ExitStatus {
+    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.0 {}
+    }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(bool);
+
+impl ExitCode {
+    pub const SUCCESS: ExitCode = ExitCode(false);
+    pub const FAILURE: ExitCode = ExitCode(true);
+
+    pub fn as_i32(&self) -> i32 {
+        self.0 as i32
+    }
+}
+
+pub struct Process(Void);
+
+impl Process {
+    pub fn id(&self) -> u32 {
+        match self.0 {}
+    }
+
+    pub fn kill(&mut self) -> io::Result<()> {
+        match self.0 {}
+    }
+
+    pub fn wait(&mut self) -> io::Result<ExitStatus> {
+        match self.0 {}
+    }
+
+    pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+        match self.0 {}
+    }
+}
diff --git a/src/libstd/sys/hermit/rwlock.rs b/src/libstd/sys/hermit/rwlock.rs
new file mode 100644
index 00000000000..990e7551114
--- /dev/null
+++ b/src/libstd/sys/hermit/rwlock.rs
@@ -0,0 +1,51 @@
+use super::mutex::Mutex;
+
+pub struct RWLock {
+    mutex: Mutex
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+impl RWLock {
+    pub const fn new() -> RWLock {
+        RWLock {
+            mutex: Mutex::new()
+        }
+    }
+
+    #[inline]
+    pub unsafe fn read(&self) {
+        self.mutex.lock();
+    }
+
+    #[inline]
+    pub unsafe fn try_read(&self) -> bool {
+        self.mutex.try_lock()
+    }
+
+    #[inline]
+    pub unsafe fn write(&self) {
+        self.mutex.lock();
+    }
+
+    #[inline]
+    pub unsafe fn try_write(&self) -> bool {
+        self.mutex.try_lock()
+    }
+
+    #[inline]
+    pub unsafe fn read_unlock(&self) {
+        self.mutex.unlock();
+    }
+
+    #[inline]
+    pub unsafe fn write_unlock(&self) {
+        self.mutex.unlock();
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        self.mutex.destroy();
+    }
+}
diff --git a/src/libstd/sys/hermit/stack_overflow.rs b/src/libstd/sys/hermit/stack_overflow.rs
new file mode 100644
index 00000000000..b339e433e77
--- /dev/null
+++ b/src/libstd/sys/hermit/stack_overflow.rs
@@ -0,0 +1,15 @@
+pub struct Handler;
+
+impl Handler {
+    pub unsafe fn new() -> Handler {
+        Handler
+    }
+}
+
+#[inline]
+pub unsafe fn init() {
+}
+
+#[inline]
+pub unsafe fn cleanup() {
+}
diff --git a/src/libstd/sys/hermit/stdio.rs b/src/libstd/sys/hermit/stdio.rs
new file mode 100644
index 00000000000..07be3b6fdd3
--- /dev/null
+++ b/src/libstd/sys/hermit/stdio.rs
@@ -0,0 +1,122 @@
+use crate::io;
+use crate::io::{IoSlice, IoSliceMut};
+
+extern "C" {
+    fn sys_write(fd: i32, buf: *const u8, len: usize) -> isize;
+}
+
+pub struct Stdin;
+pub struct Stdout;
+pub struct Stderr;
+
+impl Stdin {
+    pub fn new() -> io::Result<Stdin> {
+        Ok(Stdin)
+    }
+
+    pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+        self.read_vectored(&mut [IoSliceMut::new(data)])
+    }
+
+    pub fn read_vectored(&self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        //ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) })
+        //    .read(data)
+        Ok(0)
+    }
+
+}
+
+impl Stdout {
+    pub fn new() -> io::Result<Stdout> {
+        Ok(Stdout)
+    }
+
+    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+        let len;
+
+        unsafe {
+            len = sys_write(1, data.as_ptr() as *const u8, data.len())
+        }
+
+        if len < 0 {
+            Err(io::Error::new(io::ErrorKind::Other, "Stdout is not able to print"))
+        } else {
+            Ok(len as usize)
+        }
+    }
+
+    pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+        let len;
+
+        unsafe {
+            len = sys_write(1, data.as_ptr() as *const u8, data.len())
+        }
+
+        if len < 0 {
+            Err(io::Error::new(io::ErrorKind::Other, "Stdout is not able to print"))
+        } else {
+            Ok(len as usize)
+        }
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl Stderr {
+    pub fn new() -> io::Result<Stderr> {
+        Ok(Stderr)
+    }
+
+    pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+        let len;
+
+        unsafe {
+            len = sys_write(2, data.as_ptr() as *const u8, data.len())
+        }
+
+        if len < 0 {
+            Err(io::Error::new(io::ErrorKind::Other, "Stderr is not able to print"))
+        } else {
+            Ok(len as usize)
+        }
+    }
+
+    pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> {
+        let len;
+
+        unsafe {
+            len = sys_write(2, data.as_ptr() as *const u8, data.len())
+        }
+
+        if len < 0 {
+            Err(io::Error::new(io::ErrorKind::Other, "Stderr is not able to print"))
+        } else {
+            Ok(len as usize)
+        }
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl io::Write for Stderr {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        (&*self).write(data)
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        (&*self).flush()
+    }
+}
+
+pub const STDIN_BUF_SIZE: usize = 0;
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+    true
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+    Stderr::new().ok()
+}
diff --git a/src/libstd/sys/hermit/thread.rs b/src/libstd/sys/hermit/thread.rs
new file mode 100644
index 00000000000..cb5ed2963b1
--- /dev/null
+++ b/src/libstd/sys/hermit/thread.rs
@@ -0,0 +1,121 @@
+#![allow(dead_code)]
+
+use crate::ffi::CStr;
+use crate::io;
+use crate::time::Duration;
+use crate::mem;
+use crate::fmt;
+use core::u32;
+
+use crate::sys_common::thread::*;
+
+pub type Tid = u32;
+
+/// Priority of a task
+#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
+pub struct Priority(u8);
+
+impl Priority {
+    pub const fn into(self) -> u8 {
+        self.0
+    }
+
+    pub const fn from(x: u8) -> Self {
+        Priority(x)
+    }
+}
+
+impl fmt::Display for Priority {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.0)
+    }
+}
+
+pub const NORMAL_PRIO: Priority = Priority::from(2);
+
+extern "C" {
+    fn sys_usleep(usecs: u64);
+    fn sys_spawn(id: *mut Tid, func: extern "C" fn(usize), arg: usize, prio: u8, core_id: isize) -> i32;
+    fn sys_join(id: Tid) -> i32;
+    fn sys_yield();
+}
+
+pub struct Thread {
+    tid: Tid
+}
+
+unsafe impl Send for Thread {}
+unsafe impl Sync for Thread {}
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 262144;
+
+impl Thread {
+    pub unsafe fn new_with_coreid(_stack: usize, p: Box<dyn FnOnce()>, core_id: isize)
+        -> io::Result<Thread>
+    {
+        let p = box p;
+        let mut tid: Tid = u32::MAX;
+        let ret = sys_spawn(&mut tid as *mut Tid, thread_start, &*p as *const _ as *const u8 as usize,
+                            Priority::into(NORMAL_PRIO), core_id);
+
+        return if ret == 0 {
+            mem::forget(p); // ownership passed to pthread_create
+            Ok(Thread { tid: tid })
+        } else {
+            Err(io::Error::new(io::ErrorKind::Other, "Unable to create thread!"))
+        };
+
+        extern fn thread_start(main: usize) {
+            unsafe {
+                start_thread(main as *mut u8);
+            }
+        }
+    }
+
+    pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>)
+        -> io::Result<Thread>
+    {
+        Thread::new_with_coreid(stack, p, -1 /* = no specific core */)
+    }
+
+    #[inline]
+    pub fn yield_now() {
+        unsafe {
+            sys_yield();
+        }
+    }
+
+    #[inline]
+    pub fn set_name(_name: &CStr) {
+        // nope
+    }
+
+    #[inline]
+    pub fn sleep(dur: Duration) {
+        unsafe {
+            sys_usleep(dur.as_micros() as u64);
+        }
+    }
+
+    pub fn join(self) {
+        unsafe {
+            let _ = sys_join(self.tid);
+        }
+    }
+
+    #[inline]
+    pub fn id(&self) -> Tid { self.tid }
+
+    #[inline]
+    pub fn into_id(self) -> Tid {
+        let id = self.tid;
+        mem::forget(self);
+        id
+    }
+}
+
+pub mod guard {
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> { None }
+    pub unsafe fn init() -> Option<Guard> { None }
+}
diff --git a/src/libstd/sys/hermit/thread_local.rs b/src/libstd/sys/hermit/thread_local.rs
new file mode 100644
index 00000000000..4bc8c4d5883
--- /dev/null
+++ b/src/libstd/sys/hermit/thread_local.rs
@@ -0,0 +1,61 @@
+#![allow(dead_code)] // not used on all platforms
+
+use crate::collections::BTreeMap;
+use crate::ptr;
+use crate::sync::atomic::{AtomicUsize, Ordering};
+
+pub type Key = usize;
+
+type Dtor = unsafe extern fn(*mut u8);
+
+static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
+
+static mut KEYS: *mut BTreeMap<Key, Option<Dtor>> = ptr::null_mut();
+
+#[thread_local]
+static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut();
+
+unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> {
+    if KEYS == ptr::null_mut() {
+        KEYS = Box::into_raw(Box::new(BTreeMap::new()));
+    }
+    &mut *KEYS
+}
+
+unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> {
+    if LOCALS == ptr::null_mut() {
+        LOCALS = Box::into_raw(Box::new(BTreeMap::new()));
+    }
+    &mut *LOCALS
+}
+
+#[inline]
+pub unsafe fn create(dtor: Option<Dtor>) -> Key {
+    let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst);
+    keys().insert(key, dtor);
+    key
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+    if let Some(&entry) = locals().get(&key) {
+        entry
+    } else {
+        ptr::null_mut()
+    }
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+    locals().insert(key, value);
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+    keys().remove(&key);
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+    false
+}
diff --git a/src/libstd/sys/hermit/time.rs b/src/libstd/sys/hermit/time.rs
new file mode 100644
index 00000000000..2c8aafef0fe
--- /dev/null
+++ b/src/libstd/sys/hermit/time.rs
@@ -0,0 +1,188 @@
+#![allow(dead_code)]
+
+use crate::time::Duration;
+use crate::cmp::Ordering;
+use crate::convert::TryInto;
+use core::hash::{Hash, Hasher};
+
+const NSEC_PER_SEC: u64 = 1_000_000_000;
+const CLOCK_REALTIME: u64 = 1;
+const CLOCK_MONOTONIC: u64 = 4;
+
+extern "C" {
+    fn sys_clock_gettime(clock_id: u64, tp: *mut timespec) -> i32;
+}
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct timespec {
+    pub tv_sec: i64,
+    pub tv_nsec: i64,
+}
+
+#[derive(Copy, Clone, Debug)]
+struct Timespec {
+    t: timespec
+}
+
+impl Timespec {
+    const fn zero() -> Timespec {
+        Timespec {
+            t: timespec { tv_sec: 0, tv_nsec: 0 },
+        }
+    }
+
+    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+        if self >= other {
+            Ok(if self.t.tv_nsec >= other.t.tv_nsec {
+                Duration::new((self.t.tv_sec - other.t.tv_sec) as u64,
+                              (self.t.tv_nsec - other.t.tv_nsec) as u32)
+            } else {
+                Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64,
+                              self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
+                              other.t.tv_nsec as u32)
+            })
+        } else {
+            match other.sub_timespec(self) {
+                Ok(d) => Err(d),
+                Err(d) => Ok(d),
+            }
+        }
+    }
+
+    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
+        let mut secs = other
+            .as_secs()
+            .try_into() // <- target type would be `libc::time_t`
+            .ok()
+            .and_then(|secs| self.t.tv_sec.checked_add(secs))?;
+
+        // Nano calculations can't overflow because nanos are <1B which fit
+        // in a u32.
+        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
+        if nsec >= NSEC_PER_SEC as u32 {
+            nsec -= NSEC_PER_SEC as u32;
+            secs = secs.checked_add(1)?;
+        }
+        Some(Timespec {
+            t: timespec {
+                tv_sec: secs,
+                tv_nsec: nsec as _,
+            },
+        })
+    }
+
+    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
+        let mut secs = other
+            .as_secs()
+            .try_into() // <- target type would be `libc::time_t`
+            .ok()
+            .and_then(|secs| self.t.tv_sec.checked_sub(secs))?;
+
+        // Similar to above, nanos can't overflow.
+        let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
+        if nsec < 0 {
+            nsec += NSEC_PER_SEC as i32;
+            secs = secs.checked_sub(1)?;
+        }
+        Some(Timespec {
+            t: timespec {
+                tv_sec: secs,
+                tv_nsec: nsec as _,
+            },
+        })
+    }
+}
+
+impl PartialEq for Timespec {
+    fn eq(&self, other: &Timespec) -> bool {
+        self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
+    }
+}
+
+impl Eq for Timespec {}
+
+impl PartialOrd for Timespec {
+    fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for Timespec {
+    fn cmp(&self, other: &Timespec) -> Ordering {
+        let me = (self.t.tv_sec, self.t.tv_nsec);
+        let other = (other.t.tv_sec, other.t.tv_nsec);
+        me.cmp(&other)
+    }
+}
+
+impl Hash for Timespec {
+    fn hash<H : Hasher>(&self, state: &mut H) {
+        self.t.tv_sec.hash(state);
+        self.t.tv_nsec.hash(state);
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant {
+    t: Timespec,
+}
+
+impl Instant {
+    pub fn now() -> Instant {
+        let mut time: Timespec = Timespec::zero();
+        let _ = unsafe { sys_clock_gettime(CLOCK_MONOTONIC, &mut time.t as *mut timespec) };
+
+        Instant { t: time }
+    }
+
+    pub const fn zero() -> Instant {
+        Instant { t: Timespec::zero() }
+    }
+
+    pub fn actually_monotonic() -> bool {
+        true
+    }
+
+    pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+        self.t.sub_timespec(&other.t).ok()
+    }
+
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant { t: self.t.checked_add_duration(other)? })
+    }
+
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+        Some(Instant { t: self.t.checked_sub_duration(other)? })
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct SystemTime {
+    t: Timespec,
+}
+
+pub const UNIX_EPOCH: SystemTime = SystemTime {
+    t: Timespec::zero(),
+};
+
+impl SystemTime {
+    pub fn now() -> SystemTime {
+        let mut time: Timespec = Timespec::zero();
+        let _ = unsafe { sys_clock_gettime(CLOCK_REALTIME, &mut time.t as *mut timespec) };
+
+        SystemTime { t: time }
+    }
+
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        self.t.sub_timespec(&other.t)
+    }
+
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+        Some(SystemTime { t: self.t.checked_add_duration(other)? })
+    }
+
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+        Some(SystemTime { t: self.t.checked_sub_duration(other)? })
+    }
+}
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs
index 5a5859a6ad8..16b0539cdb9 100644
--- a/src/libstd/sys/mod.rs
+++ b/src/libstd/sys/mod.rs
@@ -35,6 +35,9 @@ cfg_if::cfg_if! {
     } else if #[cfg(target_os = "cloudabi")] {
         mod cloudabi;
         pub use self::cloudabi::*;
+    } else if #[cfg(target_os = "hermit")] {
+        mod hermit;
+        pub use self::hermit::*;
     } else if #[cfg(target_os = "wasi")] {
         mod wasi;
         pub use self::wasi::*;
@@ -60,6 +63,7 @@ cfg_if::cfg_if! {
         #[stable(feature = "rust1", since = "1.0.0")]
         pub use self::ext as unix_ext;
     } else if #[cfg(any(target_os = "cloudabi",
+                        target_os = "hermit",
                         target_arch = "wasm32",
                         all(target_vendor = "fortanix", target_env = "sgx")))] {
         // On CloudABI and wasm right now the module below doesn't compile
diff --git a/src/libstd/sys/unix/alloc.rs b/src/libstd/sys/unix/alloc.rs
index f47dc92d2de..cf4900b4894 100644
--- a/src/libstd/sys/unix/alloc.rs
+++ b/src/libstd/sys/unix/alloc.rs
@@ -53,7 +53,6 @@ unsafe impl GlobalAlloc for System {
 }
 
 #[cfg(any(target_os = "android",
-          target_os = "hermit",
           target_os = "redox",
           target_os = "solaris"))]
 #[inline]
@@ -79,7 +78,6 @@ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
 }
 
 #[cfg(not(any(target_os = "android",
-              target_os = "hermit",
               target_os = "redox",
               target_os = "solaris")))]
 #[inline]
diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs
index 288e9b5c126..82ef35ea7b5 100644
--- a/src/libstd/sys/unix/args.rs
+++ b/src/libstd/sys/unix/args.rs
@@ -56,7 +56,6 @@ impl DoubleEndedIterator for Args {
           target_os = "haiku",
           target_os = "l4re",
           target_os = "fuchsia",
-          target_os = "hermit",
           target_os = "redox"))]
 mod imp {
     use crate::os::unix::prelude::*;
diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs
index 0a93fbf8ea7..6be844ded19 100644
--- a/src/libstd/sys/unix/condvar.rs
+++ b/src/libstd/sys/unix/condvar.rs
@@ -31,7 +31,6 @@ impl Condvar {
               target_os = "ios",
               target_os = "l4re",
               target_os = "android",
-              target_os = "hermit",
               target_os = "redox"))]
     pub unsafe fn init(&mut self) {}
 
@@ -39,7 +38,6 @@ impl Condvar {
                   target_os = "ios",
                   target_os = "l4re",
                   target_os = "android",
-                  target_os = "hermit",
                   target_os = "redox")))]
     pub unsafe fn init(&mut self) {
         use crate::mem::MaybeUninit;
@@ -78,8 +76,7 @@ impl Condvar {
     // from changes made to the system time.
     #[cfg(not(any(target_os = "macos",
                   target_os = "ios",
-                  target_os = "android",
-                  target_os = "hermit")))]
+                  target_os = "android")))]
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
         use crate::mem;
 
@@ -109,7 +106,7 @@ impl Condvar {
     // This implementation is modeled after libcxx's condition_variable
     // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46
     // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367
-    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android", target_os = "hermit"))]
+    #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
     pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
         use crate::ptr;
         use crate::time::Instant;
diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs
index d724eeb8b3f..984bcfa4509 100644
--- a/src/libstd/sys/unix/env.rs
+++ b/src/libstd/sys/unix/env.rs
@@ -152,17 +152,6 @@ pub mod os {
     pub const EXE_EXTENSION: &str = "";
 }
 
-#[cfg(target_os = "hermit")]
-pub mod os {
-    pub const FAMILY: &str = "unix";
-    pub const OS: &str = "hermit";
-    pub const DLL_PREFIX: &str = "lib";
-    pub const DLL_SUFFIX: &str = ".so";
-    pub const DLL_EXTENSION: &str = "so";
-    pub const EXE_SUFFIX: &str = "";
-    pub const EXE_EXTENSION: &str = "";
-}
-
 #[cfg(target_os = "redox")]
 pub mod os {
     pub const FAMILY: &str = "unix";
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index 3b1eb86b84f..c2064fca23e 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -319,12 +319,12 @@ impl DirEntry {
         lstat(&self.path())
     }
 
-    #[cfg(any(target_os = "solaris", target_os = "haiku", target_os = "hermit"))]
+    #[cfg(any(target_os = "solaris", target_os = "haiku"))]
     pub fn file_type(&self) -> io::Result<FileType> {
         lstat(&self.path()).map(|m| m.file_type())
     }
 
-    #[cfg(not(any(target_os = "solaris", target_os = "haiku", target_os = "hermit")))]
+    #[cfg(not(any(target_os = "solaris", target_os = "haiku")))]
     pub fn file_type(&self) -> io::Result<FileType> {
         match self.entry.d_type {
             libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }),
@@ -347,7 +347,6 @@ impl DirEntry {
               target_os = "haiku",
               target_os = "l4re",
               target_os = "fuchsia",
-              target_os = "hermit",
               target_os = "redox"))]
     pub fn ino(&self) -> u64 {
         self.entry.d_ino as u64
@@ -378,8 +377,7 @@ impl DirEntry {
               target_os = "linux",
               target_os = "emscripten",
               target_os = "l4re",
-              target_os = "haiku",
-              target_os = "hermit"))]
+              target_os = "haiku"))]
     fn name_bytes(&self) -> &[u8] {
         unsafe {
             CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index b1f7aac8b4b..d0bed0f038e 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -16,7 +16,6 @@ use crate::io::ErrorKind;
 #[cfg(all(not(rustdoc), target_os = "emscripten"))] pub use crate::os::emscripten as platform;
 #[cfg(all(not(rustdoc), target_os = "fuchsia"))]   pub use crate::os::fuchsia as platform;
 #[cfg(all(not(rustdoc), target_os = "l4re"))]      pub use crate::os::linux as platform;
-#[cfg(all(not(rustdoc), target_os = "hermit"))]    pub use crate::os::hermit as platform;
 #[cfg(all(not(rustdoc), target_os = "redox"))]      pub use crate::os::redox as platform;
 
 pub use self::rand::hashmap_random_keys;
diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs
index 169bb57ef78..10cdb25999c 100644
--- a/src/libstd/sys/unix/os.rs
+++ b/src/libstd/sys/unix/os.rs
@@ -43,7 +43,6 @@ extern {
     #[cfg_attr(any(target_os = "netbsd",
                    target_os = "openbsd",
                    target_os = "android",
-                   target_os = "hermit",
                    target_os = "redox",
                    target_env = "newlib"),
                link_name = "__errno")]
@@ -394,7 +393,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
     crate::fs::read_to_string("sys:exe").map(PathBuf::from)
 }
 
-#[cfg(any(target_os = "fuchsia", target_os = "l4re", target_os = "hermit"))]
+#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
 pub fn current_exe() -> io::Result<PathBuf> {
     use crate::io::ErrorKind;
     Err(io::Error::new(ErrorKind::Other, "Not yet implemented!"))
diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs
index 988881e3596..72b0ac493da 100644
--- a/src/libstd/sys/unix/thread.rs
+++ b/src/libstd/sys/unix/thread.rs
@@ -140,7 +140,6 @@ impl Thread {
               target_os = "haiku",
               target_os = "l4re",
               target_os = "emscripten",
-              target_os = "hermit",
               target_os = "redox"))]
     pub fn set_name(_name: &CStr) {
         // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name.
diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs
index fd6796ad22c..a9122defa55 100644
--- a/src/libstd/sys/unix/time.rs
+++ b/src/libstd/sys/unix/time.rs
@@ -371,9 +371,9 @@ mod inner {
         }
     }
 
-    #[cfg(not(any(target_os = "dragonfly", target_os = "hermit")))]
+    #[cfg(not(target_os = "dragonfly"))]
     pub type clock_t = libc::c_int;
-    #[cfg(any(target_os = "dragonfly", target_os = "hermit"))]
+    #[cfg(target_os = "dragonfly")]
     pub type clock_t = libc::c_ulong;
 
     fn now(clock: clock_t) -> Timespec {
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
index cba3eca5386..7a0bcd03d75 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -49,6 +49,7 @@ pub mod mutex;
           unix,
           target_os = "redox",
           target_os = "cloudabi",
+          target_os = "hermit",
           target_arch = "wasm32",
           all(target_vendor = "fortanix", target_env = "sgx")))]
 pub mod os_str_bytes;
@@ -67,6 +68,7 @@ pub mod fs;
 cfg_if::cfg_if! {
     if #[cfg(any(target_os = "cloudabi",
                  target_os = "l4re",
+                 target_os = "hermit",
                  all(target_arch = "wasm32", not(target_os = "emscripten")),
                  all(target_vendor = "fortanix", target_env = "sgx")))] {
         pub use crate::sys::net;
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index e8f3434b958..4a28872deca 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -1052,6 +1052,7 @@ fn use_color(opts: &TestOpts) -> bool {
 
 #[cfg(any(
     target_os = "cloudabi",
+    target_os = "hermit",
     all(target_arch = "wasm32", not(target_os = "emscripten")),
     all(target_vendor = "fortanix", target_env = "sgx")
 ))]
@@ -1308,6 +1309,12 @@ fn get_concurrency() -> usize {
         1
     }
 
+    #[cfg(target_os = "hermit")]
+    fn num_cpus() -> usize {
+        // FIXME: Implement num_cpus on HermitCore
+        1
+    }
+
     #[cfg(any(
         all(target_arch = "wasm32", not(target_os = "emscripten")),
         all(target_vendor = "fortanix", target_env = "sgx")
diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs
index f24d957d67b..a2e2df016bd 100644
--- a/src/libunwind/build.rs
+++ b/src/libunwind/build.rs
@@ -43,6 +43,8 @@ fn main() {
         println!("cargo:rustc-link-lib=gcc_s");
     } else if target.contains("redox") {
         // redox is handled in lib.rs
+    } else if target.contains("hermit") {
+        //println!("cargo:rustc-link-lib=unwind");
     } else if target.contains("cloudabi") {
         println!("cargo:rustc-link-lib=unwind");
     }
diff --git a/src/libunwind/libunwind.rs b/src/libunwind/libunwind.rs
index 7c9eaa51fd9..92231e8207b 100644
--- a/src/libunwind/libunwind.rs
+++ b/src/libunwind/libunwind.rs
@@ -1,7 +1,26 @@
 #![allow(nonstandard_style)]
 
+#[cfg(not(target_os = "hermit"))]
 use libc::{c_int, c_void, uintptr_t};
 
+#[cfg(target_os = "hermit")]
+pub type c_int = i32;
+
+#[cfg(target_os = "hermit")]
+pub type uintptr_t = usize;
+
+#[cfg(target_os = "hermit")]
+#[repr(u8)]
+#[allow(missing_copy_implementations)]
+#[allow(missing_debug_implementations)]
+pub enum c_void {
+    // Two dummy variants so the #[repr] attribute can be used.
+    #[doc(hidden)]
+    __variant1,
+    #[doc(hidden)]
+    __variant2,
+}
+
 #[repr(C)]
 #[derive(Debug, Copy, Clone, PartialEq)]
 pub enum _Unwind_Reason_Code {
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index f41e7dd17ed..bc6c1973870 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -52,6 +52,7 @@ static TARGETS: &[&str] = &[
     "aarch64-linux-android",
     "aarch64-pc-windows-msvc",
     "aarch64-unknown-cloudabi",
+    "aarch64-unknown-hermit",
     "aarch64-unknown-linux-gnu",
     "aarch64-unknown-linux-musl",
     "aarch64-unknown-redox",
@@ -136,6 +137,7 @@ static TARGETS: &[&str] = &[
     "x86_64-unknown-linux-musl",
     "x86_64-unknown-netbsd",
     "x86_64-unknown-redox",
+    "x86_64-unknown-hermit",
 ];
 
 static DOCS_TARGETS: &[&str] = &[