about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/Cargo.toml3
-rw-r--r--src/libstd/build.rs2
-rw-r--r--src/libstd/keyword_docs.rs35
-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/panicking.rs12
-rw-r--r--src/libstd/sys/hermit/alloc.rs35
-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.rs62
-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.rs82
-rw-r--r--src/libstd/sys/hermit/fs.rs387
-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.rs147
-rw-r--r--src/libstd/sys/hermit/mutex.rs77
-rw-r--r--src/libstd/sys/hermit/net.rs364
-rw-r--r--src/libstd/sys/hermit/os.rs174
-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.rs119
-rw-r--r--src/libstd/sys/hermit/thread.rs116
-rw-r--r--src/libstd/sys/hermit/thread_local.rs61
-rw-r--r--src/libstd/sys/hermit/time.rs176
-rw-r--r--src/libstd/sys/mod.rs4
-rw-r--r--src/libstd/sys/sgx/abi/entry.S8
-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
43 files changed, 2306 insertions, 442 deletions
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index efe5c9d28f0..c55911a33f5 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -50,6 +50,9 @@ dlmalloc = { version = "0.1", features = ['rustc-dep-of-std'] }
 [target.x86_64-fortanix-unknown-sgx.dependencies]
 fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
 
+[target.'cfg(all(any(target_arch = "x86_64", target_arch = "aarch64"), target_os = "hermit"))'.dependencies]
+hermit-abi = { version = "0.1", features = ['rustc-dep-of-std'] }
+
 [target.wasm32-wasi.dependencies]
 wasi = { version = "0.7.0", features = ['rustc-dep-of-std', 'alloc'] }
 
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/keyword_docs.rs b/src/libstd/keyword_docs.rs
index ab8a55660cb..d025a7d16f2 100644
--- a/src/libstd/keyword_docs.rs
+++ b/src/libstd/keyword_docs.rs
@@ -159,9 +159,40 @@ mod const_keyword { }
 //
 /// Skip to the next iteration of a loop.
 ///
-/// The documentation for this keyword is [not yet complete]. Pull requests welcome!
+/// When `continue` is encountered, the current iteration is terminated, returning control to the
+/// loop head, typically continuing with the next iteration.
 ///
-/// [not yet complete]: https://github.com/rust-lang/rust/issues/34601
+///```rust
+/// // Printing odd numbers by skipping even ones
+/// for number in 1..=10 {
+///     if number % 2 == 0 {
+///         continue;
+///     }
+///     println!("{}", number);
+/// }
+///```
+///
+/// Like `break`, `continue` is normally associated with the innermost enclosing loop, but labels
+/// may be used to specify the affected loop.
+///
+///```rust
+/// // Print Odd numbers under 30 with unit <= 5
+/// 'tens: for ten in 0..3 {
+///     'units: for unit in 0..=9 {
+///         if unit % 2 == 0 {
+///             continue;
+///         }
+///         if unit > 5 {
+///             continue 'tens;
+///         }
+///         println!("{}", ten * 10 + unit);
+///     }
+/// }
+///```
+///
+/// See [continue expressions] from the reference for more details.
+///
+/// [continue expressions]: ../reference/expressions/loop-expr.html#continue-expressions
 mod continue_keyword { }
 
 #[doc(keyword = "crate")]
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/panicking.rs b/src/libstd/panicking.rs
index 619b1820190..f76969146fd 100644
--- a/src/libstd/panicking.rs
+++ b/src/libstd/panicking.rs
@@ -323,10 +323,8 @@ pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>,
     }
 
     let (file, line, col) = *file_line_col;
-    let info = PanicInfo::internal_constructor(
-        Some(msg),
-        Location::internal_constructor(file, line, col),
-    );
+    let location = Location::internal_constructor(file, line, col);
+    let info = PanicInfo::internal_constructor(Some(msg), &location);
     continue_panic_fmt(&info)
 }
 
