From patchwork Thu Nov 14 12:35:39 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Leif Lindholm X-Patchwork-Id: 21497 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-gg0-f198.google.com (mail-gg0-f198.google.com [209.85.161.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id 540E623FBC for ; Thu, 14 Nov 2013 12:36:13 +0000 (UTC) Received: by mail-gg0-f198.google.com with SMTP id l2sf2882627ggn.1 for ; Thu, 14 Nov 2013 04:36:12 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:x-original-sender:x-original-authentication-results :precedence:mailing-list:list-id:list-post:list-help:list-archive :list-unsubscribe; bh=crxCNGR6H0AAILxP5EUuMgrRofA3z6dyrj7zGAKeKwY=; b=Y9cfFSfWTUmDa+jX5n63aw/VB6zhiwnFgkzovH3j3B+filfIWdlfIooaNPWkESzaDY qrIuhkvHAqn6QfFTAkEYRk1qyMsXlik38grfMrt9J7aMsZcP4YDM4rdXT8WJurKEu+rt T4xotFmdBdQb6/82wXedI1Erat0as64swCaTLlw3+9YlL3sQUgX97TYXZKOG09RUeSnV REY4DPuqR/LNPoqulzJHW9ha7icNM7cVDtpPD9pGbYsyK1zjeE0Tc221f/L9fz7VVvsr 58v0buBk8fBN3dJy8KDy1sC5IOBj0jEbkWhu4DOAxH5hnbQ0F9NwtjvTSfNtxY4PC1VB dgYw== X-Gm-Message-State: ALoCoQlFYT/7p8thlfuY4/w0jwTNJeXXdcWv94WcPyxkQy6IJV9FZLO4HHQwN6lP4zzFNG6HdMD9 X-Received: by 10.58.182.167 with SMTP id ef7mr471333vec.15.1384432572486; Thu, 14 Nov 2013 04:36:12 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.49.121.69 with SMTP id li5ls973424qeb.39.gmail; Thu, 14 Nov 2013 04:36:12 -0800 (PST) X-Received: by 10.221.40.10 with SMTP id to10mr570015vcb.22.1384432572389; Thu, 14 Nov 2013 04:36:12 -0800 (PST) Received: from mail-ve0-f177.google.com (mail-ve0-f177.google.com [209.85.128.177]) by mx.google.com with ESMTPS id xz7si17018994vcb.50.2013.11.14.04.36.12 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 14 Nov 2013 04:36:12 -0800 (PST) Received-SPF: neutral (google.com: 209.85.128.177 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.177; Received: by mail-ve0-f177.google.com with SMTP id jz11so1744710veb.8 for ; Thu, 14 Nov 2013 04:36:12 -0800 (PST) X-Received: by 10.220.169.203 with SMTP id a11mr573480vcz.26.1384432572151; Thu, 14 Nov 2013 04:36:12 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.220.174.196 with SMTP id u4csp312625vcz; Thu, 14 Nov 2013 04:36:11 -0800 (PST) X-Received: by 10.180.12.12 with SMTP id u12mr2324517wib.48.1384432570746; Thu, 14 Nov 2013 04:36:10 -0800 (PST) Received: from mail-wi0-f178.google.com (mail-wi0-f178.google.com [209.85.212.178]) by mx.google.com with ESMTPS id ax1si16102251wjc.107.2013.11.14.04.36.10 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 14 Nov 2013 04:36:10 -0800 (PST) Received-SPF: neutral (google.com: 209.85.212.178 is neither permitted nor denied by best guess record for domain of leif.lindholm@linaro.org) client-ip=209.85.212.178; Received: by mail-wi0-f178.google.com with SMTP id hn6so2400685wib.17 for ; Thu, 14 Nov 2013 04:36:10 -0800 (PST) X-Received: by 10.194.94.167 with SMTP id dd7mr1443534wjb.43.1384432569905; Thu, 14 Nov 2013 04:36:09 -0800 (PST) Received: from mohikan.mushroom.smurfnet.nu (cpc4-cmbg17-2-0-cust71.5-4.cable.virginm.net. [86.14.224.72]) by mx.google.com with ESMTPSA id bs15sm66235982wib.10.2013.11.14.04.36.08 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 14 Nov 2013 04:36:09 -0800 (PST) From: Leif Lindholm To: grub-devel@gnu.org Cc: patches@linaro.org, Leif Lindholm Subject: [RFC] New port to arm64-efi Date: Thu, 14 Nov 2013 12:35:39 +0000 Message-Id: <1384432539-7696-1-git-send-email-leif.lindholm@linaro.org> X-Mailer: git-send-email 1.7.10.4 X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: leif.lindholm@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.177 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , 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 --- 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 diff --git a/ChangeLog b/ChangeLog index d68b33a..35e32f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2013-11-14 Leif Lindholm + + * New port to arm64-efi. + 2013-11-13 Colin Watson * grub-core/osdep/unix/emuconsole.c (put): Pacify the compiler on diff --git a/Makefile.util.def b/Makefile.util.def index 59e3e73..e5ba9fa 100644 --- a/Makefile.util.def +++ b/Makefile.util.def @@ -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; diff --git a/conf/Makefile.common b/conf/Makefile.common index 0dc26db..bdb32d6 100644 --- a/conf/Makefile.common +++ b/conf/Makefile.common @@ -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 diff --git a/configure.ac b/configure.ac index d76cef0..2ee2d72 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/gentpl.py b/gentpl.py index 825739d..5089d62 100644 --- a/gentpl.py +++ b/gentpl.py @@ -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"] diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index 6c20c7d..61287b0 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -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 diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 6114519..c7dfd90 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -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; }; diff --git a/grub-core/kern/arm64/cache.c b/grub-core/kern/arm64/cache.c new file mode 100644 index 0000000..deea2f8 --- /dev/null +++ b/grub-core/kern/arm64/cache.c @@ -0,0 +1,40 @@ +#include +#include +#include + +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); +} diff --git a/grub-core/kern/arm64/cache_flush.S b/grub-core/kern/arm64/cache_flush.S new file mode 100644 index 0000000..44ca6a6 --- /dev/null +++ b/grub-core/kern/arm64/cache_flush.S @@ -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 . + */ + +#include + + .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 diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c new file mode 100644 index 0000000..afd0de2 --- /dev/null +++ b/grub-core/kern/arm64/dl.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * 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; +} diff --git a/grub-core/kern/arm64/dl_helper.c b/grub-core/kern/arm64/dl_helper.c new file mode 100644 index 0000000..2827370 --- /dev/null +++ b/grub-core/kern/arm64/dl_helper.c @@ -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 . + */ + +#include +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/grub-core/kern/arm64/efi/startup.S b/grub-core/kern/arm64/efi/startup.S new file mode 100644 index 0000000..781c2b0 --- /dev/null +++ b/grub-core/kern/arm64/efi/startup.S @@ -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 . + */ + +#include + + .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 diff --git a/grub-core/lib/arm64/setjmp.S b/grub-core/lib/arm64/setjmp.S new file mode 100644 index 0000000..adaafe4 --- /dev/null +++ b/grub-core/lib/arm64/setjmp.S @@ -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 . + */ + +#include + + .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 diff --git a/grub-core/lib/efi/halt.c b/grub-core/lib/efi/halt.c index ce93db3..e9441c8 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__) +#if !defined(__ia64__) && !defined(__arm__) && !defined(__aarch64__) grub_acpi_halt (); #endif efi_call_4 (grub_efi_system_table->runtime_services->reset_system, diff --git a/grub-core/lib/setjmp.S b/grub-core/lib/setjmp.S index feb7b43..f6e4905 100644 --- a/grub-core/lib/setjmp.S +++ b/grub-core/lib/setjmp.S @@ -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 diff --git a/include/grub/arm64/efi/memory.h b/include/grub/arm64/efi/memory.h new file mode 100644 index 0000000..c9a61bb --- /dev/null +++ b/include/grub/arm64/efi/memory.h @@ -0,0 +1 @@ +#include diff --git a/include/grub/arm64/reloc.h b/include/grub/arm64/reloc.h new file mode 100644 index 0000000..606d71c --- /dev/null +++ b/include/grub/arm64/reloc.h @@ -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 . + */ + +#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 diff --git a/include/grub/arm64/setjmp.h b/include/grub/arm64/setjmp.h new file mode 100644 index 0000000..111d697 --- /dev/null +++ b/include/grub/arm64/setjmp.h @@ -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 . + */ + +#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 */ diff --git a/include/grub/arm64/time.h b/include/grub/arm64/time.h new file mode 100644 index 0000000..4128506 --- /dev/null +++ b/include/grub/arm64/time.h @@ -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 . + */ + +#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 */ diff --git a/include/grub/arm64/types.h b/include/grub/arm64/types.h new file mode 100644 index 0000000..91fe027 --- /dev/null +++ b/include/grub/arm64/types.h @@ -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 . + */ + +#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 */ diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index f750340..3af0911 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -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) diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h index 7cacabd..4adea60 100644 --- a/include/grub/efi/pe32.h +++ b/include/grub/efi/pe32.h @@ -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 diff --git a/include/grub/elf.h b/include/grub/elf.h index f64d6a8..140d24d 100644 --- a/include/grub/elf.h +++ b/include/grub/elf.h @@ -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 */ diff --git a/util/grub-install.in b/util/grub-install.in index 4cddf5e..a882acf 100644 --- a/util/grub-install.in +++ b/util/grub-install.in @@ -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 diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c index 36a683d..b88e9b9 100644 --- a/util/grub-mkimagexx.c +++ b/util/grub-mkimagexx.c @@ -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, diff --git a/util/mkimage.c b/util/mkimage.c index a5a683b..963dd94 100644 --- a/util/mkimage.c +++ b/util/mkimage.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -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)))