grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] mips64: Add support for 64-bit MIPS.
@ 2017-02-13 15:57 wangr
  2017-02-13 19:01 ` Andrei Borzenkov
  0 siblings, 1 reply; 6+ messages in thread
From: wangr @ 2017-02-13 15:57 UTC (permalink / raw)
  To: grub-devel; +Cc: Heiher

From: Heiher <r@hev.cc>

---
 configure.ac                        |  21 ++-
 gentpl.py                           |   5 +-
 grub-core/Makefile.am               |   6 +
 grub-core/Makefile.core.def         |  13 ++
 grub-core/kern/mips64/cache.S       |  23 ++++
 grub-core/kern/mips64/dl.c          | 150 +++++++++++++++++++++
 grub-core/kern/mips64/efi/init.c    |  44 ++++++
 grub-core/kern/mips64/efi/startup.S |  47 +++++++
 grub-core/kern/mips64/init.c        |  47 +++++++
 grub-core/lib/efi/halt.c            |   2 +-
 grub-core/lib/mips64/setjmp.S       |  69 ++++++++++
 grub-core/lib/setjmp.S              |   4 +
 grub-core/term/serial.c             |   8 +-
 include/grub/cache.h                |   2 +-
 include/grub/dl.h                   |   8 +-
 include/grub/efi/api.h              |   2 +-
 include/grub/efi/pe32.h             |   5 +
 include/grub/mips64/asm.h           |  10 ++
 include/grub/mips64/efi/boot.h      |   0
 include/grub/mips64/efi/loader.h    |  25 ++++
 include/grub/mips64/efi/memory.h    |   6 +
 include/grub/mips64/efi/time.h      |   0
 include/grub/mips64/io.h            |  62 +++++++++
 include/grub/mips64/kernel.h        |  24 ++++
 include/grub/mips64/memory.h        |  56 ++++++++
 include/grub/mips64/mips.h          |  30 +++++
 include/grub/mips64/setjmp.h        |  27 ++++
 include/grub/mips64/time.h          |  39 ++++++
 include/grub/mips64/types.h         |  38 ++++++
 include/grub/misc.h                 |   2 +-
 include/grub/serial.h               |   6 +-
 include/grub/util/install.h         |   1 +
 util/grub-install-common.c          |   1 +
 util/grub-install.c                 |  18 +++
 util/grub-mkimagexx.c               | 259 ++++++++++++++++++++++++++++++++++--
 util/grub-mknetdir.c                |   3 +-
 util/grub-mkrescue.c                |   9 +-
 util/grub-module-verifier.c         |  13 ++
 util/grub-module-verifierXX.c       |  11 +-
 util/mkimage.c                      |  16 +++
 40 files changed, 1078 insertions(+), 34 deletions(-)
 create mode 100644 grub-core/kern/mips64/cache.S
 create mode 100644 grub-core/kern/mips64/dl.c
 create mode 100644 grub-core/kern/mips64/efi/init.c
 create mode 100644 grub-core/kern/mips64/efi/startup.S
 create mode 100644 grub-core/kern/mips64/init.c
 create mode 100644 grub-core/lib/mips64/setjmp.S
 create mode 100644 include/grub/mips64/asm.h
 create mode 100644 include/grub/mips64/efi/boot.h
 create mode 100644 include/grub/mips64/efi/loader.h
 create mode 100644 include/grub/mips64/efi/memory.h
 create mode 100644 include/grub/mips64/efi/time.h
 create mode 100644 include/grub/mips64/io.h
 create mode 100644 include/grub/mips64/kernel.h
 create mode 100644 include/grub/mips64/memory.h
 create mode 100644 include/grub/mips64/mips.h
 create mode 100644 include/grub/mips64/setjmp.h
 create mode 100644 include/grub/mips64/time.h
 create mode 100644 include/grub/mips64/types.h

diff --git a/configure.ac b/configure.ac
index 0893ad60c..fa017bc37 100644
--- a/configure.ac
+++ b/configure.ac
@@ -86,7 +86,11 @@ case "$target_cpu" in
   i[[3456]]86)	target_cpu=i386 ;;
   amd64)	target_cpu=x86_64 ;;
   sparc)	target_cpu=sparc64 ;;
-  mipsel|mips64el)
+  mips64el)
+                target_cpu=mips64el
+		machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_MIPS64EL=1"
+		;;
+  mipsel)
                 target_cpu=mipsel
 		machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_MIPSEL=1"
 		;;
@@ -118,6 +122,7 @@ if test "x$with_platform" = x; then
     powerpc64-*) platform=ieee1275 ;;
     powerpc64le-*) platform=ieee1275 ;;
     sparc64-*) platform=ieee1275 ;;
+    mips64el-*) platform=efi;;
     mipsel-*) platform=loongson ;;
     mips-*) platform=arc ;;
     ia64-*) platform=efi ;;
@@ -166,6 +171,7 @@ case "$target_cpu"-"$platform" in
   mipsel-yeeloong) platform=loongson ;;
   mipsel-fuloong) platform=loongson ;;
   mipsel-loongson) ;;
+  mips64el-efi) ;;
   arm-uboot) ;;
   arm-efi) ;;
   arm64-efi) ;;
@@ -1234,10 +1240,15 @@ grub_CHECK_PIC
 # movk's which aren't representable.
 # Since default varies across dictributions use either -fPIC or -fno-PIC
 # explicitly.
-if ( test x$target_cpu = xmips || test x$target_cpu = xmipsel || test x$target_cpu = xarm64 ) && test "x$grub_cv_cc_target_clang" = xyes ; then
+if ( test x$target_cpu = xmips || test x$target_cpu = xmipsel || test x$target_cpu = xarm64 || test x$target_cpu = xmips64el ) && test "x$grub_cv_cc_target_clang" = xyes ; then
    TARGET_CFLAGS="$TARGET_CFLAGS -fPIC"
 elif [ x"$pic_possible" = xyes ]; then
    TARGET_CFLAGS="$TARGET_CFLAGS -fno-PIC"
+fi
+# Don't generate SVR4-style position-independent code for MIPS64.
+if test x$target_cpu = xmips64el ; then
+   TARGET_CFLAGS="$TARGET_CFLAGS -mno-abicalls"
+   TARGET_CCASFLAGS="$TARGET_CCASFLAGS -mno-abicalls"
 fi]
 
 CFLAGS="$TARGET_CFLAGS"
@@ -1894,12 +1905,14 @@ AM_CONDITIONAL([COND_i386_multiboot], [test x$target_cpu = xi386 -a x$platform =
 AM_CONDITIONAL([COND_x86_64_efi], [test x$target_cpu = xx86_64 -a x$platform = xefi])
 AM_CONDITIONAL([COND_i386_xen], [test x$target_cpu = xi386 -a x$platform = xxen])
 AM_CONDITIONAL([COND_x86_64_xen], [test x$target_cpu = xx86_64 -a x$platform = xxen])
+AM_CONDITIONAL([COND_mips64_efi], [test x$target_cpu = xmips64el -a x$platform = xefi])
 AM_CONDITIONAL([COND_mips_loongson], [test x$target_cpu = xmipsel -a x$platform = xloongson])
 AM_CONDITIONAL([COND_mips_qemu_mips], [test "(" x$target_cpu = xmips -o x$target_cpu = xmipsel ")"  -a x$platform = xqemu_mips])
 AM_CONDITIONAL([COND_mips_arc], [test "(" x$target_cpu = xmips -o x$target_cpu = xmipsel ")"  -a x$platform = xarc])
 AM_CONDITIONAL([COND_sparc64_ieee1275], [test x$target_cpu = xsparc64 -a x$platform = xieee1275])
 AM_CONDITIONAL([COND_sparc64_emu], [test x$target_cpu = xsparc64 -a x$platform = xemu])
 AM_CONDITIONAL([COND_powerpc_ieee1275], [test x$target_cpu = xpowerpc -a x$platform = xieee1275])
+AM_CONDITIONAL([COND_mips64el], [test x$target_cpu = xmips64el])
 AM_CONDITIONAL([COND_mips], [test x$target_cpu = xmips -o x$target_cpu = xmipsel])
 AM_CONDITIONAL([COND_mipsel], [test x$target_cpu = xmipsel])
 AM_CONDITIONAL([COND_mipseb], [test x$target_cpu = xmips])
@@ -1956,7 +1969,9 @@ AC_DEFINE_UNQUOTED(GRUB_SYSCONFDIR, "$grub_sysconfdir", [Configuration dir])
 # Output files.
 if test "$platform" != none; then
   cpudir="${target_cpu}"
-  if test x${cpudir} = xmipsel; then
+  if test x${cpudir} = xmips64el; then
+    cpudir=mips64;
+  elif test x${cpudir} = xmipsel; then
     cpudir=mips;
   fi
   grub_CHECK_LINK_DIR
diff --git a/gentpl.py b/gentpl.py
index f08bcc404..e9ec540ca 100644
--- a/gentpl.py
+++ b/gentpl.py
@@ -29,7 +29,7 @@ import re
 GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
                    "i386_multiboot", "i386_ieee1275", "x86_64_efi",
                    "i386_xen", "x86_64_xen",
-                   "mips_loongson", "sparc64_ieee1275",
+                   "mips_loongson", "mips64_efi", "sparc64_ieee1275",
                    "powerpc_ieee1275", "mips_arc", "ia64_efi",
                    "mips_qemu_mips", "arm_uboot", "arm_efi", "arm64_efi" ]
 
@@ -42,13 +42,14 @@ GROUPS["i386"]     = [ "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", "i38
 GROUPS["x86_64"]   = [ "x86_64_efi" ]
 GROUPS["x86"]      = GROUPS["i386"] + GROUPS["x86_64"]
 GROUPS["mips"]     = [ "mips_loongson", "mips_qemu_mips", "mips_arc" ]
+GROUPS["mips64"]   = [ "mips64_efi" ]
 GROUPS["sparc64"]  = [ "sparc64_ieee1275" ]
 GROUPS["powerpc"]  = [ "powerpc_ieee1275" ]
 GROUPS["arm"]      = [ "arm_uboot", "arm_efi" ]
 GROUPS["arm64"]    = [ "arm64_efi" ]
 
 # Groups based on firmware
-GROUPS["efi"]  = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi" ]
+GROUPS["efi"]  = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi", "mips64_efi" ]
 GROUPS["ieee1275"]   = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ]
 GROUPS["uboot"] = [ "arm_uboot" ]
 GROUPS["xen"]  = [ "i386_xen", "x86_64_xen" ]
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
index 04e9395fd..5512f274f 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -216,6 +216,12 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h
 KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h
 endif
 
+if COND_mips64_efi
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h
+endif
+
 if COND_powerpc_ieee1275
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 2dfa22a92..e23782c1f 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -93,6 +93,9 @@ kernel = {
   arm_uboot_ldflags       = '-Wl,-r,-d';
   arm_uboot_stripflags    = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
 
+  mips64_efi_ldflags          = '-Wl,-r,-d';
+  mips64_efi_stripflags       = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame -R .MIPS.abiflags';
+
   i386_pc_startup = kern/i386/pc/startup.S;
   i386_efi_startup = kern/i386/efi/startup.S;
   x86_64_efi_startup = kern/x86_64/efi/startup.S;
@@ -103,6 +106,7 @@ kernel = {
   i386_coreboot_startup = kern/i386/coreboot/startup.S;
   i386_multiboot_startup = kern/i386/coreboot/startup.S;
   mips_startup = kern/mips/startup.S;
+  mips64_efi_startup = kern/mips64/efi/startup.S;
   sparc64_ieee1275_startup = kern/sparc64/ieee1275/crt0.S;
   powerpc_ieee1275_startup = kern/powerpc/ieee1275/startup.S;
   arm_uboot_startup = kern/arm/uboot/startup.S;
@@ -263,6 +267,12 @@ kernel = {
   extra_dist = video/sis315_init.c;
   mips_loongson = commands/keylayouts.c;
 
+  mips64 = kern/mips64/init.c;
+  mips64 = kern/mips64/dl.c;
+  mips64 = kern/mips64/cache.S;
+  mips64 = kern/generic/rtc_get_time_ms.c;
+  mips64_efi = kern/mips64/efi/init.c;
+
   powerpc_ieee1275 = kern/powerpc/cache.S;
   powerpc_ieee1275 = kern/powerpc/dl.c;
   powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
@@ -750,6 +760,7 @@ module = {
   enable = sparc64_ieee1275;
   enable = powerpc_ieee1275;
   enable = mips_arc;
+  enable = mips64_efi;
   enable = ia64_efi;
   enable = arm_efi;
   enable = arm64_efi;
@@ -853,6 +864,7 @@ module = {
   mips_arc = lib/mips/arc/reboot.c;
   mips_loongson = lib/mips/loongson/reboot.c;
   mips_qemu_mips = lib/mips/qemu_mips/reboot.c;
+  mips64_efi = lib/efi/reboot.c;
   xen = lib/xen/reboot.c;
   uboot = lib/uboot/reboot.c;
   common = commands/reboot.c;
@@ -1762,6 +1774,7 @@ module = {
   enable = arm_efi;
   enable = arm64_efi;
   enable = mips;
+  enable = mips64_efi;
 };
 
 module = {
diff --git a/grub-core/kern/mips64/cache.S b/grub-core/kern/mips64/cache.S
new file mode 100644
index 000000000..c1fb4d44a
--- /dev/null
+++ b/grub-core/kern/mips64/cache.S
@@ -0,0 +1,23 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009,2017  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+FUNCTION (grub_arch_sync_caches)
+	jr.hb	$ra
+
diff --git a/grub-core/kern/mips64/dl.c b/grub-core/kern/mips64/dl.c
new file mode 100644
index 000000000..7c6a0833b
--- /dev/null
+++ b/grub-core/kern/mips64/dl.c
@@ -0,0 +1,150 @@
+/* dl-mips64.c - arch-dependent part of loadable module support */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2005,2007,2009,2017  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/elf.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+#include <grub/cpu/types.h>
+#include <grub/mm.h>
+#include <grub/i18n.h>
+
+/* Check if EHDR is a valid ELF header.  */
+grub_err_t
+grub_arch_dl_check_header (void *ehdr)
+{
+  Elf_Ehdr *e = ehdr;
+
+  /* Check the magic numbers.  */
+#ifdef GRUB_CPU_WORDS_BIGENDIAN
+  if (e->e_ident[EI_CLASS] != ELFCLASS64
+      || e->e_ident[EI_DATA] != ELFDATA2MSB
+      || e->e_machine != EM_MIPS)
+#else
+  if (e->e_ident[EI_CLASS] != ELFCLASS64
+      || e->e_ident[EI_DATA] != ELFDATA2LSB
+      || e->e_machine != EM_MIPS)
+#endif
+    return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic"));
+
+  return GRUB_ERR_NONE;
+}
+
+#pragma GCC diagnostic ignored "-Wcast-align"
+
+grub_err_t
+grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)),
+				 grub_size_t *tramp, grub_size_t *got)
+{
+  *tramp = 0;
+  *got = 0;
+  return GRUB_ERR_NONE;
+}
+
+/* Relocate symbols.  */
+grub_err_t
+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
+			       Elf_Shdr *s, grub_dl_segment_t seg)
+{
+  Elf_Ehdr *e = ehdr;
+  Elf_Rel *rel, *max;
+
+  for (rel = (Elf_Rel *) ((char *) e + s->sh_offset),
+	 max = (Elf_Rel *) ((char *) rel + s->sh_size);
+       rel < max;
+       rel = (Elf_Rel *) ((char *) rel + s->sh_entsize))
+    {
+      grub_uint8_t *addr;
+      Elf_Sym *sym;
+      Elf_Addr r_info;
+      grub_uint64_t sym_value;
+
+      if (seg->size < rel->r_offset)
+	return grub_error (GRUB_ERR_BAD_MODULE,
+			   "reloc offset is out of the segment");
+
+      r_info = ((grub_uint64_t) rel->r_info << 32) |
+              (grub_uint32_t) grub_be_to_cpu64 (rel->r_info);
+
+      addr = (grub_uint8_t *) ((char *) seg->addr + rel->r_offset);
+      sym = (Elf_Sym *) ((char *) mod->symtab
+			 + mod->symsize * ELF_R_SYM (r_info));
+      sym_value = sym->st_value;
+      if (s->sh_type == SHT_RELA)
+	{
+	  sym_value += ((Elf_Rela *) rel)->r_addend;
+	}
+      switch (ELF_R_TYPE (r_info))
+	{
+	case R_MIPS_64:
+	  *(grub_uint64_t *) addr += sym_value;
+	  break;
+	case R_MIPS_32:
+	  *(grub_uint32_t *) addr += sym_value;
+	  break;
+	case R_MIPS_26:
+	  {
+	    grub_uint32_t value;
+	    grub_uint32_t raw;
+	    raw = (*(grub_uint32_t *) addr) & 0x3ffffff;
+	    value = raw << 2;
+	    value += sym_value;
+	    raw = (value >> 2) & 0x3ffffff;
+
+	    *(grub_uint32_t *) addr =
+	      raw | ((*(grub_uint32_t *) addr) & 0xfc000000);
+	  }
+	  break;
+	case R_MIPS_LO16:
+#ifdef GRUB_CPU_WORDS_BIGENDIAN
+	  addr += 2;
+#endif
+	  *(grub_uint16_t *) addr = (grub_int16_t) sym_value;
+	  break;
+	case R_MIPS_HI16:
+#ifdef GRUB_CPU_WORDS_BIGENDIAN
+	  addr += 2;
+#endif
+	  *(grub_uint16_t *) addr = (grub_int16_t) ((sym_value + 0x8000UL) >> 16);
+	  break;
+	case R_MIPS_HIGHER:
+#ifdef GRUB_CPU_WORDS_BIGENDIAN
+	  addr += 2;
+#endif
+	  *(grub_uint16_t *) addr = (grub_int16_t) ((sym_value + 0x80008000UL) >> 32);
+	  break;
+	case R_MIPS_HIGHEST:
+#ifdef GRUB_CPU_WORDS_BIGENDIAN
+	  addr += 2;
+#endif
+	  *(grub_uint16_t *) addr = (grub_uint16_t) ((sym_value + 0x800080008000UL) >> 48);
+	  break;
+	default:
+	  {
+	    return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+			       N_("relocation 0x%x is not implemented yet"),
+			       ELF_R_TYPE (r_info));
+	  }
+	  break;
+	}
+    }
+
+  return GRUB_ERR_NONE;
+}
+
diff --git a/grub-core/kern/mips64/efi/init.c b/grub-core/kern/mips64/efi/init.c
new file mode 100644
index 000000000..074736db9
--- /dev/null
+++ b/grub-core/kern/mips64/efi/init.c
@@ -0,0 +1,44 @@
+/* init.c - initialize an arm-based EFI system */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/env.h>
+#include <grub/kernel.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/cpu/time.h>
+#include <grub/efi/efi.h>
+#include <grub/loader.h>
+
+void
+grub_machine_init (void)
+{
+  grub_efi_init ();
+
+  /* FIXME: Get cpuclock from EFI. */
+  grub_timer_init (1000000000U);
+}
+
+void
+grub_machine_fini (int flags)
+{
+  if (!(flags & GRUB_LOADER_FLAG_NORETURN))
+    return;
+
+  grub_efi_fini ();
+}
diff --git a/grub-core/kern/mips64/efi/startup.S b/grub-core/kern/mips64/efi/startup.S
new file mode 100644
index 000000000..4fee9bee1
--- /dev/null
+++ b/grub-core/kern/mips64/efi/startup.S
@@ -0,0 +1,47 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+	.file 	"startup.S"
+	.text
+
+	.set		push
+	.align		4
+
+FUNCTION(_start)
+	/*
+	 *  EFI_SYSTEM_TABLE and EFI_HANDLE are passed in a1/a0.
+	 */
+	daddiu		$sp, -16
+	sd		$ra, ($sp)
+
+	dla		$a2, grub_efi_image_handle
+	sd		$a0, ($a2)
+	dla		$a2, grub_efi_system_table
+	sd		$a1, ($a2)
+
+	jal		grub_main
+
+1:
+	ld		$ra, ($sp)
+	daddiu		$sp, 16
+	jr		$ra
+
+	.set		pop
+
diff --git a/grub-core/kern/mips64/init.c b/grub-core/kern/mips64/init.c
new file mode 100644
index 000000000..8fd0a88a5
--- /dev/null
+++ b/grub-core/kern/mips64/init.c
@@ -0,0 +1,47 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009,2017  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/kernel.h>
+#include <grub/env.h>
+#include <grub/time.h>
+#include <grub/cpu/mips.h>
+
+grub_uint32_t grub_arch_cpuclock;
+
+/* FIXME: use interrupt to count high.  */
+grub_uint64_t
+grub_get_rtc (void)
+{
+  static grub_uint32_t high = 0;
+  static grub_uint32_t last = 0;
+  grub_uint32_t low;
+
+  asm volatile ("mfc0 %0, " GRUB_CPU_MIPS_COP0_TIMER_COUNT : "=r" (low));
+  if (low < last)
+    high++;
+  last = low;
+
+  return (((grub_uint64_t) high) << 32) | low;
+}
+
+void
+grub_timer_init (grub_uint32_t cpuclock)
+{
+  grub_arch_cpuclock = cpuclock;
+  grub_install_get_time_ms (grub_rtc_get_time_ms);
+}
diff --git a/grub-core/lib/efi/halt.c b/grub-core/lib/efi/halt.c
index e9441c844..3c4453922 100644
--- a/grub-core/lib/efi/halt.c
+++ b/grub-core/lib/efi/halt.c
@@ -29,7 +29,7 @@ void
 grub_halt (void)
 {
   grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
-#if !defined(__ia64__) && !defined(__arm__) && !defined(__aarch64__)
+#if !defined(__ia64__) && !defined(__arm__) && !defined(__aarch64__) && !defined(__mips__)
   grub_acpi_halt ();
 #endif
   efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
diff --git a/grub-core/lib/mips64/setjmp.S b/grub-core/lib/mips64/setjmp.S
new file mode 100644
index 000000000..99ae22c18
--- /dev/null
+++ b/grub-core/lib/mips64/setjmp.S
@@ -0,0 +1,69 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003,2007,2009  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+#include <grub/dl.h>
+#include <grub/mips64/asm.h>
+
+	.file	"setjmp.S"
+
+GRUB_MOD_LICENSE "GPLv3+"
+
+	.text
+
+/*
+ * int grub_setjmp (grub_jmp_buf env)
+ */
+FUNCTION(grub_setjmp)
+	GRUB_ASM_REG_S $s0, 0($a0)
+	GRUB_ASM_REG_S $s1, 8($a0)
+	GRUB_ASM_REG_S $s2, 16($a0)
+	GRUB_ASM_REG_S $s3, 24($a0)
+	GRUB_ASM_REG_S $s4, 32($a0)
+	GRUB_ASM_REG_S $s5, 40($a0)
+	GRUB_ASM_REG_S $s6, 48($a0)
+	GRUB_ASM_REG_S $s7, 56($a0)
+	GRUB_ASM_REG_S $s8, 64($a0)
+	GRUB_ASM_REG_S $gp, 72($a0)
+	GRUB_ASM_REG_S $sp, 80($a0)
+	GRUB_ASM_REG_S $ra, 88($a0)
+	move $v0, $zero
+	move $v1, $zero
+	jr $ra
+	 nop
+/*
+ * int grub_longjmp (grub_jmp_buf env, int val)
+ */
+FUNCTION(grub_longjmp)
+	GRUB_ASM_REG_L $s0, 0($a0)
+	GRUB_ASM_REG_L $s1, 8($a0)
+	GRUB_ASM_REG_L $s2, 16($a0)
+	GRUB_ASM_REG_L $s3, 24($a0)
+	GRUB_ASM_REG_L $s4, 32($a0)
+	GRUB_ASM_REG_L $s5, 40($a0)
+	GRUB_ASM_REG_L $s6, 48($a0)
+	GRUB_ASM_REG_L $s7, 56($a0)
+	GRUB_ASM_REG_L $s8, 64($a0)
+	GRUB_ASM_REG_L $gp, 72($a0)
+	GRUB_ASM_REG_L $sp, 80($a0)
+	GRUB_ASM_REG_L $ra, 88($a0)
+	addiu $v0, $zero, 1
+	movn $v0, $a1, $a1
+	move $v1, $zero
+	jr $ra
+	 nop
diff --git a/grub-core/lib/setjmp.S b/grub-core/lib/setjmp.S
index f6e4905e2..8799fa133 100644
--- a/grub-core/lib/setjmp.S
+++ b/grub-core/lib/setjmp.S
@@ -5,7 +5,11 @@
 #elif defined(__sparc__)
 #include "./sparc64/setjmp.S"
 #elif defined(__mips__)
+#if _MIPS_SIM == _ABI64
+#include "./mips64/setjmp.S"
+#else
 #include "./mips/setjmp.S"
+#endif
 #elif defined(__powerpc__) || defined(__PPC__)
 #include "./powerpc/setjmp.S"
 #elif defined(__ia64__)
diff --git a/grub-core/term/serial.c b/grub-core/term/serial.c
index db80b3ba0..3b2e01c93 100644
--- a/grub-core/term/serial.c
+++ b/grub-core/term/serial.c
@@ -22,7 +22,7 @@
 #include <grub/dl.h>
 #include <grub/misc.h>
 #include <grub/terminfo.h>
-#if !defined (GRUB_MACHINE_EMU) && (defined(__mips__) || defined (__i386__) || defined (__x86_64__))
+#if !defined (GRUB_MACHINE_EMU) && ((defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__))
 #include <grub/cpu/io.h>
 #endif
 #include <grub/extcmd.h>
@@ -151,7 +151,7 @@ grub_serial_find (const char *name)
     if (grub_strcmp (port->name, name) == 0)
       break;
 
-#if (defined(__mips__) || defined (__i386__) || defined (__x86_64__)) && !defined(GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC)
+#if ((defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__)) && !defined(GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC)
   if (!port && grub_memcmp (name, "port", sizeof ("port") - 1) == 0
       && grub_isxdigit (name [sizeof ("port") - 1]))
     {
@@ -286,7 +286,7 @@ grub_cmd_serial (grub_extcmd_context_t ctxt, int argc, char **args)
   err = port->driver->configure (port, &config);
   if (err)
     return err;
-#if !defined (GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC) && (defined(__mips__) || defined (__i386__) || defined (__x86_64__))
+#if !defined (GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC) && ((defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__))
 
   /* Compatibility kludge.  */
   if (port->driver == &grub_ns8250_driver)
@@ -436,7 +436,7 @@ GRUB_MOD_INIT(serial)
 	       &grub_serial_terminfo_input_template,
 	       sizeof (grub_serial_terminfo_input));
 
-#if !defined (GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC) && (defined(__mips__) || defined (__i386__) || defined (__x86_64__))
+#if !defined (GRUB_MACHINE_EMU) && !defined(GRUB_MACHINE_ARC) && ((defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__))
   grub_ns8250_init ();
 #endif
 #ifdef GRUB_MACHINE_IEEE1275
diff --git a/include/grub/cache.h b/include/grub/cache.h
index fc669dfd1..93583ea15 100644
--- a/include/grub/cache.h
+++ b/include/grub/cache.h
@@ -34,7 +34,7 @@ void EXPORT_FUNC(grub_arch_sync_caches) (void *address, grub_size_t len);
 #endif
 
 #ifndef GRUB_MACHINE_EMU
-#ifdef _mips
+#if defined(__mips__) && (_MIPS_SIM != _ABI64)
 void EXPORT_FUNC(grub_arch_sync_dma_caches) (volatile void *address,
 					     grub_size_t len);
 #else
diff --git a/include/grub/dl.h b/include/grub/dl.h
index 2bca56ce0..89216b175 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -187,7 +187,7 @@ struct grub_dl
   void *tramp;
   void *trampptr;
 #endif
-#ifdef __mips__
+#if defined(__mips__) && (_MIPS_SIM != _ABI64)
   grub_uint32_t *reginfo;
 #endif
   void *base;
@@ -252,7 +252,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
 			       Elf_Shdr *s, grub_dl_segment_t seg);
 #endif
 
-#if defined (_mips)
+#if defined (__mips__) && (_MIPS_SIM != _ABI64)
 #define GRUB_LINKER_HAVE_INIT 1
 void grub_arch_dl_init_linker (void);
 #endif
@@ -279,12 +279,12 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
 				 grub_size_t *got);
 #endif
 
-#if defined (__powerpc__) || defined (__mips__) || defined (__arm__)
+#if defined (__powerpc__) || (defined (__mips__) && (_MIPS_SIM != _ABI64)) || defined (__arm__)
 #define GRUB_ARCH_DL_TRAMP_ALIGN 4
 #define GRUB_ARCH_DL_GOT_ALIGN 4
 #endif
 
-#if defined (__aarch64__) || defined (__sparc__)
+#if defined (__aarch64__) || defined (__sparc__) || (defined (__mips__) && (_MIPS_SIM == _ABI64))
 #define GRUB_ARCH_DL_TRAMP_ALIGN 8
 #define GRUB_ARCH_DL_GOT_ALIGN 8
 #endif
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index c7c9f0e1d..cb4848323 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -1686,7 +1686,7 @@ struct grub_efi_block_io
 typedef struct grub_efi_block_io grub_efi_block_io_t;
 
 #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
-  || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__)
+  || defined (__aarch64__) || defined(__mips__) || defined (__MINGW64__) || defined (__CYGWIN__)
 
 #define efi_call_0(func)		func()
 #define efi_call_1(func, a)		func(a)
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
index f79c36c02..a2bff174e 100644
--- a/include/grub/efi/pe32.h
+++ b/include/grub/efi/pe32.h
@@ -64,6 +64,7 @@ struct grub_pe32_coff_header
 };
 
 #define GRUB_PE32_MACHINE_I386			0x14c
+#define GRUB_PE32_MACHINE_MIPS			0x166
 #define GRUB_PE32_MACHINE_IA64			0x200
 #define GRUB_PE32_MACHINE_X86_64		0x8664
 #define GRUB_PE32_MACHINE_ARMTHUMB_MIXED	0x01c2
@@ -278,6 +279,10 @@ struct grub_pe32_fixup_block
 #define GRUB_PE32_REL_BASED_HIGHLOW	3
 #define GRUB_PE32_REL_BASED_HIGHADJ	4
 #define GRUB_PE32_REL_BASED_MIPS_JMPADDR 5
+#define GRUB_PE32_REL_BASED_MIPS_LOW    6
+#define GRUB_PE32_REL_BASED_MIPS_HIGH   4
+#define GRUB_PE32_REL_BASED_MIPS_HIGHER 7
+#define GRUB_PE32_REL_BASED_MIPS_HIGHEST 8
 #define GRUB_PE32_REL_BASED_ARM_MOV32A  5
 #define GRUB_PE32_REL_BASED_SECTION	6
 #define GRUB_PE32_REL_BASED_REL		7
diff --git a/include/grub/mips64/asm.h b/include/grub/mips64/asm.h
new file mode 100644
index 000000000..062bdf5e9
--- /dev/null
+++ b/include/grub/mips64/asm.h
@@ -0,0 +1,10 @@
+#ifndef GRUB_MIPS64_ASM_HEADER
+#define GRUB_MIPS64_ASM_HEADER	1
+
+#define GRUB_ASM_T4 $a4
+#define GRUB_ASM_T5 $a5
+#define GRUB_ASM_SZREG 8
+#define GRUB_ASM_REG_S sd
+#define GRUB_ASM_REG_L ld
+
+#endif
diff --git a/include/grub/mips64/efi/boot.h b/include/grub/mips64/efi/boot.h
new file mode 100644
index 000000000..e69de29bb
diff --git a/include/grub/mips64/efi/loader.h b/include/grub/mips64/efi/loader.h
new file mode 100644
index 000000000..71a015977
--- /dev/null
+++ b/include/grub/mips64/efi/loader.h
@@ -0,0 +1,25 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2004,2006,2007,2017  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_LOADER_MACHINE_HEADER
+#define GRUB_LOADER_MACHINE_HEADER	1
+
+#include <grub/types.h>
+#include <grub/symbol.h>
+
+#endif /* ! GRUB_LOADER_MACHINE_HEADER */
diff --git a/include/grub/mips64/efi/memory.h b/include/grub/mips64/efi/memory.h
new file mode 100644
index 000000000..52e6ae6eb
--- /dev/null
+++ b/include/grub/mips64/efi/memory.h
@@ -0,0 +1,6 @@
+#ifndef GRUB_MEMORY_CPU_HEADER
+#include <grub/efi/memory.h>
+
+#define GRUB_EFI_MAX_USABLE_ADDRESS 0x980000000fffffffUL
+
+#endif /* ! GRUB_MEMORY_CPU_HEADER */
diff --git a/include/grub/mips64/efi/time.h b/include/grub/mips64/efi/time.h
new file mode 100644
index 000000000..e69de29bb
diff --git a/include/grub/mips64/io.h b/include/grub/mips64/io.h
new file mode 100644
index 000000000..5f341037a
--- /dev/null
+++ b/include/grub/mips64/io.h
@@ -0,0 +1,62 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009,2017  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef	GRUB_IO_H
+#define	GRUB_IO_H	1
+
+#include <grub/types.h>
+
+typedef grub_addr_t grub_port_t;
+
+static __inline unsigned char
+grub_inb (grub_port_t port)
+{
+  return *(volatile grub_uint8_t *) port;
+}
+
+static __inline unsigned short int
+grub_inw (grub_port_t port)
+{
+  return *(volatile grub_uint16_t *) port;
+}
+
+static __inline unsigned int
+grub_inl (grub_port_t port)
+{
+  return *(volatile grub_uint32_t *) port;
+}
+
+static __inline void
+grub_outb (unsigned char value, grub_port_t port)
+{
+  *(volatile grub_uint8_t *) port = value;
+}
+
+static __inline void
+grub_outw (unsigned short int value, grub_port_t port)
+{
+  *(volatile grub_uint16_t *) port = value;
+}
+
+static __inline void
+grub_outl (unsigned int value, grub_port_t port)
+{
+  *(volatile grub_uint32_t *) port = value;
+}
+
+#endif /* _SYS_IO_H */
diff --git a/include/grub/mips64/kernel.h b/include/grub/mips64/kernel.h
new file mode 100644
index 000000000..909d5397d
--- /dev/null
+++ b/include/grub/mips64/kernel.h
@@ -0,0 +1,24 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2005,2006,2007,2008,2009,2017  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_KERNEL_CPU_HEADER
+#define GRUB_KERNEL_CPU_HEADER	1
+
+#include <grub/symbol.h>
+
+#endif /* ! GRUB_KERNEL_MACHINE_HEADER */
diff --git a/include/grub/mips64/memory.h b/include/grub/mips64/memory.h
new file mode 100644
index 000000000..573a70f79
--- /dev/null
+++ b/include/grub/mips64/memory.h
@@ -0,0 +1,56 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2017 Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_MEMORY_CPU_HEADER
+#define GRUB_MEMORY_CPU_HEADER	1
+
+#ifndef ASM_FILE
+#include <grub/symbol.h>
+#include <grub/err.h>
+#include <grub/types.h>
+#endif
+
+#ifndef ASM_FILE
+
+typedef grub_addr_t grub_phys_addr_t;
+
+static inline grub_phys_addr_t
+grub_vtop (void *a)
+{
+  if (-1 == ((grub_int64_t) a >> 32))
+    return ((grub_phys_addr_t) a) & 0x1fffffffUL;
+  return ((grub_phys_addr_t) a) & 0xffffffffffffUL;
+}
+
+static inline void *
+grub_map_memory (grub_phys_addr_t a, grub_size_t size)
+{
+  if ((a + size) < 0x20000000UL)
+    return (void *) (a | 0xffffffff80000000UL);
+  return (void *) (a | 0x9800000000000000UL);
+}
+
+static inline void
+grub_unmap_memory (void *a __attribute__ ((unused)),
+		   grub_size_t size __attribute__ ((unused)))
+{
+}
+
+#endif
+
+#endif
diff --git a/include/grub/mips64/mips.h b/include/grub/mips64/mips.h
new file mode 100644
index 000000000..a13c709e0
--- /dev/null
+++ b/include/grub/mips64/mips.h
@@ -0,0 +1,30 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2010,2017  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_REGISTERS_CPU_HEADER
+#define GRUB_REGISTERS_CPU_HEADER	1
+
+#ifdef ASM_FILE
+#define GRUB_CPU_REGISTER_WRAP(x) x
+#else
+#define GRUB_CPU_REGISTER_WRAP(x) #x
+#endif
+
+#define GRUB_CPU_MIPS_COP0_TIMER_COUNT GRUB_CPU_REGISTER_WRAP($9)
+
+#endif
diff --git a/include/grub/mips64/setjmp.h b/include/grub/mips64/setjmp.h
new file mode 100644
index 000000000..d9a0776b6
--- /dev/null
+++ b/include/grub/mips64/setjmp.h
@@ -0,0 +1,27 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2004,2006,2007,2009,2017  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_SETJMP_CPU_HEADER
+#define GRUB_SETJMP_CPU_HEADER	1
+
+typedef grub_uint64_t grub_jmp_buf[12];
+
+int grub_setjmp (grub_jmp_buf env) RETURNS_TWICE;
+void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn));
+
+#endif /* ! GRUB_SETJMP_CPU_HEADER */
diff --git a/include/grub/mips64/time.h b/include/grub/mips64/time.h
new file mode 100644
index 000000000..c9a733488
--- /dev/null
+++ b/include/grub/mips64/time.h
@@ -0,0 +1,39 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2003,2004,2005,2007,2017  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef KERNEL_CPU_TIME_HEADER
+#define KERNEL_CPU_TIME_HEADER	1
+
+#ifndef GRUB_UTIL
+
+#define GRUB_TICKS_PER_SECOND	(grub_arch_cpuclock / 2)
+
+void grub_timer_init (grub_uint32_t cpuclock);
+
+/* Return the real time in ticks.  */
+grub_uint64_t grub_get_rtc (void);
+
+extern grub_uint32_t grub_arch_cpuclock;
+#endif
+
+static inline void
+grub_cpu_idle(void)
+{
+}
+
+#endif
diff --git a/include/grub/mips64/types.h b/include/grub/mips64/types.h
new file mode 100644
index 000000000..fc896c83b
--- /dev/null
+++ b/include/grub/mips64/types.h
@@ -0,0 +1,38 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2006,2007,2009,2017  Free Software Foundation, Inc.
+ *
+ *  GRUB 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB 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.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_TYPES_CPU_HEADER
+#define GRUB_TYPES_CPU_HEADER	1
+
+/* The size of void *.  */
+#define GRUB_TARGET_SIZEOF_VOID_P	8
+
+/* The size of long.  */
+#define GRUB_TARGET_SIZEOF_LONG		8
+
+#ifdef GRUB_CPU_MIPS64EL
+/* mips64EL is little-endian.  */
+#undef GRUB_TARGET_WORDS_BIGENDIAN
+#elif defined (GRUB_CPU_MIPS64)
+/* mips64 is big-endian.  */
+#define GRUB_TARGET_WORDS_BIGENDIAN
+#elif !defined (GRUB_SYMBOL_GENERATOR)
+#error Neither GRUB_CPU_MIPS64 nor GRUB_CPU_MIPS64EL is defined
+#endif
+
+#endif /* ! GRUB_TYPES_CPU_HEADER */
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 2a9f87cc2..2ba97b493 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -410,7 +410,7 @@ void __attribute__ ((noreturn)) EXPORT_FUNC (abort) (void);
 /* Halt the system, using APM if possible. If NO_APM is true, don't
  * use APM even if it is available.  */
 void grub_halt (int no_apm) __attribute__ ((noreturn));
-#elif defined (__mips__) && !defined (GRUB_MACHINE_EMU)
+#elif (defined (__mips__) && (_MIPS_SIM != _ABI64)) && !defined (GRUB_MACHINE_EMU)
 void EXPORT_FUNC (grub_halt) (void) __attribute__ ((noreturn));
 #else
 void grub_halt (void) __attribute__ ((noreturn));
diff --git a/include/grub/serial.h b/include/grub/serial.h
index 67379de45..f8cc4612b 100644
--- a/include/grub/serial.h
+++ b/include/grub/serial.h
@@ -21,7 +21,7 @@
 #define GRUB_SERIAL_HEADER	1
 
 #include <grub/types.h>
-#if defined(__mips__) || defined (__i386__) || defined (__x86_64__)
+#if (defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__)
 #include <grub/cpu/io.h>
 #endif
 #include <grub/usb.h>
@@ -86,7 +86,7 @@ struct grub_serial_port
    */
   union
   {
-#if defined(__mips__) || defined (__i386__) || defined (__x86_64__)
+#if (defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__)
     grub_port_t port;
 #endif
     struct
@@ -175,7 +175,7 @@ grub_serial_config_defaults (struct grub_serial_port *port)
   return port->driver->configure (port, &config);
 }
 
-#if defined(__mips__) || defined (__i386__) || defined (__x86_64__)
+#if (defined(__mips__) && _MIPS_SIM != _ABI64) || defined (__i386__) || defined (__x86_64__)
 void grub_ns8250_init (void);
 char *grub_serial_ns8250_add_port (grub_port_t port);
 #endif
diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index 5ca4811cd..00c6d64af 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -99,6 +99,7 @@ enum grub_install_plat
     GRUB_INSTALL_PLATFORM_I386_XEN,
     GRUB_INSTALL_PLATFORM_X86_64_XEN,
     GRUB_INSTALL_PLATFORM_ARM64_EFI,
+    GRUB_INSTALL_PLATFORM_MIPS64EL_EFI,
     GRUB_INSTALL_PLATFORM_MAX
   };
 
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
index 452b230da..871000449 100644
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -665,6 +665,7 @@ static struct
     [GRUB_INSTALL_PLATFORM_IA64_EFI] =         { "ia64",    "efi"       },
     [GRUB_INSTALL_PLATFORM_ARM_EFI] =          { "arm",     "efi"       },
     [GRUB_INSTALL_PLATFORM_ARM64_EFI] =        { "arm64",   "efi"       },
+    [GRUB_INSTALL_PLATFORM_MIPS64EL_EFI] =     { "mips64el","efi"       },
     [GRUB_INSTALL_PLATFORM_ARM_UBOOT] =        { "arm",     "uboot"     },
   }; 
 
diff --git a/util/grub-install.c b/util/grub-install.c
index 6c89c2b0c..5fac6389b 100644
--- a/util/grub-install.c
+++ b/util/grub-install.c
@@ -313,7 +313,11 @@ get_default_platform (void)
 #elif defined (__sparc__) || defined (__sparc64__)
    return "sparc64-ieee1275";
 #elif defined (__MIPSEL__)
+#if _MIPS_SIM == _ABI64
+   return "mips64el-efi";
+#else
    return "mipsel-loongson";
+#endif
 #elif defined (__MIPSEB__)
    return "mips-arc";
 #elif defined (__ia64__)
@@ -477,6 +481,7 @@ have_bootdev (enum grub_install_plat pl)
     case GRUB_INSTALL_PLATFORM_IA64_EFI:
     case GRUB_INSTALL_PLATFORM_ARM_EFI:
     case GRUB_INSTALL_PLATFORM_ARM64_EFI:
+    case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI:
     case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
     case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
     case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
@@ -898,6 +903,7 @@ main (int argc, char *argv[])
     case GRUB_INSTALL_PLATFORM_X86_64_EFI:
     case GRUB_INSTALL_PLATFORM_ARM_EFI:
     case GRUB_INSTALL_PLATFORM_ARM64_EFI:
+    case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI:
     case GRUB_INSTALL_PLATFORM_IA64_EFI:
     case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
     case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
@@ -941,6 +947,7 @@ main (int argc, char *argv[])
     case GRUB_INSTALL_PLATFORM_X86_64_EFI:
     case GRUB_INSTALL_PLATFORM_ARM_EFI:
     case GRUB_INSTALL_PLATFORM_ARM64_EFI:
+    case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI:
     case GRUB_INSTALL_PLATFORM_IA64_EFI:
     case GRUB_INSTALL_PLATFORM_I386_IEEE1275:
     case GRUB_INSTALL_PLATFORM_ARM_UBOOT:
@@ -992,6 +999,7 @@ main (int argc, char *argv[])
     case GRUB_INSTALL_PLATFORM_X86_64_EFI:
     case GRUB_INSTALL_PLATFORM_ARM_EFI:
     case GRUB_INSTALL_PLATFORM_ARM64_EFI:
+    case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI:
     case GRUB_INSTALL_PLATFORM_IA64_EFI:
       is_efi = 1;
       break;
@@ -1105,6 +1113,9 @@ main (int argc, char *argv[])
 	    case GRUB_INSTALL_PLATFORM_ARM64_EFI:
 	      efi_file = "BOOTAA64.EFI";
 	      break;
+	    case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI:
+	      efi_file = "BOOTMIPS64EL.EFI";
+	      break;
 	    default:
 	      grub_util_error ("%s", _("You've found a bug"));
 	      break;
@@ -1132,6 +1143,9 @@ main (int argc, char *argv[])
 	    case GRUB_INSTALL_PLATFORM_ARM64_EFI:
 	      efi_file = "grubaa64.efi";
 	      break;
+	    case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI:
+	      efi_file = "grubmips64el.efi";
+	      break;
 	    default:
 	      efi_file = "grub.efi";
 	      break;
@@ -1434,6 +1448,7 @@ main (int argc, char *argv[])
 		  case GRUB_INSTALL_PLATFORM_X86_64_EFI:
 		  case GRUB_INSTALL_PLATFORM_ARM_EFI:
 		  case GRUB_INSTALL_PLATFORM_ARM64_EFI:
+		  case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI:
 		  case GRUB_INSTALL_PLATFORM_IA64_EFI:
 		    g = grub_util_guess_efi_drive (*curdev);
 		    break;
@@ -1524,6 +1539,7 @@ main (int argc, char *argv[])
     case GRUB_INSTALL_PLATFORM_X86_64_EFI:
     case GRUB_INSTALL_PLATFORM_ARM_EFI:
     case GRUB_INSTALL_PLATFORM_ARM64_EFI:
+    case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI:
     case GRUB_INSTALL_PLATFORM_IA64_EFI:
       core_name = "core.efi";
       snprintf (mkimage_target, sizeof (mkimage_target),
@@ -1625,6 +1641,7 @@ main (int argc, char *argv[])
       break;
     case GRUB_INSTALL_PLATFORM_ARM_EFI:
     case GRUB_INSTALL_PLATFORM_ARM64_EFI:
+    case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI:
     case GRUB_INSTALL_PLATFORM_IA64_EFI:
     case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS:
     case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
@@ -1853,6 +1870,7 @@ main (int argc, char *argv[])
 	}
     case GRUB_INSTALL_PLATFORM_ARM_EFI:
     case GRUB_INSTALL_PLATFORM_ARM64_EFI:
+    case GRUB_INSTALL_PLATFORM_MIPS64EL_EFI:
     case GRUB_INSTALL_PLATFORM_IA64_EFI:
       {
 	char *dst = grub_util_path_concat (2, efidir, efi_file);
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index f8faae878..f70e98241 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -769,7 +769,11 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
 	    offset = grub_target_to_host (r->r_offset);
 	    target = SUFFIX (get_target_address) (e, target_section,
 						  offset, image_target);
-	    info = grub_target_to_host (r->r_info);
+	    if (image_target->elf_target == EM_MIPS && image_target->voidp_sizeof == 8)
+	      info = ((grub_uint64_t) r->r_info << 32) |
+		      (grub_uint32_t) grub_be_to_cpu64 (r->r_info);
+	    else
+	      info = grub_target_to_host (r->r_info);
 	    sym_addr = SUFFIX (get_symbol_address) (e, symtab_section,
 						    ELF_R_SYM (info), image_target);
 
@@ -1051,6 +1055,66 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
 		   }
 	       break;
 	       }
+	     case EM_MIPS:
+	       {
+		 sym_addr += addend;
+		 switch (ELF_R_TYPE (info))
+		   {
+		   case R_MIPS_NONE:
+		     break;
+		   case R_MIPS_64:
+		     {
+		       *target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr);
+		     }
+		     break;
+		   case R_MIPS_32:
+		     {
+		       grub_uint32_t *t32 = (grub_uint32_t *) target;
+		       *t32 = grub_host_to_target64 (grub_target_to_host32 (*t32) + sym_addr);
+		     }
+		     break;
+		   case R_MIPS_26:
+		     {
+		       grub_uint32_t *t32 = (grub_uint32_t *) target;
+		       grub_addr_t addr = grub_host_to_target64 (sym_addr);
+		       *t32 = ((*t32) & 0xfc000000U) | ((addr >> 2) & 0x3ffffffUL);
+		     }
+		     break;
+		   case R_MIPS_LO16:
+		     {
+		       grub_int16_t *t16 = (grub_int16_t *) target;
+		       grub_addr_t addr = grub_host_to_target64 (sym_addr);
+		       *t16 = (grub_int16_t) addr;
+		     }
+		     break;
+		   case R_MIPS_HI16:
+		     {
+		       grub_int16_t *t16 = (grub_int16_t *) target;
+		       grub_addr_t addr = grub_host_to_target64 (sym_addr);
+		       *t16 = (grub_int16_t) ((addr + 0x8000UL) >> 16);
+		     }
+		     break;
+		   case R_MIPS_HIGHER:
+		     {
+		       grub_int16_t *t16 = (grub_int16_t *) target;
+		       grub_addr_t addr = grub_host_to_target64 (sym_addr);
+		       *t16 = (grub_int16_t) ((addr + 0x80008000UL) >> 32);
+		     }
+		     break;
+		   case R_MIPS_HIGHEST:
+		     {
+		       grub_uint16_t *t16 = (grub_uint16_t *) target;
+		       grub_addr_t addr = grub_host_to_target64 (sym_addr);
+		       *t16 = (grub_uint16_t) ((addr + 0x800080008000UL) >> 48);
+		     }
+		     break;
+		   default:
+		     grub_util_error (_("relocation 0x%x is not implemented yet"),
+				      (unsigned int) ELF_R_TYPE (info));
+		     break;
+		   }
+	       break;
+	       }
 #endif
 #if defined(MKIMAGE_ELF32)
 	     case EM_ARM:
@@ -1176,7 +1240,7 @@ add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type,
   /* First, check if it is necessary to write out the current block.  */
   if ((*cblock)->state)
     {
-      if (flush || addr < b->page_rva || b->page_rva + 0x1000 <= addr)
+      if (flush || (type && (addr < b->page_rva || b->page_rva + 0x1000 <= addr)))
 	{
 	  grub_uint32_t size;
 
@@ -1239,7 +1303,8 @@ add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type,
 
 	  /* The spec does not mention the requirement of a Page RVA.
 	     Here, align the address with a 4K boundary for safety.  */
-	  b->page_rva = (addr & ~(0x1000 - 1));
+	  if (type)
+	    b->page_rva = (addr & ~(0x1000 - 1));
 	  b->block_size = sizeof (*b);
 	}
 
@@ -1249,7 +1314,7 @@ add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type,
 
       /* Add a new entry.  */
       cur_index = ((b->block_size - sizeof (*b)) >> 1);
-      entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva);
+      entry = GRUB_PE32_FIXUP_ENTRY (type, type ? (addr - b->page_rva) : addr);
       b->entries[cur_index] = grub_host_to_target16 (entry);
       b->block_size += 2;
     }
@@ -1295,6 +1360,8 @@ static void
 translate_relocation_pe (struct translate_context *ctx,
 			 Elf_Addr addr,
 			 Elf_Addr info,
+			 Elf_Addr sym_addr,
+			 Elf_Addr addend,
 			 const struct grub_install_image_target_desc *image_target)
 {
   /* Necessary to relocate only absolute addresses.  */
@@ -1405,7 +1472,162 @@ translate_relocation_pe (struct translate_context *ctx,
 	  break;
 	}
       break;
+#if defined(MKIMAGE_ELF64)
+    case EM_MIPS:
+      switch (ELF_R_TYPE (info))
+	{
+	case R_MIPS_64:
+	  {
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst,
+				 GRUB_PE32_REL_BASED_DIR64,
+				 addr, 0, ctx->current_address,
+				 image_target);
+	  }
+	  break;
+	case R_MIPS_32:
+#if 0
+	  {
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst,
+				 GRUB_PE32_REL_BASED_HIGHLOW,
+				 addr, 0, ctx->current_address,
+				 image_target);
+	  }
+#endif
+	  break;
+	case R_MIPS_26:
+	  {
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst,
+				 GRUB_PE32_REL_BASED_MIPS_JMPADDR,
+				 addr, 0, ctx->current_address,
+				 image_target);
+	  }
+	  break;
+	case R_MIPS_LO16:
+	  {
+	    Elf_Addr target = sym_addr + addend;
+
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst,
+				 GRUB_PE32_REL_BASED_MIPS_LOW,
+				 addr, 0, ctx->current_address,
+				 image_target);
+	    /* Hi */
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst, 0,
+				 (grub_int16_t) ((target & 0x8000UL) >> 16),
+				 0, ctx->current_address,
+				 image_target);
+	    /* Higher */
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst, 0,
+				 (grub_int16_t) ((target & 0x80008000UL) >> 32),
+				 0, ctx->current_address,
+				 image_target);
+	    /* Highest */
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst, 0,
+				 (grub_uint16_t) ((target & 0x800080008000UL) >> 48),
+				 0, ctx->current_address,
+				 image_target);
+	  }
+	  break;
+	case R_MIPS_HI16:
+	  {
+	    Elf_Addr target = sym_addr + addend;
+
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst,
+				 GRUB_PE32_REL_BASED_MIPS_HIGH,
+				 addr, 0, ctx->current_address,
+				 image_target);
+	    /* Lo */
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst, 0,
+				 (grub_int16_t) target,
+				 0, ctx->current_address,
+				 image_target);
+	    /* Higher */
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst, 0,
+				 (grub_int16_t) ((target & 0x80008000UL) >> 32),
+				 0, ctx->current_address,
+				 image_target);
+	    /* Highest */
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst, 0,
+				 (grub_uint16_t) ((target & 0x800080008000UL) >> 48),
+				 0, ctx->current_address,
+				 image_target);
+	  }
+	  break;
+	case R_MIPS_HIGHER:
+	  {
+	    Elf_Addr target = sym_addr + addend;
+
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst,
+				 GRUB_PE32_REL_BASED_MIPS_HIGHER,
+				 addr, 0, ctx->current_address,
+				 image_target);
+	    /* Lo */
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst, 0,
+				 (grub_int16_t) target,
+				 0, ctx->current_address,
+				 image_target);
+	    /* Hi */
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst, 0,
+				 (grub_int16_t) ((target & 0x8000UL) >> 16),
+				 0, ctx->current_address,
+				 image_target);
+	    /* Highest */
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst, 0,
+				 (grub_uint16_t) ((target & 0x800080008000UL) >> 48),
+				 0, ctx->current_address,
+				 image_target);
+	  }
+	  break;
+	case R_MIPS_HIGHEST:
+	  {
+	    Elf_Addr target = sym_addr + addend;
+
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst,
+				 GRUB_PE32_REL_BASED_MIPS_HIGHEST,
+				 addr, 0, ctx->current_address,
+				 image_target);
+	    /* Lo */
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst, 0,
+				 (grub_int16_t) target,
+				 0, ctx->current_address,
+				 image_target);
+	    /* Hi */
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst, 0,
+				 (grub_int16_t) ((target & 0x8000UL) >> 16),
+				 0, ctx->current_address,
+				 image_target);
+	    /* Higher */
+	    ctx->current_address
+	      = add_fixup_entry (&ctx->lst, 0,
+				 (grub_int16_t) ((target & 0x80008000UL) >> 32),
+				 0, ctx->current_address,
+				 image_target);
+	  }
+	  break;
+	default:
+	  grub_util_error (_("relocation 0x%x is not implemented yet"),
+			   (unsigned int) ELF_R_TYPE (info));
+	  break;
+	}
       break;
+#endif
 #if defined(MKIMAGE_ELF32)
     case EM_ARM:
       switch (ELF_R_TYPE (info))
@@ -1494,10 +1716,12 @@ static void
 translate_relocation (struct translate_context *ctx,
 		      Elf_Addr addr,
 		      Elf_Addr info,
+		      Elf_Addr sym_addr,
+		      Elf_Addr addend,
 		      const struct grub_install_image_target_desc *image_target)
 {
   if (image_target->id == IMAGE_EFI)
-    translate_relocation_pe (ctx, addr, info, image_target);
+    translate_relocation_pe (ctx, addr, info, sym_addr, addend, image_target);
   else
     translate_relocation_raw (ctx, addr, info, image_target);
 }
@@ -1640,12 +1864,17 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout,
     if ((grub_target_to_host32 (s->sh_type) == SHT_REL) ||
         (grub_target_to_host32 (s->sh_type) == SHT_RELA))
       {
-	Elf_Rel *r;
+	Elf_Rela *r;
 	Elf_Word rtab_size, r_size, num_rs;
 	Elf_Off rtab_offset;
+	Elf_Shdr *symtab_section;
 	Elf_Addr section_address;
 	Elf_Word j;
 
+	symtab_section = (Elf_Shdr *) ((char *) sections
+					+ (grub_target_to_host32 (s->sh_link)
+						* section_entsize));
+
 	grub_util_info ("translating the relocation section %s",
 			strtab + grub_le_to_cpu32 (s->sh_name));
 
@@ -1656,20 +1885,30 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout,
 
 	section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)];
 
-	for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset);
+	for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset);
 	     j < num_rs;
-	     j++, r = (Elf_Rel *) ((char *) r + r_size))
+	     j++, r = (Elf_Rela *) ((char *) r + r_size))
 	  {
 	    Elf_Addr info;
 	    Elf_Addr offset;
 	    Elf_Addr addr;
+	    Elf_Addr sym_addr;
+	    Elf_Addr addend;
 
 	    offset = grub_target_to_host (r->r_offset);
-	    info = grub_target_to_host (r->r_info);
+	    if (image_target->elf_target == EM_MIPS && image_target->voidp_sizeof == 8)
+	      info = ((grub_uint64_t) r->r_info << 32) |
+		      (grub_uint32_t) grub_be_to_cpu64 (r->r_info);
+	    else
+	      info = grub_target_to_host (r->r_info);
 
+	    sym_addr = SUFFIX (get_symbol_address) (e, symtab_section,
+						    ELF_R_SYM (info), image_target);
+	    addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ?
+		grub_target_to_host (r->r_addend) : 0;
 	    addr = section_address + offset;
 
-	    translate_relocation (&ctx, addr, info, image_target);
+	    translate_relocation (&ctx, addr, info, sym_addr, addend, image_target);
 	  }
       }
 
diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c
index 82073d5cc..5e9be8f2e 100644
--- a/util/grub-mknetdir.c
+++ b/util/grub-mknetdir.c
@@ -107,7 +107,8 @@ static const struct
     [GRUB_INSTALL_PLATFORM_X86_64_EFI] = { "x86_64-efi", "efinet", ".efi" },
     [GRUB_INSTALL_PLATFORM_IA64_EFI] = { "ia64-efi", "efinet", ".efi" },
     [GRUB_INSTALL_PLATFORM_ARM_EFI] = { "arm-efi", "efinet", ".efi" },
-    [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64-efi", "efinet", ".efi" }
+    [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64-efi", "efinet", ".efi" },
+    [GRUB_INSTALL_PLATFORM_MIPS64EL_EFI] = { "mips64el-efi", "efinet", ".efi" }
   };
 
 static void
diff --git a/util/grub-mkrescue.c b/util/grub-mkrescue.c
index 238d4840e..f42a9c6a5 100644
--- a/util/grub-mkrescue.c
+++ b/util/grub-mkrescue.c
@@ -530,6 +530,7 @@ main (int argc, char *argv[])
 	  || source_dirs[GRUB_INSTALL_PLATFORM_IA64_EFI]
 	  || source_dirs[GRUB_INSTALL_PLATFORM_ARM_EFI]
 	  || source_dirs[GRUB_INSTALL_PLATFORM_ARM64_EFI]
+	  || source_dirs[GRUB_INSTALL_PLATFORM_MIPS64EL_EFI]
 	  || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI])
 	system_area = SYS_AREA_COMMON;
       else if (source_dirs[GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275])
@@ -727,7 +728,8 @@ main (int argc, char *argv[])
       || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]
       || source_dirs[GRUB_INSTALL_PLATFORM_IA64_EFI]
       || source_dirs[GRUB_INSTALL_PLATFORM_ARM_EFI]
-      || source_dirs[GRUB_INSTALL_PLATFORM_ARM64_EFI])
+      || source_dirs[GRUB_INSTALL_PLATFORM_ARM64_EFI]
+      || source_dirs[GRUB_INSTALL_PLATFORM_MIPS64EL_EFI])
     {
       char *efidir = grub_util_make_temporary_dir ();
       char *efidir_efi = grub_util_path_concat (2, efidir, "efi");
@@ -762,6 +764,11 @@ main (int argc, char *argv[])
 			     imgname);
       free (imgname);
 
+      imgname = grub_util_path_concat (2, efidir_efi_boot, "bootmips64el.efi");
+      make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_MIPS64EL_EFI, "mips64el-efi",
+			     imgname);
+      free (imgname);
+
       if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI])
 	{
 	  imgname = grub_util_path_concat (2, efidir_efi_boot, "boot.efi");
diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c
index d0cf8176f..6b07631d6 100644
--- a/util/grub-module-verifier.c
+++ b/util/grub-module-verifier.c
@@ -118,6 +118,19 @@ struct grub_module_verifier_arch archs[] = {
       -1
     }
   },
+  { "mips64el", 8, 0, EM_MIPS, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){
+      R_MIPS_64,
+      R_MIPS_32,
+      R_MIPS_26,
+      R_MIPS_LO16,
+      R_MIPS_HI16,
+      R_MIPS_HIGHER,
+      R_MIPS_HIGHEST,
+      -1
+    }, (int[]){
+      -1
+    }
+  },
 };
 
 struct platform_whitelist {
diff --git a/util/grub-module-verifierXX.c b/util/grub-module-verifierXX.c
index 1feaafc9b..0b0446e98 100644
--- a/util/grub-module-verifierXX.c
+++ b/util/grub-module-verifierXX.c
@@ -296,7 +296,14 @@ section_check_relocations (const struct grub_module_verifier_arch *arch, void *e
       if (target_seg_size < grub_target_to_host (rel->r_offset))
 	grub_util_error ("reloc offset is out of the segment");
 
-      grub_uint32_t type = ELF_R_TYPE (grub_target_to_host (rel->r_info));
+      grub_size_t r_info;
+      if (arch->machine == EM_MIPS && arch->voidp_sizeof == 8)
+        r_info = ((grub_uint64_t) rel->r_info << 32) |
+                  (grub_uint32_t) grub_be_to_cpu64 (rel->r_info);
+      else
+        r_info = grub_target_to_host (rel->r_info);
+
+      grub_uint32_t type = ELF_R_TYPE (r_info);
 
       if (arch->machine == EM_SPARCV9)
 	type &= 0xff;
@@ -313,7 +320,7 @@ section_check_relocations (const struct grub_module_verifier_arch *arch, void *e
 	  break;
       if (arch->short_relocations[i] == -1)
 	grub_util_error ("unsupported relocation 0x%x", type);
-      sym = (Elf_Sym *) ((char *) symtab + symtabentsize * ELF_R_SYM (grub_target_to_host (rel->r_info)));
+      sym = (Elf_Sym *) ((char *) symtab + symtabentsize * ELF_R_SYM (r_info));
 
       if (is_symbol_local (sym))
 	continue;
diff --git a/util/mkimage.c b/util/mkimage.c
index 9ad4cfe42..5ad214a17 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -570,6 +570,22 @@ static const struct grub_install_image_target_desc image_targets[] =
       .pe_target = GRUB_PE32_MACHINE_ARM64,
       .elf_target = EM_AARCH64,
     },
+    {
+      .dirname = "mips64el-efi",
+      .names = { "mips64el-efi", NULL },
+      .voidp_sizeof = 8,
+      .bigendian = 0,
+      .id = IMAGE_EFI,
+      .flags = PLATFORM_FLAGS_NONE,
+      .total_module_size = TARGET_NO_FIELD,
+      .decompressor_compressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_size = TARGET_NO_FIELD,
+      .decompressor_uncompressed_addr = TARGET_NO_FIELD,
+      .section_align = GRUB_PE32_SECTION_ALIGNMENT,
+      .vaddr_offset = EFI64_HEADER_SIZE,
+      .pe_target = GRUB_PE32_MACHINE_MIPS,
+      .elf_target = EM_MIPS,
+    },
   };
 
 #include <grub/lib/LzmaEnc.h>
-- 
2.11.1





^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] mips64: Add support for 64-bit MIPS.
  2017-02-13 15:57 [PATCH v2] mips64: Add support for 64-bit MIPS wangr
@ 2017-02-13 19:01 ` Andrei Borzenkov
  2017-02-13 19:29   ` Vladimir 'phcoder' Serbinenko
  2017-02-14  1:24   ` Heiher
  0 siblings, 2 replies; 6+ messages in thread
