grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v2] mips64: Add support for 64-bit MIPS.


From: wangr
Subject: [PATCH v2] mips64: Add support for 64-bit MIPS.
Date: Mon, 13 Feb 2017 23:57:50 +0800

From: Heiher <address@hidden>

---
 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






reply via email to

[Prev in Thread] Current Thread [Next in Thread]