Browse Source

Add support for LoongArch64 architecture

zhoumingtao 3 years ago
parent
commit
e7db4418b1

+ 2 - 0
Make.defaults

@@ -143,11 +143,13 @@ ifneq ($(ARCH),aarch64)
 ifneq ($(ARCH),arm)
 ifneq ($(ARCH),mips64el)
 ifneq ($(ARCH),riscv64)
+ifneq ($(ARCH),loongarch64)
 export HAVE_EFI_OBJCOPY=y
 endif
 endif
 endif
 endif
+endif
 
 ifneq ($(ARCH),arm)
 export LIBGCC=$(shell $(CC) $(ARCH3264) -print-libgcc-file-name)

+ 4 - 2
apps/lfbgrid.c

@@ -52,7 +52,8 @@ draw_boxes(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop)
 	UINT32 *PixelBuffer;
 	UINT32 CopySize, BufferSize;
 #if defined(__x86_64__) || defined(__aarch64__) || \
-    (defined (__riscv) && __riscv_xlen == 64)
+    (defined (__riscv) && __riscv_xlen == 64) || \
+    defined(__loongarch64)
 	UINT64 FrameBufferAddr;
 #elif defined(__i386__) || defined(__arm__)
 	UINT32 FrameBufferAddr;
@@ -116,7 +117,8 @@ draw_boxes(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop)
 			return;
 		}
 #if defined(__x86_64__) || defined(__aarch64__) || \
-    (defined (__riscv) && __riscv_xlen == 64)
+    (defined (__riscv) && __riscv_xlen == 64) || \
+    defined(__loongarch64)
 		FrameBufferAddr = (UINT64)gop->Mode->FrameBufferBase;
 #elif defined(__i386__) || defined(__arm__)
 		FrameBufferAddr = (UINT32)(UINT64)gop->Mode->FrameBufferBase;

+ 148 - 0
gnuefi/crt0-efi-loongarch64.S

