diff --git a/Cargo.lock b/Cargo.lock
index 449f0c73588eb..014e6ee71c76b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -868,9 +868,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.87"
+version = "0.1.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f867ce54c09855ccd135ad4a50c777182a0c7af5ff20a8f537617bd648b10d50"
+checksum = "9fc9c2080d347a2c316518840ac9194644a9993dfa1e9778ef38979a339f5d8b"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
@@ -2879,9 +2879,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.139"
+version = "0.2.140"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
+checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
 dependencies = [
  "rustc-std-workspace-core",
 ]
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index a4ae1b01e869d..fb563f70ed090 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -214,6 +214,8 @@ pub fn target_machine_factory(
 
     let path_mapping = sess.source_map().path_mapping().clone();
 
+    let force_emulated_tls = sess.target.force_emulated_tls;
+
     Arc::new(move |config: TargetMachineFactoryConfig| {
         let split_dwarf_file =
             path_mapping.map_prefix(config.split_dwarf_file.unwrap_or_default()).0;
@@ -239,6 +241,7 @@ pub fn target_machine_factory(
                 relax_elf_relocations,
                 use_init_array,
                 split_dwarf_file.as_ptr(),
+                force_emulated_tls,
             )
         };
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 9e5265188b503..0d63e634ad888 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -2257,6 +2257,7 @@ extern "C" {
         RelaxELFRelocations: bool,
         UseInitArray: bool,
         SplitDwarfFile: *const c_char,
+        ForceEmulatedTls: bool,
     ) -> Option<&'static mut TargetMachine>;
     pub fn LLVMRustDisposeTargetMachine(T: &'static mut TargetMachine);
     pub fn LLVMRustAddLibraryInfo<'a>(
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index e604e44a7157b..329e7329b11a5 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -368,7 +368,8 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
     bool EmitStackSizeSection,
     bool RelaxELFRelocations,
     bool UseInitArray,
-    const char *SplitDwarfFile) {
+    const char *SplitDwarfFile,
+    bool ForceEmulatedTls) {
 
   auto OptLevel = fromRust(RustOptLevel);
   auto RM = fromRust(RustReloc);
@@ -400,6 +401,10 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
   }
   Options.RelaxELFRelocations = RelaxELFRelocations;
   Options.UseInitArray = UseInitArray;
+  if (ForceEmulatedTls) {
+    Options.ExplicitEmulatedTLS = true;
+    Options.EmulatedTLS = true;
+  }
 
   if (TrapUnreachable) {
     // Tell LLVM to codegen `unreachable` into an explicit trap instruction.
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_ohos.rs
new file mode 100644
index 0000000000000..0a5e654cf0d03
--- /dev/null
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_ohos.rs
@@ -0,0 +1,31 @@
+use crate::spec::{Target, TargetOptions};
+
+use super::SanitizerSet;
+
+pub fn target() -> Target {
+    let mut base = super::linux_musl_base::opts();
+    base.env = "ohos".into();
+    base.crt_static_default = false;
+    base.max_atomic_width = Some(128);
+
+    Target {
+        // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead.
+        llvm_target: "aarch64-unknown-linux-musl".into(),
+        pointer_width: 64,
+        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(),
+        arch: "aarch64".into(),
+        options: TargetOptions {
+            features: "+reserve-x18".into(),
+            mcount: "\u{1}_mcount".into(),
+            force_emulated_tls: true,
+            supported_sanitizers: SanitizerSet::ADDRESS
+                | SanitizerSet::CFI
+                | SanitizerSet::LEAK
+                | SanitizerSet::MEMORY
+                | SanitizerSet::MEMTAG
+                | SanitizerSet::THREAD
+                | SanitizerSet::HWADDRESS,
+            ..base
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_ohos.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_ohos.rs
new file mode 100644
index 0000000000000..a64f3a4f0493e
--- /dev/null
+++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_ohos.rs
@@ -0,0 +1,27 @@
+use crate::spec::{Target, TargetOptions};
+
+// This target is for OpenHarmony on ARMv7 Linux with thumb-mode, but no NEON or
+// hardfloat.
+
+pub fn target() -> Target {
+    // Most of these settings are copied from the armv7_unknown_linux_musleabi
+    // target.
+    Target {
+        // LLVM 15 doesn't support OpenHarmony yet, use a linux target instead.
+        llvm_target: "armv7-unknown-linux-gnueabi".into(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
+        arch: "arm".into(),
+
+        options: TargetOptions {
+            abi: "eabi".into(),
+            features: "+v7,+thumb2,+soft-float,-neon".into(),
+            max_atomic_width: Some(64),
+            env: "ohos".into(),
+            crt_static_default: false,
+            mcount: "\u{1}mcount".into(),
+            force_emulated_tls: true,
+            ..super::linux_musl_base::opts()
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 2553b11d8789b..c40284cbf4474 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -1261,6 +1261,9 @@ supported_targets! {
 
     ("aarch64-unknown-nto-qnx710", aarch64_unknown_nto_qnx_710),
     ("x86_64-pc-nto-qnx710", x86_64_pc_nto_qnx710),
+
+    ("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos),
+    ("armv7-unknown-linux-ohos", armv7_unknown_linux_ohos),
 }
 
 /// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]>
@@ -1734,6 +1737,9 @@ pub struct TargetOptions {
 
     /// Whether the target supports XRay instrumentation.
     pub supports_xray: bool,
+
+    /// Forces the use of emulated TLS (__emutls_get_address)
+    pub force_emulated_tls: bool,
 }
 
 /// Add arguments for the given flavor and also for its "twin" flavors
@@ -1954,6 +1960,7 @@ impl Default for TargetOptions {
             entry_name: "main".into(),
             entry_abi: Conv::C,
             supports_xray: false,
+            force_emulated_tls: false,
         }
     }
 }
@@ -2605,6 +2612,7 @@ impl Target {
         key!(entry_name);
         key!(entry_abi, Conv)?;
         key!(supports_xray, bool);
+        key!(force_emulated_tls, bool);
 
         if base.is_builtin {
             // This can cause unfortunate ICEs later down the line.
@@ -2859,6 +2867,7 @@ impl ToJson for Target {
         target_option_val!(entry_name);
         target_option_val!(entry_abi);
         target_option_val!(supports_xray);
+        target_option_val!(force_emulated_tls);
 
         if let Some(abi) = self.default_adjusted_cabi {
             d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json());
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 598a4bf928290..6345db240548d 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -15,7 +15,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
-libc = { version = "0.2.139", default-features = false, features = ['rustc-dep-of-std'] }
+libc = { version = "0.2.140", default-features = false, features = ['rustc-dep-of-std'] }
 compiler_builtins = { version = "0.1.87" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 21b035fb37379..1c44058aff79d 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -115,7 +115,10 @@ pub fn set_errno(e: i32) {
 /// Gets a detailed string description for the given error number.
 pub fn error_string(errno: i32) -> String {
     extern "C" {
-        #[cfg_attr(any(target_os = "linux", target_env = "newlib"), link_name = "__xpg_strerror_r")]
+        #[cfg_attr(
+            all(any(target_os = "linux", target_env = "newlib"), not(target_env = "ohos")),
+            link_name = "__xpg_strerror_r"
+        )]
         fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int;
     }
 
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index edc10aa39afba..b655bae967372 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -54,6 +54,22 @@ cfg_if::cfg_if! {
     }
 }
 
+// This is the same as musl except that we default to using the system libunwind
+// instead of libgcc.
+#[cfg(target_env = "ohos")]
+cfg_if::cfg_if! {
+    if #[cfg(all(feature = "llvm-libunwind", feature = "system-llvm-libunwind"))] {
+        compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time");
+    } else if #[cfg(feature = "llvm-libunwind")] {
+        #[link(name = "unwind", kind = "static", modifiers = "-bundle")]
+        extern "C" {}
+    } else {
+        #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
+        #[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
+        extern "C" {}
+    }
+}
+
 #[cfg(target_os = "android")]
 cfg_if::cfg_if! {
     if #[cfg(feature = "llvm-libunwind")] {
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 20b92b294fec5..f981b5d5da843 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -149,6 +149,8 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)]
     // Needed to avoid the need to copy windows.lib into the sysroot.
     (Some(Mode::Rustc), "windows_raw_dylib", None),
     (Some(Mode::ToolRustc), "windows_raw_dylib", None),
+    // #[cfg(bootstrap)] ohos
+    (Some(Mode::Std), "target_env", Some(&["ohos"])),
 ];
 
 /// A structure representing a Rust compiler.
diff --git a/src/bootstrap/llvm.rs b/src/bootstrap/llvm.rs
index de06f8ca8c0bb..a22f0f04b2e01 100644
--- a/src/bootstrap/llvm.rs
+++ b/src/bootstrap/llvm.rs
@@ -1008,6 +1008,9 @@ fn supported_sanitizers(
         "aarch64-unknown-linux-gnu" => {
             common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
         }
+        "aarch64-unknown-linux-ohos" => {
+            common_libs("linux", "aarch64", &["asan", "lsan", "msan", "tsan", "hwasan"])
+        }
         "x86_64-apple-darwin" => darwin_libs("osx", &["asan", "lsan", "tsan"]),
         "x86_64-unknown-fuchsia" => common_libs("fuchsia", "x86_64", &["asan"]),
         "x86_64-apple-ios" => darwin_libs("iossim", &["asan", "tsan"]),
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 752f1cc4aba03..0452126cc3782 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -26,6 +26,7 @@
     - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
     - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
     - [\*-android and \*-androideabi](platform-support/android.md)
+    - [\*-linux-ohos](platform-support/openharmony.md)
     - [\*-unknown-fuchsia](platform-support/fuchsia.md)
     - [\*-kmc-solid_\*](platform-support/kmc-solid.md)
     - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 2d74a2240969c..5c18a38ddab94 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -218,6 +218,7 @@ target | std | host | notes
 [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ |  | ARM64 SOLID with TOPPERS/ASP3
 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * |  | ARM64 Nintendo Switch, Horizon
 [`aarch64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ |
+[`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ |  | ARM64 OpenHarmony |
 [`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ |  | ARM64 QNX Neutrino 7.1 RTOS |
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 `aarch64-unknown-hermit` | ✓ |  | ARM64 HermitCore
@@ -240,6 +241,7 @@ target | std | host | notes
 [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? |  | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain)
 `armv7-apple-ios` | ✓ |  | ARMv7 iOS, Cortex-a8
 [`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ? |  | ARM Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain)
+[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ |  | ARMv7 OpenHarmony |
 [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | ARMv7 Linux with uClibc, softfloat
 [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7 Linux with uClibc, hardfloat
 `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD
diff --git a/src/doc/rustc/src/platform-support/openharmony.md b/src/doc/rustc/src/platform-support/openharmony.md
new file mode 100644
index 0000000000000..aa4debfd45a33
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/openharmony.md
@@ -0,0 +1,128 @@
+# `*-linux-ohos*`
+
+**Tier: 3**
+
+Targets for the [OpenHarmony](https://gitee.com/openharmony/docs/) operating
+system.
+
+## Target maintainers
+
+- Amanieu d'Antras ([@Amanieu](https://github.com/Amanieu))
+
+## Setup
+
+The OpenHarmony SDK doesn't currently support Rust compilation directly, so
+some setup is required.
+
+First, you must obtain the OpenHarmony SDK from [this page](https://gitee.com/openharmony/docs/tree/master/en/release-notes).
+Select the version of OpenHarmony you are developing for and download the "Public SDK package for the standard system".
+
+Create the following shell scripts that wrap Clang from the OpenHarmony SDK:
+
+`aarch64-unknown-linux-ohos-clang.sh`
+
+```sh
+#!/bin/sh
+exec /path/to/ohos-sdk/linux/native/llvm/bin/clang \
+  -target aarch64-linux-ohos \
+  --sysroot=/path/to/ohos-sdk/linux/native/sysroot \
+  -D__MUSL__ \
+  "$@"
+```
+
+`aarch64-unknown-linux-ohos-clang++.sh`
+
+```sh
+#!/bin/sh
+exec /path/to/ohos-sdk/linux/native/llvm/bin/clang++ \
+  -target aarch64-linux-ohos \
+  --sysroot=/path/to/ohos-sdk/linux/native/sysroot \
+  -D__MUSL__ \
+  "$@"
+```
+
+`armv7-unknown-linux-ohos-clang.sh`
+
+```sh
+#!/bin/sh
+exec /path/to/ohos-sdk/linux/native/llvm/bin/clang \
+  -target arm-linux-ohos \
+  --sysroot=/path/to/ohos-sdk/linux/native/sysroot \
+  -D__MUSL__ \
+  -march=armv7-a \
+  -mfloat-abi=softfp \
+  -mtune=generic-armv7-a \
+  -mthumb \
+  "$@"
+```
+
+`armv7-unknown-linux-ohos-clang++.sh`
+
+```sh
+#!/bin/sh
+exec /path/to/ohos-sdk/linux/native/llvm/bin/clang++ \
+  -target arm-linux-ohos \
+  --sysroot=/path/to/ohos-sdk/linux/native/sysroot \
+  -D__MUSL__ \
+  -march=armv7-a \
+  -mfloat-abi=softfp \
+  -mtune=generic-armv7-a \
+  -mthumb \
+  "$@"
+```
+
+Future versions of the OpenHarmony SDK will avoid the need for this process.
+
+## Building the target
+
+To build a rust toolchain, create a `config.toml` with the following contents:
+
+```toml
+profile = "compiler"
+changelog-seen = 2
+
+[build]
+sanitizers = true
+profiler = true
+
+[target.aarch64-unknown-linux-ohos]
+cc = "/path/to/aarch64-unknown-linux-ohos-clang.sh"
+cxx = "/path/to/aarch64-unknown-linux-ohos-clang++.sh"
+ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
+ranlib = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ranlib"
+linker  = "/path/to/aarch64-unknown-linux-ohos-clang.sh"
+
+[target.armv7-unknown-linux-ohos]
+cc = "/path/to/armv7-unknown-linux-ohos-clang.sh"
+cxx = "/path/to/armv7-unknown-linux-ohos-clang++.sh"
+ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
+ranlib = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ranlib"
+linker  = "/path/to/armv7-unknown-linux-ohos-clang.sh"
+```
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+You will need to configure the linker to use in `~/.cargo/config`:
+```toml
+[target.aarch64-unknown-linux-ohos]
+ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
+linker = "/path/to/aarch64-unknown-linux-ohos-clang.sh"
+
+[target.armv7-unknown-linux-ohos]
+ar = "/path/to/ohos-sdk/linux/native/llvm/bin/llvm-ar"
+linker = "/path/to/armv7-unknown-linux-ohos-clang.sh"
+```
+
+## Testing
+
+Running the Rust testsuite is possible, but currently difficult due to the way
+the OpenHarmony emulator is set up (no networking).
+
+## Cross-compilation toolchains and C code
+
+You can use the shell scripts above to compile C code for the target.