@@ -1,3 +1,7 @@
+2013-11-14 Leif Lindholm <leif.lindholm@linaro.org>
+
+ * New port to arm64-efi.
+
2013-11-13 Colin Watson <cjwatson@ubuntu.com>
* grub-core/osdep/unix/emuconsole.c (put): Pacify the compiler on
@@ -173,6 +173,7 @@ program = {
common = grub-core/osdep/init.c;
common = grub-core/kern/arm/dl_helper.c;
+ common = grub-core/kern/arm64/dl_helper.c;
extra_dist = util/grub-mkimagexx.c;
@@ -22,6 +22,9 @@ if COND_arm
CFLAGS_PLATFORM += -mthumb-interwork -mlong-calls
LDFLAGS_PLATFORM = -Wl,--wrap=__clear_cache
endif
+if COND_arm64
+ CFLAGS_PLATFORM += -mcmodel=large
+endif
#FIXME: discover and check XEN headers
CPPFLAGS_XEN = -I/usr/include
@@ -103,6 +103,9 @@ case "$target_cpu" in
arm*)
target_cpu=arm;
;;
+ aarch64*)
+ target_cpu=arm64;
+ ;;
esac
# Specify the platform (such as firmware).
@@ -124,6 +127,7 @@ if test "x$with_platform" = x; then
mips-*) platform=arc ;;
ia64-*) platform=efi ;;
arm-*) platform=uboot ;;
+ arm64-*) platform=efi ;;
*) AC_MSG_ERROR([unsupported CPU: "$target_cpu"]) ;;
esac
else
@@ -164,6 +168,7 @@ case "$target_cpu"-"$platform" in
mipsel-loongson) ;;
arm-uboot) ;;
arm-efi) ;;
+ arm64-efi) ;;
*-emu) ;;
*) AC_MSG_ERROR([platform "$platform" is not supported for target CPU "$target_cpu"]) ;;
esac
@@ -208,6 +213,7 @@ case "$platform" in
esac
case "$target_cpu" in
arm) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_ARM=1" ;;
+ arm64) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_ARM64=1" ;;
mips |mipsel) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS=1" ;;
sparc64) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_SPARC64=1" ;;
esac
@@ -1435,6 +1441,8 @@ AM_CONDITIONAL([COND_mipseb], [test x$target_cpu = xmips])
AM_CONDITIONAL([COND_arm], [test x$target_cpu = xarm ])
AM_CONDITIONAL([COND_arm_uboot], [test x$target_cpu = xarm -a x$platform = xuboot])
AM_CONDITIONAL([COND_arm_efi], [test x$target_cpu = xarm -a x$platform = xefi])
+AM_CONDITIONAL([COND_arm64], [test x$target_cpu = xarm64 ])
+AM_CONDITIONAL([COND_arm64_efi], [test x$target_cpu = xarm64 -a x$platform = xefi])
AM_CONDITIONAL([COND_HOST_HURD], [test x$host_kernel = xhurd])
AM_CONDITIONAL([COND_HOST_LINUX], [test x$host_kernel = xlinux])
@@ -24,7 +24,7 @@ GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot",
"i386_xen", "x86_64_xen",
"mips_loongson", "sparc64_ieee1275",
"powerpc_ieee1275", "mips_arc", "ia64_efi",
- "mips_qemu_mips", "arm_uboot", "arm_efi" ]
+ "mips_qemu_mips", "arm_uboot", "arm_efi", "arm64_efi" ]
GROUPS = {}
@@ -38,9 +38,10 @@ GROUPS["mips"] = [ "mips_loongson", "mips_qemu_mips", "mips_arc" ]
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" ]
+GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi" ]
GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ]
GROUPS["uboot"] = [ "arm_uboot" ]
GROUPS["xen"] = [ "i386_xen", "x86_64_xen" ]
@@ -66,7 +67,7 @@ GROUPS["terminfomodule"] = GRUB_PLATFORMS[:];
for i in GROUPS["terminfoinkernel"]: GROUPS["terminfomodule"].remove(i)
# Flattened Device Trees (FDT)
-GROUPS["fdt"] = [ "arm_uboot", "arm_efi" ]
+GROUPS["fdt"] = [ "arm64_efi", "arm_uboot", "arm_efi" ]
# Miscelaneous groups schedulded to disappear in future
GROUPS["i386_coreboot_multiboot_qemu"] = ["i386_coreboot", "i386_multiboot", "i386_qemu"]
@@ -234,6 +234,11 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
endif
+if COND_arm64_efi
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
+endif
+
if COND_emu
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/datetime.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/misc.h
@@ -67,6 +67,9 @@ kernel = {
arm_efi_ldflags = '-Wl,-r,-d';
arm_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
+ arm64_efi_ldflags = '-Wl,-r,-d';
+ arm64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version';
+
i386_pc_ldflags = '$(TARGET_IMG_LDFLAGS)';
i386_pc_ldflags = '$(TARGET_IMG_BASE_LDOPT),0x9000';
@@ -106,6 +109,7 @@ kernel = {
powerpc_ieee1275_startup = kern/powerpc/ieee1275/startup.S;
arm_uboot_startup = kern/arm/uboot/startup.S;
arm_efi_startup = kern/arm/efi/startup.S;
+ arm64_efi_startup = kern/arm64/efi/startup.S;
common = kern/command.c;
common = kern/corecmd.c;
@@ -194,6 +198,8 @@ kernel = {
arm_efi = kern/arm/efi/init.c;
arm_efi = kern/arm/efi/misc.c;
+ arm64_efi = kern/arm/efi/init.c;
+
i386_pc = kern/i386/pc/init.c;
i386_pc = kern/i386/pc/mmap.c;
i386_pc = term/i386/pc/console.c;
@@ -254,6 +260,11 @@ kernel = {
arm = kern/arm/cache.c;
arm = kern/arm/misc.S;
+ arm64 = kern/arm64/cache.c;
+ arm64 = kern/arm64/cache_flush.S;
+ arm64 = kern/arm64/dl.c;
+ arm64 = kern/arm64/dl_helper.c;
+
emu = disk/host.c;
emu = kern/emu/cache_s.S;
emu = kern/emu/hostdisk.c;
@@ -750,6 +761,7 @@ module = {
enable = mips_arc;
enable = ia64_efi;
enable = arm_efi;
+ enable = arm64_efi;
enable = arm_uboot;
};
@@ -845,6 +857,7 @@ module = {
ia64_efi = lib/efi/reboot.c;
x86_64_efi = lib/efi/reboot.c;
arm_efi = lib/efi/reboot.c;
+ arm64_efi = lib/efi/reboot.c;
powerpc_ieee1275 = lib/ieee1275/reboot.c;
sparc64_ieee1275 = lib/ieee1275/reboot.c;
mips_arc = lib/mips/arc/reboot.c;
@@ -1707,6 +1720,7 @@ module = {
enable = x86;
enable = ia64_efi;
enable = arm_efi;
+ enable = arm64_efi;
enable = mips;
};
new file mode 100644
@@ -0,0 +1,40 @@
+#include <grub/cache.h>
+#include <grub/misc.h>
+#include <grub/cpu/system.h>
+
+grub_int64_t grub_arch_cache_dlinesz;
+grub_int64_t grub_arch_cache_ilinesz;
+
+/* Prototypes for asm functions. */
+void grub_arch_sync_caches_real (void *address, grub_size_t len);
+
+static void
+probe_caches (void)
+{
+ grub_uint32_t cache_type;
+
+ /* Read Cache Type Register */
+ asm volatile ("mrs %0, ctr_el0": "=r"(cache_type));
+
+ grub_arch_cache_dlinesz = 8 << ((cache_type >> 16) & 0xf);
+ grub_arch_cache_ilinesz = 8 << (cache_type & 0xf);
+
+ grub_dprintf("cache", "D$ line size: %lld\n",
+ (long long) grub_arch_cache_dlinesz);
+ grub_dprintf("cache", "I$ line size: %lld\n",
+ (long long) grub_arch_cache_ilinesz);
+}
+
+void
+grub_arch_sync_caches (void *address, grub_size_t len)
+{
+ if (grub_arch_cache_dlinesz == 0)
+ probe_caches();
+ if (grub_arch_cache_dlinesz == 0)
+ grub_fatal ("Unknown cache line size!");
+
+ grub_dprintf("cache", "syncing caches for %p-%lx\n",
+ address, (grub_addr_t) address + len);
+
+ grub_arch_sync_caches_real (address, len);
+}
new file mode 100644
@@ -0,0 +1,74 @@
+/*
+ * 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 "cache_flush.S"
+ .text
+
+/*
+ * Simple cache maintenance functions
+ */
+
+// r0 - *beg (inclusive)
+// r1 - *end (exclusive)
+clean_dcache_range:
+ // Clean data cache for range to point-of-unification
+ ldr x2, =EXT_C(grub_arch_cache_dlinesz)
+ ldr x2, [x2]
+ sub x3, x2, #1 // align "beg" to start of line
+ mvn x3, x3
+ and x0, x0, x3
+1: cmp x0, x1
+ bge 2f
+ dc cvau, x0 // Clean Virtual Address to PoU
+ add x0, x0, x2 // Next line
+ b 1b
+2: dsb ish
+ ret
+
+// r0 - *beg (inclusive)
+// r1 - *end (exclusive)
+invalidate_icache_range:
+ // Invalidate instruction cache for range to point-of-unification
+ ldr x2, =EXT_C(grub_arch_cache_ilinesz)
+ ldr x2, [x2]
+ sub x3, x2, #1 // align "beg" to start of line
+ mvn x3, x3
+ and x0, x0, x3
+1: cmp x0, x1
+ bge 2f
+ ic ivau, x0 // Invalidate Virtual Address to PoU
+ add x0, x0, x2 // Next line
+ b 1b
+ // Branch predictor invalidation not needed on AArch64
+2: dsb ish
+ isb
+ ret
+
+// void grub_arch_sync_caches_real (void *address, grub_size_t len)
+FUNCTION(grub_arch_sync_caches_real)
+ dsb ish
+ add x1, x0, x1
+ stp x0, x30, [sp, #-16]!
+ stp x0, x1, [sp, #-16]!
+ bl clean_dcache_range
+ ldp x0, x1, [sp], #16
+ bl invalidate_icache_range
+ ldp x0, x30, [sp], #16
+ ret
new file mode 100644
@@ -0,0 +1,199 @@
+/* dl.c - arch-dependent part of loadable module support */
+/*
+ * 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/dl.h>
+#include <grub/elf.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/i18n.h>
+#include <grub/cpu/reloc.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. */
+ if (e->e_ident[EI_CLASS] != ELFCLASS64
+ || e->e_ident[EI_DATA] != ELFDATA2LSB || e->e_machine != EM_AARCH64)
+ return grub_error (GRUB_ERR_BAD_OS,
+ N_("invalid arch-dependent ELF magic"));
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Unified function for both REL and RELA
+ */
+static grub_err_t
+do_relX (Elf_Shdr * relhdr, Elf_Ehdr * e, grub_dl_t mod)
+{
+ grub_err_t retval;
+ grub_dl_segment_t segment;
+ Elf_Rel *rel;
+ Elf_Rela *rela;
+ Elf_Sym *symbol;
+ int i, entnum;
+ unsigned long long entsize;
+
+ /* Find the target segment for this relocation section. */
+ for (segment = mod->segment ; segment != 0 ; segment = segment->next)
+ if (segment->section == relhdr->sh_info)
+ break;
+ if (!segment)
+ return grub_error (GRUB_ERR_EOF, N_("relocation segment not found"));
+
+ rel = (Elf_Rel *) ((grub_addr_t) e + relhdr->sh_offset);
+ rela = (Elf_Rela *) rel;
+ if (relhdr->sh_type == SHT_RELA)
+ entsize = sizeof (Elf_Rela);
+ else
+ entsize = sizeof (Elf_Rel);
+
+ entnum = relhdr->sh_size / entsize;
+ retval = GRUB_ERR_NONE;
+
+ grub_dprintf("dl", "Processing %d relocation entries.\n", entnum);
+
+ /* Step through all relocations */
+ for (i = 0, symbol = mod->symtab; i < entnum; i++)
+ {
+ void *place;
+ grub_uint64_t sym_addr, symidx, reltype;
+
+ if (rel->r_offset >= segment->size)
+ return grub_error (GRUB_ERR_BAD_MODULE,
+ "reloc offset is out of the segment");
+
+ symidx = ELF_R_SYM (rel->r_info);
+ reltype = ELF_R_TYPE (rel->r_info);
+
+ sym_addr = symbol[symidx].st_value;
+ if (relhdr->sh_type == SHT_RELA)
+ sym_addr += rela->r_addend;
+
+ place = (void *) ((grub_addr_t) segment->addr + rel->r_offset);
+
+ switch (reltype)
+ {
+ case R_AARCH64_ABS64:
+ {
+ grub_uint64_t *abs_place = place;
+
+ grub_dprintf ("dl", " reloc_abs64 %p => 0x%016llx\n",
+ place, (unsigned long long) sym_addr);
+
+ *abs_place = (grub_uint64_t) sym_addr;
+ }
+ break;
+ case R_AARCH64_CALL26:
+ case R_AARCH64_JUMP26:
+ retval = grub_arm64_reloc_xxxx26 (place, sym_addr);
+ break;
+ default:
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ N_("relocation 0x%x is not implemented yet"),
+ reltype);
+ }
+
+ if (retval != GRUB_ERR_NONE)
+ break;
+
+ rel = (Elf_Rel *) ((grub_addr_t) rel + entsize);
+ rela++;
+ }
+
+ return retval;
+}
+
+/*
+ * Verify that provided ELF header contains reference to a symbol table
+ */
+static int
+has_symtab (Elf_Ehdr * e)
+{
+ int i;
+ Elf_Shdr *s;
+
+ for (i = 0, s = (Elf_Shdr *) ((grub_addr_t) e + e->e_shoff);
+ i < e->e_shnum;
+ i++, s = (Elf_Shdr *) ((grub_addr_t) s + e->e_shentsize))
+ if (s->sh_type == SHT_SYMTAB)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * grub_arch_dl_relocate_symbols():
+ * Locates the relocations section of the ELF object, and calls
+ * do_relX() to deal with it.
+ */
+grub_err_t
+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
+{
+ Elf_Ehdr *e = ehdr;
+ Elf_Shdr *s;
+ unsigned i;
+
+ if (!has_symtab (e))
+ return grub_error (GRUB_ERR_BAD_MODULE, N_("no symbol table"));
+
+#define FIRST_SHDR(x) ((Elf_Shdr *) ((grub_addr_t)(x) + (x)->e_shoff))
+#define NEXT_SHDR(x, y) ((Elf_Shdr *) ((grub_addr_t)(y) + (x)->e_shentsize))
+
+ for (i = 0, s = FIRST_SHDR (e); i < e->e_shnum; i++, s = NEXT_SHDR (e, s))
+ {
+ grub_err_t ret;
+
+ switch (s->sh_type)
+ {
+ case SHT_REL:
+ case SHT_RELA:
+ {
+ ret = do_relX (s, e, mod);
+ if (ret != GRUB_ERR_NONE)
+ return ret;
+ }
+ break;
+ case SHT_ARM_ATTRIBUTES:
+ case SHT_NOBITS:
+ case SHT_NULL:
+ case SHT_PROGBITS:
+ case SHT_SYMTAB:
+ case SHT_STRTAB:
+ break;
+ default:
+ {
+ grub_dprintf ("dl", "unhandled section_type: %d (0x%08x)\n",
+ s->sh_type, s->sh_type);
+ return GRUB_ERR_NOT_IMPLEMENTED_YET;
+ };
+ }
+ }
+
+#undef FIRST_SHDR
+#undef NEXT_SHDR
+
+ return GRUB_ERR_NONE;
+}
new file mode 100644
@@ -0,0 +1,72 @@
+/* dl_helper.c - relocation helper functions for modules and grub-mkimage */
+/*
+ * 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/dl.h>
+#include <grub/elf.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+#include <grub/mm.h>
+#include <grub/i18n.h>
+#include <grub/cpu/reloc.h>
+
+static grub_ssize_t
+sign_compress_offset (grub_ssize_t offset, int bitpos)
+{
+ return offset & ((1LL << (bitpos + 1)) - 1);
+}
+
+/*
+ * grub_arm64_reloc_xxxx26():
+ *
+ * JUMP26/CALL26 relocations for B and BL instructions.
+ */
+
+grub_err_t
+grub_arm64_reloc_xxxx26 (grub_uint32_t *place, Elf64_Addr adjust)
+{
+ grub_uint32_t insword, insmask;
+ grub_ssize_t offset, offset_low, offset_high;
+
+ insword = grub_le_to_cpu32 (*place);
+ insmask = 0xfc000000;
+
+ offset_low = -(1 << 27);
+ offset_high = (1 << 27) - 1;
+
+ offset = adjust;
+#ifndef GRUB_UTIL
+ offset -= (grub_addr_t) place;
+#endif
+
+ if ((offset < offset_low) || (offset > offset_high))
+ {
+ return grub_error (GRUB_ERR_BAD_MODULE,
+ N_("CALL26 Relocation out of range"));
+ }
+
+ grub_dprintf ("dl", " reloc_xxxx64 %p %c= 0x%llx\n",
+ place, offset > 0 ? '+' : '-',
+ offset < 0 ? (long long) -(unsigned long long) offset : offset);
+
+ offset = sign_compress_offset (offset, 27) >> 2;
+
+ *place = grub_cpu_to_le32 ((insword & insmask) | offset);
+
+ return GRUB_ERR_NONE;
+}
new file mode 100644
@@ -0,0 +1,34 @@
+/*
+ * 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
+FUNCTION(_start)
+ /*
+ * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in x1/x0.
+ */
+ ldr x2, =EXT_C(grub_efi_image_handle)
+ str x0, [x2]
+ ldr x2, =EXT_C(grub_efi_system_table)
+ str x1, [x2]
+ ldr x2, =EXT_C(grub_main)
+ br x2
+
+ .end
new file mode 100644
@@ -0,0 +1,53 @@
+/*
+ * 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 "setjmp.S"
+ .text
+
+/*
+ * int grub_setjmp (grub_jmp_buf env)
+ */
+FUNCTION(grub_setjmp)
+ stp x19, x20, [x0], #16
+ stp x21, x22, [x0], #16
+ stp x23, x24, [x0], #16
+ stp x25, x26, [x0], #16
+ stp x27, x28, [x0], #16
+ stp x29, x30, [x0], #16
+ mov x1, sp
+ str x1, [x0]
+ mov x0, #0
+ ret
+
+/*
+ * int grub_longjmp (grub_jmp_buf env, int val)
+ */
+FUNCTION(grub_longjmp)
+ ldp x19, x20, [x0], #16
+ ldp x21, x22, [x0], #16
+ ldp x23, x24, [x0], #16
+ ldp x25, x26, [x0], #16
+ ldp x27, x28, [x0], #16
+ ldp x29, x30, [x0], #16
+ ldr x2, [x0]
+ mov sp, x2
+ cmp x1, #0
+ csel x0, x1, x0, ne
+ ret
@@ -29,7 +29,7 @@ void
grub_halt (void)
{
grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
-#if !defined(__ia64__) && !defined(__arm__)
+#if !defined(__ia64__) && !defined(__arm__) && !defined(__aarch64__)
grub_acpi_halt ();
#endif
efi_call_4 (grub_efi_system_table->runtime_services->reset_system,
@@ -13,6 +13,8 @@
#include "./ia64/longjmp.S"
#elif defined(__arm__)
#include "./arm/setjmp.S"
+#elif defined(__aarch64__)
+#include "./arm64/setjmp.S"
#else
#error "Unknown target cpu type"
#endif
new file mode 100644
@@ -0,0 +1 @@
+#include <grub/efi/memory.h>
new file mode 100644
@@ -0,0 +1,24 @@
+/*
+ * 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/>.
+ */
+
+#ifndef GRUB_ARM64_RELOC_H
+#define GRUB_ARM64_RELOC_H 1
+
+grub_err_t grub_arm64_reloc_xxxx26 (grub_uint32_t *target, Elf64_Addr sym_addr);
+
+#endif
new file mode 100644
@@ -0,0 +1,27 @@
+/*
+ * 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/>.
+ */
+
+#ifndef GRUB_SETJMP_CPU_HEADER
+#define GRUB_SETJMP_CPU_HEADER 1
+
+typedef unsigned long long grub_jmp_buf[13];
+
+int grub_setjmp (grub_jmp_buf env) __attribute__ ((returns_twice));
+void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn));
+
+#endif /* ! GRUB_SETJMP_CPU_HEADER */
new file mode 100644
@@ -0,0 +1,29 @@
+/*
+ * 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/>.
+ */
+
+#ifndef KERNEL_CPU_TIME_HEADER
+#define KERNEL_CPU_TIME_HEADER 1
+
+static __inline void
+grub_cpu_idle (void)
+{
+ /* FIXME: this can't work until we handle interrupts. */
+/* __asm__ __volatile__ ("wfi"); */
+}
+
+#endif /* ! KERNEL_CPU_TIME_HEADER */
new file mode 100644
@@ -0,0 +1,34 @@
+/*
+ * 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/>.
+ */
+
+#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
+
+/* currently only support little-endian. */
+#undef GRUB_TARGET_WORDS_BIGENDIAN
+
+/* Unaligned accesses only supported if MMU enabled */
+#define GRUB_HAVE_UNALIGNED_ACCESS 1
+
+#endif /* ! GRUB_TYPES_CPU_HEADER */
@@ -1534,7 +1534,8 @@ 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__)
+#if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
+ || defined (__aarch64__)
#define efi_call_0(func) func()
#define efi_call_1(func, a) func(a)
@@ -67,6 +67,7 @@ struct grub_pe32_coff_header
#define GRUB_PE32_MACHINE_IA64 0x200
#define GRUB_PE32_MACHINE_X86_64 0x8664
#define GRUB_PE32_MACHINE_ARMTHUMB_MIXED 0x01c2
+#define GRUB_PE32_MACHINE_ARM64 0xAA64
#define GRUB_PE32_RELOCS_STRIPPED 0x0001
#define GRUB_PE32_EXECUTABLE_IMAGE 0x0002
@@ -246,6 +246,7 @@ typedef struct
#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */
#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
#define EM_NUM 95
+#define EM_AARCH64 183 /* ARM 64-bit architecture */
/* If it is necessary to assign new unofficial EM_* values, please
pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
@@ -2062,6 +2063,21 @@ typedef Elf32_Addr Elf32_Conflict;
#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */
+/* AArch64 relocs. */
+#define R_AARCH64_NONE 0 /* No relocation. */
+#define R_AARCH64_ABS64 257 /* Direct 64 bit. */
+#define R_AARCH64_ABS32 258 /* Direct 32 bit. */
+#define R_AARCH64_JUMP26 282 /* 26-bit relative. */
+#define R_AARCH64_CALL26 283 /* 26-bit relative. */
+#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */
+#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */
+#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */
+#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */
+#define R_AARCH64_TLS_DTPMOD64 1028 /* Module number, 64 bit. */
+#define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */
+#define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */
+#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */
+
/* ARM relocs. */
#define R_ARM_NONE 0 /* No reloc */
#define R_ARM_PC24 1 /* PC relative 26 bit branch */
@@ -280,6 +280,8 @@ if [ x$source_directory = x ]; then
;;
x"arm"*)
target="arm-uboot";;
+ x"aarch64"*)
+ target="arm64-efi";;
*)
gettext "Unable to determine your platform. Use --target." ;
echo ;;
@@ -434,6 +436,8 @@ if [ x"$grub_modinfo_platform" = xefi ]; then
efi_file=BOOTIA64.EFI ;;
arm)
efi_file=BOOTARM.EFI ;;
+ arm64)
+ efi_file=BOOTAARCH64.EFI ;;
esac
else
# It is convenient for each architecture to have a different
@@ -450,6 +454,8 @@ if [ x"$grub_modinfo_platform" = xefi ]; then
efi_file=grubia64.efi ;;
arm)
efi_file=grubarm.efi ;;
+ arm64)
+ efi_file=grubarm64.efi ;;
*)
efi_file=grub.efi ;;
esac
@@ -718,6 +718,35 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
break;
}
break;
+ case EM_AARCH64:
+ {
+ sym_addr += addend;
+ switch (ELF_R_TYPE (info))
+ {
+ case R_AARCH64_ABS64:
+ {
+ *target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr);
+ }
+ break;
+ case R_AARCH64_JUMP26:
+ case R_AARCH64_CALL26:
+ {
+ grub_err_t err;
+ sym_addr -= offset;
+ sym_addr -= SUFFIX (entry_point);
+ err = grub_arm64_reloc_xxxx26((grub_uint32_t *)target,
+ sym_addr);
+ if (err)
+ grub_util_error ("%s", grub_errmsg);
+ }
+ break;
+ default:
+ grub_util_error (_("relocation %d is not implemented yet"),
+ (unsigned long long) ELF_R_TYPE (info));
+ break;
+ }
+ break;
+ }
#endif
#if defined(MKIMAGE_ELF32)
case EM_ARM:
@@ -995,6 +1024,32 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
break;
}
break;
+ case EM_AARCH64:
+ switch (ELF_R_TYPE (info))
+ {
+ case R_AARCH64_ABS64:
+ {
+ Elf_Addr addr;
+
+ addr = section_address + offset;
+ current_address
+ = SUFFIX (add_fixup_entry) (&lst,
+ GRUB_PE32_REL_BASED_DIR64,
+ addr, 0, current_address,
+ image_target);
+ }
+ break;
+ /* Relative relocations do not require fixup entries. */
+ case R_AARCH64_CALL26:
+ case R_AARCH64_JUMP26:
+ break;
+ default:
+ grub_util_error (_("fixup for relocation %d is not implemented yet"),
+ (unsigned long long) ELF_R_TYPE (info));
+ break;
+ }
+ break;
+ break;
#if defined(MKIMAGE_ELF32)
case EM_ARM:
switch (ELF_R_TYPE (info))
@@ -1358,7 +1413,7 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
image_target);
if (*start == 0)
grub_util_error ("start symbol is not defined");
-
+
SUFFIX (entry_point) = (Elf_Addr) *start;
/* Resolve addresses in the virtual address space. */
@@ -1367,7 +1422,7 @@ SUFFIX (load_image) (const char *kernel_path, size_t *exec_size,
num_sections, strtab,
out_img, ia64_toff, ia64_got_off,
image_target);
-
+
*reloc_size = SUFFIX (make_reloc_section) (e, reloc_section,
section_vaddresses, sections,
section_entsize, num_sections,
@@ -42,6 +42,7 @@
#include <grub/efi/pe32.h>
#include <grub/uboot/image.h>
#include <grub/arm/reloc.h>
+#include <grub/arm64/reloc.h>
#include <grub/ia64/reloc.h>
#include <grub/osdep/hostfile.h>
#include <grub/util/install.h>
@@ -562,6 +563,22 @@ static const struct grub_install_image_target_desc image_targets[] =
.pe_target = GRUB_PE32_MACHINE_ARMTHUMB_MIXED,
.elf_target = EM_ARM,
},
+ {
+ .dirname = "arm64-efi",
+ .names = { "arm64-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_ARM64,
+ .elf_target = EM_AARCH64,
+ },
};
#define grub_target_to_host32(x) (grub_target_to_host32_real (image_target, (x)))
This patch brings support for UEFI on the 64-bit ARM architecture. It does not yet include a Linux loader, as the boot protocol for UEFI platforms is not yet fully agreed. The chainloader can be used to load a kernel with an integrated UEFI stub loader. Instructions for how to build and set up UEFI on the ARM Foundation Model (registration required) can be found at: http://sourceforge.net/apps/mediawiki/tianocore/index.php?title=ArmPlatformPkg/AArch64 It depends on Vladimir's __ctz[sd]i2 implementation, without which grub-mkimage will fail with a "missing symbol" error. Signed-off-by: Leif Lindholm <leif.lindholm@linaro.org> --- ChangeLog | 4 + Makefile.util.def | 1 + conf/Makefile.common | 3 + configure.ac | 8 ++ gentpl.py | 7 +- grub-core/Makefile.am | 5 + grub-core/Makefile.core.def | 14 +++ grub-core/kern/arm64/cache.c | 40 ++++++++ grub-core/kern/arm64/cache_flush.S | 74 ++++++++++++++ grub-core/kern/arm64/dl.c | 199 ++++++++++++++++++++++++++++++++++++ grub-core/kern/arm64/dl_helper.c | 72 +++++++++++++ grub-core/kern/arm64/efi/startup.S | 34 ++++++ grub-core/lib/arm64/setjmp.S | 53 ++++++++++ grub-core/lib/efi/halt.c | 2 +- grub-core/lib/setjmp.S | 2 + include/grub/arm64/efi/memory.h | 1 + include/grub/arm64/reloc.h | 24 +++++ include/grub/arm64/setjmp.h | 27 +++++ include/grub/arm64/time.h | 29 ++++++ include/grub/arm64/types.h | 34 ++++++ include/grub/efi/api.h | 3 +- include/grub/efi/pe32.h | 1 + include/grub/elf.h | 16 +++ util/grub-install.in | 6 ++ util/grub-mkimagexx.c | 59 ++++++++++- util/mkimage.c | 17 +++ 26 files changed, 728 insertions(+), 7 deletions(-) create mode 100644 grub-core/kern/arm64/cache.c create mode 100644 grub-core/kern/arm64/cache_flush.S create mode 100644 grub-core/kern/arm64/dl.c create mode 100644 grub-core/kern/arm64/dl_helper.c create mode 100644 grub-core/kern/arm64/efi/startup.S create mode 100644 grub-core/lib/arm64/setjmp.S create mode 100644 include/grub/arm64/efi/memory.h create mode 100644 include/grub/arm64/reloc.h create mode 100644 include/grub/arm64/setjmp.h create mode 100644 include/grub/arm64/time.h create mode 100644 include/grub/arm64/types.h