@@ -0,0 +1,148 @@
+/*
+ * crt0-efi-loongarch64.S - PE/COFF header for LOONGARCH64 EFI applications
+ *
+ * Copyright (C) 2021 Loongson Technology Corporation Limited. <zhoumingtao@loongson.cn>
+ * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice and this list of conditions, without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License as published by the Free Software Foundation;
+ * either version 2 of the License, or (at your option) any later version.
+ */
+
+	.section	.text.head
+
+	/*
+	 * Magic "MZ" signature for PE/COFF
+	 */
+	.globl	ImageBase
+ImageBase:
+	.ascii	"MZ"
+	.skip	58				// 'MZ' + pad + offset == 64
+	.long	pe_header - ImageBase		// Offset to the PE header.
+pe_header:
+	.ascii	"PE"
+	.short 	0
+coff_header:
+	.short	0x6264				// loongarch64 little endian
+	.short	2				// nr_sections
+	.long	0 				// TimeDateStamp
+	.long	0				// PointerToSymbolTable
+	.long	1				// NumberOfSymbols
+	.short	section_table - optional_header	// SizeOfOptionalHeader
+	.short	0x206				// Characteristics.
+						// IMAGE_FILE_DEBUG_STRIPPED |
+						// IMAGE_FILE_EXECUTABLE_IMAGE |
+						// IMAGE_FILE_LINE_NUMS_STRIPPED
+optional_header:
+	.short	0x20b				// PE32+ format
+	.byte	0x02				// MajorLinkerVersion
+	.byte	0x14				// MinorLinkerVersion
+	.long	_edata - _start			// SizeOfCode
+	.long	0				// SizeOfInitializedData
+	.long	0				// SizeOfUninitializedData
+	.long	_start - ImageBase		// AddressOfEntryPoint
+	.long	_start - ImageBase		// BaseOfCode
+
+extra_header_fields:
+	.quad	0				// ImageBase
+	.long	0x20				// SectionAlignment
+	.long	0x8				// FileAlignment
+	.short	0				// MajorOperatingSystemVersion
+	.short	0				// MinorOperatingSystemVersion
+	.short	0				// MajorImageVersion
+	.short	0				// MinorImageVersion
+	.short	0				// MajorSubsystemVersion
+	.short	0				// MinorSubsystemVersion
+	.long	0				// Win32VersionValue
+
+	.long	_edata - ImageBase		// SizeOfImage
+
+	// Everything before the kernel image is considered part of the header
+	.long	_start - ImageBase		// SizeOfHeaders
+	.long	0				// CheckSum
+	.short	EFI_SUBSYSTEM			// Subsystem
+	.short	0				// DllCharacteristics
+	.quad	0				// SizeOfStackReserve
+	.quad	0				// SizeOfStackCommit
+	.quad	0				// SizeOfHeapReserve
+	.quad	0				// SizeOfHeapCommit
+	.long	0				// LoaderFlags
+	.long	0x6				// NumberOfRvaAndSizes
+
+	.quad	0				// ExportTable
+	.quad	0				// ImportTable
+	.quad	0				// ResourceTable
+	.quad	0				// ExceptionTable
+	.quad	0				// CertificationTable
+	.quad	0				// BaseRelocationTable
+
+	// Section table
+section_table:
+
+	/*
+	 * The EFI application loader requires a relocation section
+	 * because EFI applications must be relocatable.  This is a
+	 * dummy section as far as we are concerned.
+	 */
+	.ascii	".reloc"
+	.byte	0
+	.byte	0			// end of 0 padding of section name
+	.long	0
+	.long	0
+	.long	0			// SizeOfRawData
+	.long	0			// PointerToRawData
+	.long	0			// PointerToRelocations
+	.long	0			// PointerToLineNumbers
+	.short	0			// NumberOfRelocations
+	.short	0			// NumberOfLineNumbers
+	.long	0x42100040		// Characteristics (section flags)
+
+
+	.ascii	".text"
+	.byte	0
+	.byte	0
+	.byte	0        		// end of 0 padding of section name
+	.long	_edata - _start		// VirtualSize
+	.long	_start - ImageBase	// VirtualAddress
+	.long	_edata - _start		// SizeOfRawData
+	.long	_start - ImageBase	// PointerToRawData
+
+	.long	0			// PointerToRelocations (0 for executables)
+	.long	0			// PointerToLineNumbers (0 for executables)
+	.short	0			// NumberOfRelocations  (0 for executables)
+	.short	0			// NumberOfLineNumbers  (0 for executables)
+	.long	0xe0500020		// Characteristics (section flags)
+
+	.align  4
+
+	.globl	_start
+	.type	_start, @function
+_start:
+	addi.d	  $sp, $sp, -24
+	st.d	  $ra, $sp, 0
+	st.d	  $a0, $sp, 8
+	st.d 	  $a1, $sp, 16
+
+	move	  $a2, $a0		// a2: ImageHandle
+	move	  $a3, $a1 		// a3: SystemTable
+	la.local  $a0, ImageBase	// a0: ImageBase
+	la.local  $a1, _DYNAMIC		// a1: DynamicSection
+	bl        _relocate
+	bnez	  $a0, 0f
+
+	ld.d	  $a0, $sp, 8
+	ld.d	  $a1, $sp, 16
+	bl 	  efi_main
+
+0:	ld.d	  $ra, $sp, 0
+	addi.d	  $sp, $sp, 24
+	jirl	  $ra, $ra, 0
+	.end	  _start

+ 63 - 0
gnuefi/elf_loongarch64_efi.lds