@@ -453,10 +451,8 @@ fn rust_panic_with_hook(payload: &mut dyn BoxMeUp,
     }
 
     unsafe {
-        let mut info = PanicInfo::internal_constructor(
-            message,
-            Location::internal_constructor(file, line, col),
-        );
+        let location = Location::internal_constructor(file, line, col);
+        let mut info = PanicInfo::internal_constructor(message, &location);
         HOOK_LOCK.read();
         match HOOK {
             // Some platforms know that printing to stderr won't ever actually
diff --git a/src/libstd/sys/hermit/alloc.rs b/src/libstd/sys/hermit/alloc.rs
new file mode 100644
index 00000000000..86cc4463632
--- /dev/null
+++ b/src/libstd/sys/hermit/alloc.rs
@@ -0,0 +1,35 @@
+use crate::alloc::{GlobalAlloc, Layout, System};
+use crate::ptr;
+use crate::sys::hermit::abi;
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+    #[inline]
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        abi::malloc(layout.size(), layout.align())
+    }
+
+    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+        let addr = abi::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) {
+        abi::free(ptr, layout.size(), layout.align())
+    }
+
+    #[inline]
+    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        abi::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..8e52b3da1b1
--- /dev/null
+++ b/src/libstd/sys/hermit/condvar.rs
@@ -0,0 +1,62 @@
+use crate::cmp;
+use crate::sys::hermit::abi;
+use crate::sys::mutex::Mutex;
+use crate::time::Duration;
+
+pub struct Condvar {
+    identifier: usize,
+}
+
+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 _ = abi::notify(self.id(), 1);
+    }
+
+    #[inline]
+    pub unsafe fn notify_all(&self) {
+         let _ = abi::notify(self.id(), -1 /* =all */);
+    }
+
+    pub unsafe fn wait(&self, mutex: &Mutex) {
+        // add current task to the wait queue
+        let _ = abi::add_queue(self.id(), -1 /* no timeout */);
+        mutex.unlock();
+        let _ = abi::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 _ = abi::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 = abi::wait(self.id()) == 0;
+        mutex.lock();
+
+        ret
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        let _ = abi::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..84c54736647
--- /dev/null
+++ b/src/libstd/sys/hermit/fd.rs
@@ -0,0 +1,82 @@
+#![unstable(reason = "not public", issue = "0", feature = "fd")]
+
+use crate::io::{self, Read, ErrorKind};
+use crate::mem;
+use crate::sys::cvt;
+use crate::sys::hermit::abi;
+use crate::sys_common::AsInner;
+
+#[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 { abi::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 { abi::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 { abi::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..f8e5844a167
--- /dev/null
+++ b/src/libstd/sys/hermit/fs.rs
@@ -0,0 +1,387 @@
+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::abi;
+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;
+
+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(abi::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(abi::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..d4359631769
--- /dev/null
+++ b/src/libstd/sys/hermit/mod.rs
@@ -0,0 +1,147 @@
+//! 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;
+
+#[allow(unused_extern_crates)]
+pub extern crate hermit_abi as abi;
+
+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() -> ! {
+    abi::abort();
+}
+
+// FIXME: 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;
+    }
+
+    // initialize environment
+    os::init_environment(env as *const *const i8);
+
+    let result = main(argc as isize, argv);
+
+    abi::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..9414bf8fbbb
--- /dev/null
+++ b/src/libstd/sys/hermit/mutex.rs
@@ -0,0 +1,77 @@
+use crate::ptr;
+use crate::ffi::c_void;
+use crate::sys::hermit::abi;
+
+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 _ = abi::sem_init(&mut self.inner as *mut *const c_void, 1);
+    }
+
+    #[inline]
+    pub unsafe fn lock(&self) {
+        let _ = abi::sem_timedwait(self.inner, 0);
+    }
+
+    #[inline]
+    pub unsafe fn unlock(&self) {
+        let _ = abi::sem_post(self.inner);
+    }
+
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        let result = abi::sem_trywait(self.inner);
+        result == 0
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        let _ = abi::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 _ = abi::recmutex_init(&mut self.inner as *mut *const c_void);
+    }
+
+    #[inline]
+    pub unsafe fn lock(&self) {
+        let _ = abi::recmutex_lock(self.inner);
+    }
+
+    #[inline]
+    pub unsafe fn try_lock(&self) -> bool {
+        true
+    }
+
+    #[inline]
+    pub unsafe fn unlock(&self) {
+        let _ = abi::recmutex_unlock(self.inner);
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        let _ = abi::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..8a25cbcf07b
--- /dev/null
+++ b/src/libstd/sys/hermit/os.rs
@@ -0,0 +1,174 @@
+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::*;
+use crate::sys::hermit::abi;
+
+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 {
+        abi::exit(code);
+    }
+}
+
+pub fn getpid() -> u32 {
+    unsafe {
+        abi::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..9505f02fda8
--- /dev/null
+++ b/src/libstd/sys/hermit/stdio.rs
@@ -0,0 +1,119 @@
+use crate::io;
+use crate::io::{IoSlice, IoSliceMut};
+use crate::sys::hermit::abi;
+
+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 = abi::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 = abi::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 = abi::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 = abi::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..99a9c830c9e
--- /dev/null
+++ b/src/libstd/sys/hermit/thread.rs
@@ -0,0 +1,116 @@
+#![allow(dead_code)]
+
+use crate::ffi::CStr;
+use crate::io;
+use crate::sys::hermit::abi;
+use crate::time::Duration;
+use crate::mem;
+use crate::fmt;
+use core::u32;
+
+use crate::sys_common::thread::*;
+
+pub type Tid = abi::Tid;
+
+/// 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);
+
+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 = abi::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 {
+            abi::yield_now();
+        }
+    }
+
+    #[inline]
+    pub fn set_name(_name: &CStr) {
+        // nope
+    }
+
+    #[inline]
+    pub fn sleep(dur: Duration) {
+        unsafe {
+            abi::usleep(dur.as_micros() as u64);
+        }
+    }
+
+    pub fn join(self) {
+        unsafe {
+            let _ = abi::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..8372189546d
--- /dev/null
+++ b/src/libstd/sys/hermit/time.rs
@@ -0,0 +1,176 @@
+#![allow(dead_code)]
+
+use crate::time::Duration;
+use crate::cmp::Ordering;
+use crate::convert::TryInto;
+use core::hash::{Hash, Hasher};
+use crate::sys::hermit::abi;
+use crate::sys::hermit::abi::{CLOCK_REALTIME, CLOCK_MONOTONIC, NSEC_PER_SEC};
+use crate::sys::hermit::abi::timespec;
+
+#[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 { abi::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 { abi::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/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S
index c35e49b1dc6..cd26c7ca200 100644
--- a/src/libstd/sys/sgx/abi/entry.S
+++ b/src/libstd/sys/sgx/abi/entry.S
@@ -119,8 +119,14 @@ sgx_entry:
     mov %rbx,%gs:tcsls_tcs_addr
     stmxcsr %gs:tcsls_user_mxcsr
     fnstcw %gs:tcsls_user_fcw
+
 /*  reset user state */
-    cld /* x86-64 ABI requires DF to be unset at function entry/exit */
+/*    - DF flag: x86-64 ABI requires DF to be unset at function entry/exit */
+/*    - AC flag: AEX on misaligned memory accesses leaks side channel info */
+    pushfq
+    andq $~0x40400, (%rsp)
+    popfq
+
 /*  check for debug buffer pointer */
     testb  $0xff,DEBUG(%rip)
     jz .Lskip_debug_init
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 5e1f10c03ce..cbf751bec95 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -502,12 +502,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 }),
@@ -530,7 +530,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
@@ -561,8 +560,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;