From: Andrei Borzenkov @ 2017-02-13 19:01 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: Heiher

13.02.2017 18:57, wangr@lemote.com пишет:
> From: Heiher <r@hev.cc>
> 

Before going in more depth for review, could you give more details which
platforms are using it, what ABI is targeted (n64? something else?) Is
MIPS going to be included in official UEFI spec?


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] mips64: Add support for 64-bit MIPS.
  2017-02-13 19:01 ` Andrei Borzenkov
@ 2017-02-13 19:29   ` Vladimir 'phcoder' Serbinenko
  2017-02-14  1:34     ` Heiher
  2017-02-14  1:24   ` Heiher
  1 sibling, 1 reply; 6+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2017-02-13 19:29 UTC (permalink / raw)
  To: The development of GNU GRUB; +Cc: Heiher

[-- Attachment #1: Type: text/plain, Size: 751 bytes --]

On Mon, 13 Feb 2017, 20:05 Andrei Borzenkov <arvidjaar@gmail.com> wrote:

> 13.02.2017 18:57, wangr@lemote.com пишет:
> > From: Heiher <r@hev.cc>
> >
>
> Before going in more depth for review, could you give more details which
> platforms are using it, what ABI is targeted (n64? something else?) Is
> MIPS going to be included in official UEFI spec?
>
Also it seems that it targets yeeloong's and fuloong's we already support.
I'd like a good justification for this port over existing ones as it will
surely need maintenance, so we need a benefit to justify maintenance.

>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
>

[-- Attachment #2: Type: text/html, Size: 1647 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] mips64: Add support for 64-bit MIPS.
  2017-02-13 19:01 ` Andrei Borzenkov
  2017-02-13 19:29   ` Vladimir 'phcoder' Serbinenko
@ 2017-02-14  1:24   ` Heiher
  1 sibling, 0 replies; 6+ messages in thread
From: Heiher @ 2017-02-14  1:24 UTC (permalink / raw)
  To: Andrei Borzenkov; +Cc: The development of GNU GRUB

On Tue, Feb 14, 2017 at 3:01 AM, Andrei Borzenkov <arvidjaar@gmail.com> wrote:
> 13.02.2017 18:57, wangr@lemote.com пишет:
>> From: Heiher <r@hev.cc>
>>
>
> Before going in more depth for review, could you give more details which
> platforms are using it, what ABI is targeted (n64? something else?) Is
> MIPS going to be included in official UEFI spec?

Right. This port is used for MIPS64-based UEFI platforms and
Loongson-3's linux boot interface are supported.
The target ABI is standard mips n64, no-abicalls is enabled and
long-jumps is disabled for kernel and modules.

Currently, The MIPS is not included in official UEFI spec, but Lemote
will do it. Looks many MIPS cpus are used
for embedded platforms, so i think they are more use of lightweight
firmware (e.g. u-boot, pmon ...)

The Lemote (http://www.lemote.com) is a MIPS OEM, It is porting UEFI
(EDK) for MIPS-based desktop and
high-performance server.

-- 
Best regards!
Heiher
http://hev.cc


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] mips64: Add support for 64-bit MIPS.
  2017-02-13 19:29   ` Vladimir 'phcoder' Serbinenko
@ 2017-02-14  1:34     ` Heiher
  2017-02-27 16:22       ` Heiher
  0 siblings, 1 reply; 6+ messages in thread
From: Heiher @ 2017-02-14  1:34 UTC (permalink / raw)
  To: Vladimir 'phcoder' Serbinenko; +Cc: The development of GNU GRUB

On Tue, Feb 14, 2017 at 3:29 AM, Vladimir 'phcoder' Serbinenko
<phcoder@gmail.com> wrote:
>
>
> On Mon, 13 Feb 2017, 20:05 Andrei Borzenkov <arvidjaar@gmail.com> wrote:
>>
>> 13.02.2017 18:57, wangr@lemote.com пишет:
>> > From: Heiher <r@hev.cc>
>> >
>>
>> Before going in more depth for review, could you give more details which
>> platforms are using it, what ABI is targeted (n64? something else?) Is
>> MIPS going to be included in official UEFI spec?
>
> Also it seems that it targets yeeloong's and fuloong's we already support.
> I'd like a good justification for this port over existing ones as it will
> surely need maintenance, so we need a benefit to justify maintenance.

The yeeloong and fuloong are based on Loongson-2 cpu platforms, They have
been discontinued. In future, The new products will switch to full
64-bit softwares
(from firmware to operating system).

The exist mips port is mips o32 ABI and for non UEFI platforms in
GRUB, This port is
for MIPS n64 ABI and UEFI platform. I think using a new cpu type
mips64 is better.
The code is clear for maintenance. ;)

>>
>>
>> _______________________________________________
>> Grub-devel mailing list
>> Grub-devel@gnu.org
>> https://lists.gnu.org/mailman/listinfo/grub-devel



-- 
Best regards!
Heiher
http://hev.cc


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] mips64: Add support for 64-bit MIPS.
  2017-02-14  1:34     ` Heiher
@ 2017-02-27 16:22       ` Heiher
  0 siblings, 0 replies; 6+ messages in thread