@@ -0,0 +1,63 @@
+OUTPUT_FORMAT("elf64-loongarch", "elf64-loongarch", "elf64-loongarch")
+OUTPUT_ARCH(loongarch)
+ENTRY(_start)
+SECTIONS
+{
+  .text 0x0 : {
+    _text = .;
+    *(.text.head)
+    *(.text)
+    *(.text.*)
+    *(.gnu.linkonce.t.*)
+    *(.srodata)
+    *(.rodata*)
+    . = ALIGN(16);
+  }
+  _etext = .;
+  _text_size = . - _text;
+  .dynamic  : { *(.dynamic) }
+  .data : ALIGN(4096)
+  {
+   _data = .;
+   *(.sdata)
+   *(.data)
+   *(.data1)
+   *(.data.*)
+   *(.got.plt)
+   *(.got)
+
+   /* the EFI loader doesn't seem to like a .bss section, so we stick
+      it all into .data: */
+   . = ALIGN(16);
+   _bss = .;
+   *(.sbss)
+   *(.scommon)
+   *(.dynbss)
+   *(.bss)
+   *(COMMON)
+   . = ALIGN(16);
+   _bss_end = .;
+  }
+
+  .rela.dyn : { *(.rela.dyn) }
+  .rela.plt : { *(.rela.plt) }
+  .rela.got : { *(.rela.got) }
+  .rela.data : { *(.rela.data) *(.rela.data*) }
+  . = ALIGN(512);
+  _edata = .;
+  _data_size = . - _data;
+
+  . = ALIGN(4096);
+  .dynsym   : { *(.dynsym) }
+  . = ALIGN(4096);
+  .dynstr   : { *(.dynstr) }
+  . = ALIGN(4096);
+  .note.gnu.build-id : { *(.note.gnu.build-id) }
+  /DISCARD/ :
+  {
+    *(.rel.reloc)
+    *(.eh_frame)
+    *(.note.GNU-stack)
+  }
+  .comment 0 : { *(.comment) }
+}

+ 104 - 0
gnuefi/reloc_loongarch64.c

@@ -0,0 +1,104 @@
+/* reloc_loongarch64.c - position independent loongarch64 ELF shared object relocator
+   Copyright (C) 2021 Loongson Technology Corporation Limited. <zhoumingtao@loongson.cn>
+   Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
+   Copyright (C) 1999 Hewlett-Packard Co.
+	Contributed by David Mosberger <davidm@hpl.hp.com>.
+
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials
+      provided with the distribution.
+    * Neither the name of Hewlett-Packard Co. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+    CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+    BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+    OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+    THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+    SUCH DAMAGE.
+*/
+
+#include <efi.h>
+#include <efilib.h>
+
+#include <elf.h>
+
+EFI_STATUS _relocate (long ldbase, Elf64_Dyn *dyn,
+                      EFI_HANDLE image EFI_UNUSED,
+                      EFI_SYSTEM_TABLE *systab EFI_UNUSED)
+{
+	long relsz = 0, relent = 0;
+	Elf64_Rela *rel = 0;
+	unsigned long *addr;
+	int i;
+
+	for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
+		switch (dyn[i].d_tag) {
+			case DT_RELA:
+				rel = (Elf64_Rela*)
+					((unsigned long)dyn[i].d_un.d_ptr
+					 + ldbase);
+				break;
+
+			case DT_RELASZ:
+				relsz = dyn[i].d_un.d_val;
+				break;
+
+			case DT_RELAENT:
+				relent = dyn[i].d_un.d_val;
+				break;
+
+			case DT_PLTGOT:
+				addr = (unsigned long *)
+					((unsigned long)dyn[i].d_un.d_ptr
+					 + ldbase);
+				break;
+
+			default:
+				break;
+		}
+	}
+
+	if (!rel && relent == 0)
+		return EFI_SUCCESS;
+
+	if (!rel || relent == 0)
+		return EFI_LOAD_ERROR;
+
+	while (relsz > 0) {
+		/* apply the relocs */
+		switch (ELF64_R_TYPE (rel->r_info)) {
+			case R_LARCH_NONE:
+				break;
+
+			case R_LARCH_RELATIVE:
+				addr = (unsigned long *)
+					(ldbase + rel->r_offset);
+				*addr += ldbase;
+				break;
+
+			default:
+				break;
+		}
+		rel = (Elf64_Rela*) ((char *) rel + relent);
+		relsz -= relent;
+	}
+	return EFI_SUCCESS;
+}

+ 2 - 0
inc/efi.h

@@ -52,6 +52,8 @@ Revision History
 #include "mips64el/efibind.h"
 #elif defined (__riscv) && __riscv_xlen == 64
 #include "riscv64/efibind.h"
+#elif defined (__loongarch64)
+#include "loongarch64/efibind.h"
 #else
 #error Usupported architecture
 #endif

