diff --git a/libphobos/libdruntime/config/loongarch/switchcontext.S b/libphobos/libdruntime/config/loongarch/switchcontext.S
new file mode 100644
index 00000000000..edfb9b67e8f
--- /dev/null
+++ b/libphobos/libdruntime/config/loongarch/switchcontext.S
@@ -0,0 +1,133 @@
+/* LoongArch support code for fibers and multithreading.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+#include "../common/threadasm.S"
+
+/**
+ * Performs a context switch.
+ *
+ * $a0 - void** - ptr to old stack pointer
+ * $a1 - void*  - new stack pointer
+ *
+ */
+
+#if defined(__loongarch_lp64)
+#  define GPR_L ld.d
+#  define GPR_S st.d
+#  define SZ_GPR 8
+#  define ADDSP(si)   addi.d  $sp, $sp, si
+#elif defined(__loongarch64_ilp32)
+#  define GPR_L ld.w
+#  define GPR_S st.w
+#  define SZ_GPR 4
+#  define ADDSP(si)   addi.w  $sp, $sp, si
+#else
+#  error Unsupported GPR size (must be 64-bit or 32-bit).
+#endif
+
+#if defined(__loongarch_double_float)
+#  define FPR_L fld.d
+#  define FPR_S fst.d
+#  define SZ_FPR 8
+#elif defined(__loongarch_single_float)
+#  define FPR_L fld.s
+#  define FPR_S fst.s
+#  define SZ_FPR 4
+#else
+#  define SZ_FPR 0
+#endif
+
+    .text
+    .align 2
+    .global fiber_switchContext
+    .type   fiber_switchContext, @function
+fiber_switchContext:
+    .cfi_startproc
+    ADDSP(-11 * SZ_GPR)
+
+    // fp regs and return address are stored below the stack
+    // because we don't want the GC to scan them.
+
+    // return address (r1)
+    GPR_S  $r1, $sp, -SZ_GPR
+
+#if SZ_FPR != 0
+    // callee-saved scratch FPRs (f24-f31)
+    FPR_S  $f24, $sp, -SZ_GPR-1*SZ_FPR
+    FPR_S  $f25, $sp, -SZ_GPR-2*SZ_FPR
+    FPR_S  $f26, $sp, -SZ_GPR-3*SZ_FPR
+    FPR_S  $f27, $sp, -SZ_GPR-4*SZ_FPR
+    FPR_S  $f28, $sp, -SZ_GPR-5*SZ_FPR
+    FPR_S  $f29, $sp, -SZ_GPR-6*SZ_FPR
+    FPR_S  $f30, $sp, -SZ_GPR-7*SZ_FPR
+    FPR_S  $f31, $sp, -SZ_GPR-8*SZ_FPR
+#endif
+
+    // callee-saved GPRs (r21, fp (r22), r23-r31)
+    GPR_S $r21, $sp, 0*SZ_GPR
+    GPR_S  $fp, $sp, 1*SZ_GPR
+    GPR_S  $s0, $sp, 2*SZ_GPR
+    GPR_S  $s1, $sp, 3*SZ_GPR
+    GPR_S  $s2, $sp, 4*SZ_GPR
+    GPR_S  $s3, $sp, 5*SZ_GPR
+    GPR_S  $s4, $sp, 6*SZ_GPR
+    GPR_S  $s5, $sp, 7*SZ_GPR
+    GPR_S  $s6, $sp, 8*SZ_GPR
+    GPR_S  $s7, $sp, 9*SZ_GPR
+    GPR_S  $s8, $sp, 10*SZ_GPR
+
+    // swap stack pointer
+    GPR_S $sp, $a0, 0
+    move $sp, $a1
+
+    GPR_L  $r1, $sp, -SZ_GPR
+
+#if SZ_FPR != 0
+    FPR_L  $f24, $sp, -SZ_GPR-1*SZ_FPR
+    FPR_L  $f25, $sp, -SZ_GPR-2*SZ_FPR
+    FPR_L  $f26, $sp, -SZ_GPR-3*SZ_FPR
+    FPR_L  $f27, $sp, -SZ_GPR-4*SZ_FPR
+    FPR_L  $f28, $sp, -SZ_GPR-5*SZ_FPR
+    FPR_L  $f29, $sp, -SZ_GPR-6*SZ_FPR
+    FPR_L  $f30, $sp, -SZ_GPR-7*SZ_FPR
+    FPR_L  $f31, $sp, -SZ_GPR-8*SZ_FPR
+#endif
+
+    GPR_L $r21, $sp, 0*SZ_GPR
+    GPR_L  $fp, $sp, 1*SZ_GPR
+    GPR_L  $s0, $sp, 2*SZ_GPR
+    GPR_L  $s1, $sp, 3*SZ_GPR
+    GPR_L  $s2, $sp, 4*SZ_GPR
+    GPR_L  $s3, $sp, 5*SZ_GPR
+    GPR_L  $s4, $sp, 6*SZ_GPR
+    GPR_L  $s5, $sp, 7*SZ_GPR
+    GPR_L  $s6, $sp, 8*SZ_GPR
+    GPR_L  $s7, $sp, 9*SZ_GPR
+    GPR_L  $s8, $sp, 10*SZ_GPR
+
+    ADDSP(11 * SZ_GPR)
+
+    jr     $r1 // return
+    .cfi_endproc
+    .size fiber_switchContext,.-fiber_switchContext
diff --git a/libphobos/libdruntime/core/stdc/fenv.d b/libphobos/libdruntime/core/stdc/fenv.d
index 288f9c25dc6..0051ecdb7c9 100644
--- a/libphobos/libdruntime/core/stdc/fenv.d
+++ b/libphobos/libdruntime/core/stdc/fenv.d
@@ -797,7 +797,7 @@ else
     }
     else version (LoongArch64)
     {
-        // Define bits representing exceptions in the FPSR status word.
+        // Define bits representing exceptions in the Flags field in FCSR{0,2}.
         enum
         {
             FE_INEXACT      = 0x010000, ///
@@ -808,13 +808,13 @@ else
             FE_ALL_EXCEPT   = 0x1f0000, ///
         }
 
-        // Define bits representing rounding modes in the FPCR Rmode field.
+        // Define bits representing rounding modes in the RM field in FCSR{0,3}.
         enum
         {
             FE_TONEAREST    = 0x000, ///
             FE_TOWARDZERO   = 0x100, ///
-            FE_DOWNWARD     = 0x200, ///
-            FE_UPWARD       = 0x300, ///
+            FE_UPWARD       = 0x200, ///
+            FE_DOWNWARD     = 0x300, ///
         }
     }
     else