From: Heiher @ 2017-02-27 16:22 UTC (permalink / raw)
  To: Vladimir 'phcoder' Serbinenko; +Cc: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 1537 bytes --]

Hello,

What do you think about this patch set? thanks!

On Tue, Feb 14, 2017, 9:34 AM Heiher <r@hev.cc> wrote:

> On Tue, Feb 14, 2017 at 3:29 AM, Vladimir 'phcoder' Serbinenko
> <phcoder@gmail.com> wrote:
> >
> >
> > On Mon, 13 Feb 2017, 20:05 Andrei Borzenkov <arvidjaar@gmail.com> wrote:
> >>
> >> 13.02.2017 18:57, wangr@lemote.com пишет:
> >> > From: Heiher <r@hev.cc>
> >> >
> >>
> >> Before going in more depth for review, could you give more details which
> >> platforms are using it, what ABI is targeted (n64? something else?) Is
> >> MIPS going to be included in official UEFI spec?
> >
> > Also it seems that it targets yeeloong's and fuloong's we already
> support.
> > I'd like a good justification for this port over existing ones as it will
> > surely need maintenance, so we need a benefit to justify maintenance.
>
> The yeeloong and fuloong are based on Loongson-2 cpu platforms, They have
> been discontinued. In future, The new products will switch to full
> 64-bit softwares
> (from firmware to operating system).
>
> The exist mips port is mips o32 ABI and for non UEFI platforms in
> GRUB, This port is
> for MIPS n64 ABI and UEFI platform. I think using a new cpu type
> mips64 is better.
> The code is clear for maintenance. ;)
>
> >>
> >>
> >> _______________________________________________
> >> Grub-devel mailing list
> >> Grub-devel@gnu.org
> >> https://lists.gnu.org/mailman/listinfo/grub-devel
>
>
>
> --
> Best regards!
> Heiher
> http://hev.cc
>

[-- Attachment #2: Type: text/html, Size: 3251 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-02-27 16:22 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-02-13 15:57 [PATCH v2] mips64: Add support for 64-bit MIPS wangr
2017-02-13 19:01 ` Andrei Borzenkov
2017-02-13 19:29   ` Vladimir 'phcoder' Serbinenko
2017-02-14  1:34     ` Heiher
2017-02-27 16:22       ` Heiher
2017-02-14  1:24   ` Heiher

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).