+ 2 - 0
inc/efilib.h

@@ -35,6 +35,8 @@ Revision History
 #include "mips64el/efilibplat.h"
 #elif defined (__riscv) && __riscv_xlen == 64
 #include "riscv64/efilibplat.h"
+#elif defined (__loongarch64)
+#include "loongarch64/efilibplat.h"
 #endif
 #include "efilink.h"
 #include "efirtlib.h"

+ 157 - 0
inc/loongarch64/efibind.h

@@ -0,0 +1,157 @@
+/*
+ * Copright (C) 2014 - 2015 Linaro Ltd.
+ * Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ * Copright (C) 2017 Lemote Co.
+ * Author: Heiher <r@hev.cc>
+ * Copright (C) 2021 Loongson Technology Corporation Limited.
+ * Author: zhoumingtao <zhoumingtao@loongson.cn>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice and this list of conditions, without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License as published by the Free Software Foundation;
+ * either version 2 of the License, or (at your option) any later version.
+ */
+
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L ) && !defined(__cplusplus)
+
+// ANSI C 1999/2000 stdint.h integer width declarations
+
+typedef unsigned long       uint64_t;
+typedef long                int64_t;
+typedef unsigned int        uint32_t;
+typedef int                 int32_t;
+typedef unsigned short      uint16_t;
+typedef short               int16_t;
+typedef unsigned char       uint8_t;
+typedef signed char         int8_t;   // unqualified 'char' is unsigned on ARM
+typedef uint64_t            uintptr_t;
+typedef int64_t             intptr_t;
+
+#else
+#include <stdint.h>
+#endif
+
+//
+// Basic EFI types of various widths
+//
+
+#ifndef __WCHAR_TYPE__
+# define __WCHAR_TYPE__ short
+#endif
+
+typedef uint64_t   UINT64;
+typedef int64_t    INT64;
+
+typedef uint32_t   UINT32;
+typedef int32_t    INT32;
+
+typedef uint16_t   UINT16;
+typedef int16_t    INT16;
+typedef uint8_t    UINT8;
+typedef int8_t     INT8;
+typedef __WCHAR_TYPE__ WCHAR;
+
+#undef VOID
+#define VOID    void
+
+typedef int64_t    INTN;
+typedef uint64_t   UINTN;
+
+#define EFIERR(a)           (0x8000000000000000 | a)
+#define EFI_ERROR_MASK      0x8000000000000000
+#define EFIERR_OEM(a)       (0xc000000000000000 | a)
+
+#define BAD_POINTER         0xFBFBFBFBFBFBFBFB
+#define MAX_ADDRESS         0xFFFFFFFFFFFFFFFF
+
+#define BREAKPOINT()        while (TRUE);    // Make it hang on Bios[Dbg]32
+
+//
+// Pointers must be aligned to these address to function
+//
+
+#define MIN_ALIGNMENT_SIZE  8
+
+#define ALIGN_VARIABLE(Value ,Adjustment) \
+            (UINTN)Adjustment = 0; \
+            if((UINTN)Value % MIN_ALIGNMENT_SIZE) \
+                (UINTN)Adjustment = MIN_ALIGNMENT_SIZE - ((UINTN)Value % MIN_ALIGNMENT_SIZE); \
+            Value = (UINTN)Value + (UINTN)Adjustment
+
+
+//
+// Define macros to build data structure signatures from characters.
+//
+
+#define EFI_SIGNATURE_16(A,B)             ((A) | (B<<8))
+#define EFI_SIGNATURE_32(A,B,C,D)         (EFI_SIGNATURE_16(A,B)     | (EFI_SIGNATURE_16(C,D)     << 16))
+#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32))
+
+//
+// EFIAPI - prototype calling convention for EFI function pointers
+// BOOTSERVICE - prototype for implementation of a boot service interface
+// RUNTIMESERVICE - prototype for implementation of a runtime service interface
+// RUNTIMEFUNCTION - prototype for implementation of a runtime function that is not a service
+// RUNTIME_CODE - pragma macro for declaring runtime code
+//
+
+#ifndef EFIAPI          // Forces EFI calling conventions reguardless of compiler options
+#define EFIAPI          // Substitute expresion to force C calling convention
+#endif
+
+#define BOOTSERVICE
+#define RUNTIMESERVICE
+#define RUNTIMEFUNCTION
+
+
+#define RUNTIME_CODE(a)         alloc_text("rtcode", a)
+#define BEGIN_RUNTIME_DATA()    data_seg("rtdata")
+#define END_RUNTIME_DATA()      data_seg("")
+
+#define VOLATILE                volatile
+
+#define MEMORY_FENCE            __sync_synchronize
+
+//
+// When build similiar to FW, then link everything together as
+// one big module.
+//
+
+#define EFI_DRIVER_ENTRY_POINT(InitFunction)    \
+    UINTN                                       \
+    InitializeDriver (                          \
+        VOID    *ImageHandle,                   \
+        VOID    *SystemTable                    \
+        )                                       \
+    {                                           \
+        return InitFunction(ImageHandle,        \
+                SystemTable);                   \
+    }                                           \
+                                                \
+    EFI_STATUS efi_main(                        \
+        EFI_HANDLE image,                       \
+        EFI_SYSTEM_TABLE *systab                \
+        ) __attribute__((weak,                  \
+                alias ("InitializeDriver")));
+
+#define LOAD_INTERNAL_DRIVER(_if, type, name, entry)    \
+        (_if)->LoadInternal(type, name, entry)
+
+
+//
+// Some compilers don't support the forward reference construct:
+//  typedef struct XXXXX
+//
+// The following macro provide a workaround for such cases.
+
+#define INTERFACE_DECL(x) struct x
+
+#define uefi_call_wrapper(func, va_num, ...) func(__VA_ARGS__)
+#define EFI_FUNCTION