diff --git a/libphobos/libdruntime/core/stdc/stdarg.d b/libphobos/libdruntime/core/stdc/stdarg.d
index 5b79813ae1b..0ba1ebe34e3 100644
--- a/libphobos/libdruntime/core/stdc/stdarg.d
+++ b/libphobos/libdruntime/core/stdc/stdarg.d
@@ -257,6 +257,12 @@ T va_arg(T)(ref va_list ap)
         ap += T.sizeof.alignUp;
         return *p;
     }
+    else version (LoongArch64)
+    {
+        auto p = cast(T*) ap;
+        ap += T.sizeof.alignUp;
+        return *p;
+    }
     else version (MIPS_Any)
     {
         auto p = cast(T*) ap;
diff --git a/libphobos/libdruntime/core/sys/elf/package.d b/libphobos/libdruntime/core/sys/elf/package.d
index b120ee58f69..60e05d97036 100644
--- a/libphobos/libdruntime/core/sys/elf/package.d
+++ b/libphobos/libdruntime/core/sys/elf/package.d
@@ -339,6 +339,8 @@ enum EM_CSKY =        252;
 
 enum EM_NUM =         253;
 
+enum EM_LOONGARCH =   258;
+
 enum EM_ALPHA =        0x9026;
 
 enum EV_NONE =         0;
diff --git a/libphobos/libdruntime/core/sys/linux/sys/auxv.d b/libphobos/libdruntime/core/sys/linux/sys/auxv.d
index 5f098e98e02..1099fae497f 100644
--- a/libphobos/libdruntime/core/sys/linux/sys/auxv.d
+++ b/libphobos/libdruntime/core/sys/linux/sys/auxv.d
@@ -13,6 +13,7 @@ extern (C):
 
 version (MIPS32)  version = MIPS_Any;
 version (MIPS64)  version = MIPS_Any;
+version (LoongArch64) version = LoongArch_Any;
 version (PPC)     version = PPC_Any;
 version (PPC64)   version = PPC_Any;
 version (S390)    version = IBMZ_Any;
@@ -156,3 +157,19 @@ else version (IBMZ_Any)
   enum HWCAP_S390_TE                      = 1024;
   enum HWCAP_S390_VX                      = 2048;
 }