+ 24 - 0
inc/loongarch64/efilibplat.h

@@ -0,0 +1,24 @@
+/*++
+
+Copyright (c) 1998  Intel Corporation
+
+Module Name:
+
+    efilibplat.h
+
+Abstract:
+
+    EFI to compile bindings
+
+
+
+
+Revision History
+
+--*/
+
+VOID
+InitializeLibPlatform (
+    IN EFI_HANDLE           ImageHandle,
+    IN EFI_SYSTEM_TABLE     *SystemTable
+    );

+ 23 - 0
inc/loongarch64/efisetjmp_arch.h

@@ -0,0 +1,23 @@
+#ifndef GNU_EFI_LOONGARCH64_SETJMP_H
+#define GNU_EFI_LOONGARCH64_SETJMP_H
+
+#define JMPBUF_ALIGN 8
+
+typedef struct {
+	/* GP regs */
+	UINT64	RA;
+	UINT64	SP;
+	UINT64	FP;
+
+	UINT64	S0;
+	UINT64	S1;
+	UINT64	S2;
+	UINT64	S3;
+	UINT64	S4;
+	UINT64	S5;
+	UINT64	S6;
+	UINT64	S7;
+	UINT64	S8;
+} ALIGN(JMPBUF_ALIGN) jmp_buf[1];
+
+#endif /* GNU_EFI_LOONGARCH64_SETJMP_H */

+ 1 - 1
lib/Makefile

@@ -64,7 +64,7 @@ endif
 
 OBJS  = $(FILES:%=%.o)
 
-SUBDIRS = ia32 x86_64 ia64 aarch64 arm mips64el riscv64 runtime
+SUBDIRS = ia32 x86_64 ia64 aarch64 arm mips64el riscv64 loongarch64 runtime
 
 LIBDIRINSTALL = $(INSTALLROOT)$(LIBDIR)
 

+ 1 - 0
lib/loongarch64/efi_stub.S

@@ -0,0 +1 @@
+/* This stub is a stub to make the build happy */

+ 26 - 0
lib/loongarch64/initplat.c

@@ -0,0 +1,26 @@
+/*
+ * Copright (C) 2014 Linaro Ltd.
+ * Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice and this list of conditions, without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License as published by the Free Software Foundation;
+ * either version 2 of the License, or (at your option) any later version.
+ */
+
+#include "lib.h"
+
+VOID
+InitializeLibPlatform (
+    IN EFI_HANDLE           ImageHandle EFI_UNUSED,
+    IN EFI_SYSTEM_TABLE     *SystemTable EFI_UNUSED
+    )
+{
+}

+ 63 - 0
lib/loongarch64/math.c

@@ -0,0 +1,63 @@
+/*
+ * Copright (C) 2014 Linaro Ltd.
+ * Author: Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice and this list of conditions, without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License as published by the Free Software Foundation;
+ * either version 2 of the License, or (at your option) any later version.
+ */
+
+#include "lib.h"
+
+UINT64
+LShiftU64 (
+    IN UINT64   Operand,
+    IN UINTN    Count
+    )
+// Left shift 64bit by 32bit and get a 64bit result
+{
+    return Operand << Count;
+}
+
+UINT64
+RShiftU64 (
+    IN UINT64   Operand,
+    IN UINTN    Count
+    )
+// Right shift 64bit by 32bit and get a 64bit result
+{
+    return Operand >> Count;
+}
+
+
+UINT64
+MultU64x32 (
+    IN UINT64   Multiplicand,
+    IN UINTN    Multiplier
+    )
+// Multiple 64bit by 32bit and get a 64bit result
+{
+    return Multiplicand * Multiplier;
+}
+
+UINT64
+DivU64x32 (
+    IN UINT64   Dividend,
+    IN UINTN    Divisor,
+    OUT UINTN   *Remainder OPTIONAL
+    )
+// divide 64bit by 32bit and get a 64bit result
+// N.B. only works for 31bit divisors!!
+{
+    if (Remainder)
+	*Remainder = Dividend % Divisor;
+    return Dividend / Divisor;
+}

+ 68 - 0
lib/loongarch64/setjmp.S

@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.
+ * Copyright (c) 2021 Loongson Technology Corporation Limited.All rights
+ * reserved.
+ * Author: zhoumingtao <zhoumingtao@loongson.cn>
+ *
+ * This program and the accompanying materials are licensed and made
+ * available
+ * under the terms and conditions of the BSD License which accompanies
+ * this
+ * distribution.  The full text of the license may be found at
+ * http://opensource.org/licenses/bsd-license.php.
+ *
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS"
+ * BASIS,
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
+ * IMPLIED.
+ */
+
+	.text
+	.p2align 3
+
+/*
+   int setjmp(jmp_buf env);
+*/
+	.globl	setjmp
+	.type	setjmp, @function
+setjmp:
+	st.d $ra, $a0, 0x0
+	st.d $sp, $a0, 0x8
+	st.d $fp, $a0, 0x10
+	st.d $s0, $a0, 0x18
+	st.d $s1, $a0, 0x20
+	st.d $s2, $a0, 0x28
+	st.d $s3, $a0, 0x30
+	st.d $s4, $a0, 0x38
+	st.d $s5, $a0, 0x40
+	st.d $s6, $a0, 0x48
+	st.d $s7, $a0, 0x50
+	st.d $s8, $a0, 0x58
+
+	move $a0, $zero
+	jirl $zero,$ra,0
+
+/*
+   void longjmp(jmp_buf env, int val);
+*/
+	.globl	longjmp
+	.type	longjmp, @function
+longjmp:
+	ld.d $ra, $a0, 0x0
+	ld.d $sp, $a0, 0x8
+	ld.d $fp, $a0, 0x10
+	ld.d $s0, $a0, 0x18
+	ld.d $s1, $a0, 0x20
+	ld.d $s2, $a0, 0x28
+	ld.d $s3, $a0, 0x30
+	ld.d $s4, $a0, 0x38
+	ld.d $s5, $a0, 0x40
+	ld.d $s6, $a0, 0x48
+	ld.d $s7, $a0, 0x50
+	ld.d $s8, $a0, 0x58
+
+	addi.d $a0, $zero, 1	# a0 = 1
+	beqz $a1, .L0		# if (a1 == 0); goto L0
+	move $a0, $a1		# a0 = a1
+.L0:
+	jirl $zero,$ra,0