+else version (LoongArch_Any)
+{
+  enum HWCAP_LOONGARCH_CPUCFG             = 0x00000001;
+  enum HWCAP_LOONGARCH_LAM                = 0x00000002;
+  enum HWCAP_LOONGARCH_UAL                = 0x00000004;
+  enum HWCAP_LOONGARCH_FPU                = 0x00000008;
+  enum HWCAP_LOONGARCH_LSX                = 0x00000010;
+  enum HWCAP_LOONGARCH_LASX               = 0x00000020;
+  enum HWCAP_LOONGARCH_CRC32              = 0x00000040;
+  enum HWCAP_LOONGARCH_COMPLEX            = 0x00000080;
+  enum HWCAP_LOONGARCH_CRYPTO             = 0x00000100;
+  enum HWCAP_LOONGARCH_LVZ                = 0x00000200;
+  enum HWCAP_LOONGARCH_LBT_X86            = 0x00000400;
+  enum HWCAP_LOONGARCH_LBT_ARM            = 0x00000800;
+  enum HWCAP_LOONGARCH_LBT_MIPS           = 0x00001000;
+}
diff --git a/libphobos/libdruntime/core/sys/linux/sys/mman.d b/libphobos/libdruntime/core/sys/linux/sys/mman.d
index 7ed78ef6436..e4765af1490 100644
--- a/libphobos/libdruntime/core/sys/linux/sys/mman.d
+++ b/libphobos/libdruntime/core/sys/linux/sys/mman.d
@@ -432,6 +432,7 @@ else version (MIPS_Any)
         MAP_HUGETLB = 0x80000,
     }
 }
+// http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/bits/mman-map-flags-generic.h
 else version (LoongArch64)
 {
     static if (_DEFAULT_SOURCE) enum
diff --git a/libphobos/libdruntime/core/thread/fiber.d b/libphobos/libdruntime/core/thread/fiber.d
index 65878bc1c66..e0838bcffef 100644
--- a/libphobos/libdruntime/core/thread/fiber.d
+++ b/libphobos/libdruntime/core/thread/fiber.d
@@ -178,8 +178,12 @@ private
     }
     else version (LoongArch64)
     {
-        version = AsmLoongArch64_Posix;
-        version = AsmExternal;
+        version (Posix)
+        {
+            version = AsmLoongArch64_Posix;
+            version = AsmExternal;
+            version = AlignFiberStackTo16Byte;
+        }
     }
 
     version (Posix)
@@ -1442,27 +1446,6 @@ private:
             pstack -= ABOVE;
             *cast(size_t*)(pstack - SZ_RA) = cast(size_t)&fiber_entryPoint;
         }
-        else version (AsmLoongArch64_Posix)
-        {
-            version (StackGrowsDown) {}
-            else static assert(0);
-
-            // Like others, FP registers and return address (ra) are kept
-            // below the saved stack top (tstack) to hide from GC scanning.
-            // The newp stack should look like this on LoongArch64:
-            // 18: fp     <- pstack
-            // ...
-            //  9: s0     <- newp tstack
-            //  8: ra     [&fiber_entryPoint]
-            //  7: fs7
-            // ...
-            //  1: fs1
-            //  0: fs0
-            pstack -= 10 * size_t.sizeof; // skip s0-s8 and fp
-            // set $ra
-            push( cast(size_t) &fiber_entryPoint );
-            pstack += size_t.sizeof;
-        }
         else version (AsmAArch64_Posix)
         {
             // Like others, FP registers and return address (lr) are kept
@@ -1558,6 +1541,32 @@ private:
                 push( cast(size_t) m_ctxt.bstack + m_size );        // GS:[16] - Bottom of stack
             }
         }
+        else version (AsmLoongArch64_Posix)
+        {
+            // Like others, FP registers and return address ($r1) are kept
+            // below the saved stack top (tstack) to hide from GC scanning.
+            // fiber_switchContext expects newp sp to look like this:
+            //   10: $r21 (reserved)
+            //    9: $r22 (frame pointer)
+            //    8: $r23
+            //   ...
+            //    0: $r31 <-- newp tstack
+            //   -1: $r1  (return address)  [&fiber_entryPoint]
+            //   -2: $f24
+            //   ...
+            //   -9: $f31
+
+            version (StackGrowsDown) {}
+            else
+                static assert(false, "Only full descending stacks supported on LoongArch64");
+
+            // Only need to set return address ($r1).  Everything else is fine
+            // zero initialized.
+            pstack -= size_t.sizeof * 11;    // skip past space reserved for $r21-$r31
+            push (cast(size_t) &fiber_entryPoint);
+            pstack += size_t.sizeof;         // adjust sp (newp) above lr
+        }
+
         else static if ( __traits( compiles, ucontext_t ) )
         {
             getcontext( &m_utxt );
diff --git a/libphobos/libdruntime/core/vararg.d b/libphobos/libdruntime/core/vararg.d
index 2c3e9659fb6..e6dd47d06d3 100644
--- a/libphobos/libdruntime/core/vararg.d
+++ b/libphobos/libdruntime/core/vararg.d
@@ -129,6 +129,13 @@ void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
         ap += tsize.alignUp;
         parmn[0..tsize] = p[0..tsize];
     }
+    else version (LoongArch64)
+    {
+        const tsize = ti.tsize;
+        auto p = cast(void*) ap;
+        ap += tsize.alignUp;
+        parmn[0..tsize] = p[0..tsize];
+    }
     else version (MIPS_Any)
     {
         const tsize = ti.tsize;
diff --git a/libphobos/src/std/math/hardware.d b/libphobos/src/std/math/hardware.d
index 81c7302b4c1..e2ca3dbe064 100644
--- a/libphobos/src/std/math/hardware.d
+++ b/libphobos/src/std/math/hardware.d
@@ -33,6 +33,7 @@ version (SPARC64)   version = SPARC_Any;
 version (SystemZ)   version = IBMZ_Any;
 version (RISCV32)   version = RISCV_Any;
 version (RISCV64)   version = RISCV_Any;
+version (LoongArch64)   version = LoongArch_Any;
 
 version (D_InlineAsm_X86)    version = InlineAsm_X86_Any;
 version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any;
@@ -60,6 +61,7 @@ else version (X86_Any)   version = IeeeFlagsSupport;
 else version (PPC_Any)   version = IeeeFlagsSupport;
 else version (RISCV_Any) version = IeeeFlagsSupport;
 else version (MIPS_Any)  version = IeeeFlagsSupport;
+else version (LoongArch_Any) version = IeeeFlagsSupport;
 else version (ARM_Any)   version = IeeeFlagsSupport;
 
 // Struct FloatingPointControl is only available if hardware FP units are available.
@@ -90,6 +92,7 @@ private:
     // The ARM and PowerPC FPSCR is a 32-bit register.
     // The SPARC FSR is a 32bit register (64 bits for SPARC 7 & 8, but high bits are uninteresting).
     // The RISC-V (32 & 64 bit) fcsr is 32-bit register.
+    // THe LoongArch fcsr (fcsr0) is a 32-bit register.
     uint flags;
 
     version (CRuntime_Microsoft)
@@ -174,6 +177,20 @@ private:
                     return result;
                 }
             }
+            else version (LoongArch_Any)
+            {
+                version (D_SoftFloat)
+                    return 0;
+                else
+                {
+                    uint result = void;
+                    asm pure nothrow @nogc
+                    {
+                        "movfcsr2gr %0,$r2" : "=r" (result);
+                    }
+                    return result & EXCEPTIONS_MASK;
+                }
+            }
             else
                 assert(0, "Not yet supported");
         }
@@ -273,6 +290,18 @@ private:
                     }
                 }
             }
+            else version (LoongArch_Any)
+            {
+                version (D_SoftFloat)
+                    return;
+                else
+                {
+                    asm nothrow @nogc
+                    {
+                        "movgr2fcsr $r2,$r0";
+                    }
+                }
+            }
             else
                 assert(0, "Not yet supported");
         }
@@ -725,6 +754,21 @@ nothrow @nogc:
                                  | inexactException,
         }
     }
+    else version (LoongArch_Any)
+    {
+        enum : ExceptionMask
+        {
+            inexactException      = 0x00,
+            divByZeroException    = 0x01,
+            overflowException     = 0x02,
+            underflowException    = 0x04,
+            invalidException      = 0x08,
+            severeExceptions   = overflowException | divByZeroException
+                                 | invalidException,
+            allExceptions      = severeExceptions | underflowException
+                                 | inexactException,
+        }
+    }
     else version (MIPS_Any)
     {
         enum : ExceptionMask
@@ -812,6 +856,8 @@ nothrow @nogc:
             return true;
         else version (MIPS_Any)
             return true;
+        else version (LoongArch_Any)
+            return true;
         else version (ARM_Any)
         {
             // The hasExceptionTraps_impl function is basically pure,
@@ -885,6 +931,10 @@ private:
     {
         alias ControlState = uint;
     }
+    else version (LoongArch_Any)
+    {
+        alias ControlState = uint;
+    }
     else version (MIPS_Any)
     {
         alias ControlState = uint;
@@ -959,6 +1009,20 @@ private:
                 }
                 return cont;
             }
+            else version (LoongArch_Any)
+            {
+                version (D_SoftFloat)
+                    return 0;
+                else
+                {
+                    ControlState cont;
+                    asm pure nothrow @nogc
+                    {
+                        "movfcsr2gr %0,$r0" : "=r" (cont);
+                    }
+                    cont &= (roundingMask | allExceptions);
+                }
+            }
             else version (RISCV_Any)
             {
                 version (D_SoftFloat)
@@ -1068,6 +1132,19 @@ private:
                     }
                 }
             }
+            else version (LoongArch_Any)
+            {
+                version (D_SoftFloat)
+                    return;
+                else
+                {
+                    asm nothrow @nogc
+                    {
+                        "movgr2fcsr $r0,%0" :
+                        : "r" (newState & (roundingMask | allExceptions));
+                    }
+                }
+            }
             else version (RISCV_Any)
             {
                 version (D_SoftFloat)
