From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1kXrUT-0006EZ-JR for mharc-grub-devel@gnu.org; Wed, 28 Oct 2020 15:52:13 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:45032) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kXrUS-0006BP-42 for Grub-devel@gnu.org; Wed, 28 Oct 2020 15:52:12 -0400 Received: from shcp25.hosting.zen.net.uk ([82.71.204.30]:32998) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kXrUP-00045C-NW for Grub-devel@gnu.org; Wed, 28 Oct 2020 15:52:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=monkeyircd.org; s=default; h=Content-Transfer-Encoding:MIME-Version: Content-Type:References:In-Reply-To:Date:Cc:To:Reply-To:From:Subject: Message-ID:Sender:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=kFOT0VtSkkUPnstjcbPvoKy1Zzmu+NhDcuND6HaxeCw=; b=M1RQyl6GbMAsvsAo14SZpgQ0/2 k1w0+ES8AocsbzBAmyfN7XzgSZdVw9e0coOoQFonvR9WCzHesEN60XM7vjvat74u7oCHugBDCuCzz PDbjVUXd1zT3PPgenEl1F75XyRP0y4CZgmXUf6GW4swAnz1JR41XoC7iVRwZf+xRq1GdsSZxqiSmG j7nZ0lMEidTb1ivXbKybsxbFWPnKArtFmzQVNeZgJNd9bGdheBRuH5TVKkDkVnwnej7qOOtnOhsBK jpuvr4bIitwA11ZSrpDUMkoU+pr0O9WMLFdlfAcXE5iz5JuVP5kHwNL+vaxebrllX7aRwdHP/bYO/ Kx7QUhaA==; Received: from [82.69.123.44] (port=45074 helo=zoidberg.local.monkeyircd.org) by shcp25.hosting.zen.net.uk with esmtpsa (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.93) (envelope-from ) id 1kXrUN-002ijo-Of; Wed, 28 Oct 2020 19:52:08 +0000 Message-ID: <7d1613687d09f767fd9b657120abe72e1ff9c2c5.camel@monkeyircd.org> Subject: [PATCH 02/05] Enable multiboot2 support on arm64-efi target From: Chris Plant Reply-To: chris@monkeyircd.org To: Grub-devel@gnu.org Cc: chris@monkeyircd.org Date: Wed, 28 Oct 2020 19:52:07 +0000 In-Reply-To: <4b23bf36d0a833ff038709ae7c443647976dcd8c.camel@monkeyircd.org> References: <4b23bf36d0a833ff038709ae7c443647976dcd8c.camel@monkeyircd.org> Content-Type: text/plain; charset="UTF-8" User-Agent: Evolution 3.36.4-2 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-OutGoing-Spam-Status: No, score=-1.0 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - shcp25.hosting.zen.net.uk X-AntiAbuse: Original Domain - gnu.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - monkeyircd.org X-Get-Message-Sender-Via: shcp25.hosting.zen.net.uk: authenticated_id: chris@monkeyircd.org X-Authenticated-Sender: shcp25.hosting.zen.net.uk: chris@monkeyircd.org Received-SPF: pass client-ip=82.71.204.30; envelope-from=chris@monkeyircd.org; helo=shcp25.hosting.zen.net.uk X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/28 15:45:20 X-ACL-Warn: Detected OS = Linux 3.11 and newer [fuzzy] X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 28 Oct 2020 19:52:12 -0000 Add ARM64 relocator code to support multiboot2 loader Signed-off-by: Chris plant --- grub-core/lib/arm64/relocator.c | 267 ++++++++++++++++++++++++++++ grub-core/lib/arm64/relocator_asm.S | 57 ++++++ include/grub/arm64/relocator.h | 52 ++++++ 3 files changed, 376 insertions(+) create mode 100644 grub-core/lib/arm64/relocator.c create mode 100644 grub-core/lib/arm64/relocator_asm.S create mode 100644 include/grub/arm64/relocator.h diff --git a/grub-core/lib/arm64/relocator.c b/grub- core/lib/arm64/relocator.c new file mode 100644 index 000000000..a287bd5ff --- /dev/null +++ b/grub-core/lib/arm64/relocator.c @@ -0,0 +1,267 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2020 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 +#include + + +/* Defines to simplify creating machine code instructions */ + +#define AARCH64_INSTR_MOVZ_64 0xd2800000 +#define AARCH64_INSTR_MOVK_64 0xf2800000 +#define AARCH64_INSTR_MOVZ_32 0x52800000 +#define AARCH64_INSTR_MOVK_32 0x72800000 +#define AARCH64_INSTR_BR 0xd61f0000 +#define AARCH64_INSTR_NOP 0xd503201f + +#define AARCH64_INSTR_SHIFT_16 1 << 21 +#define AARCH64_INSTR_SHIFT_32 2 << 21 +#define AARCH64_INSTR_SHIFT_48 3 << 21 + +extern grub_uint8_t grub_relocator_forward_start; +extern grub_uint8_t grub_relocator_forward_end; +extern grub_uint8_t grub_relocator_backward_start; +extern grub_uint8_t grub_relocator_backward_end; +extern grub_uint32_t grub_relocator_check_endian; + +#define REGW32_SIZEOF (2 * sizeof (grub_uint32_t)) +#define REGW64_SIZEOF (4 * sizeof (grub_uint32_t)) +#define JUMP_SIZEOF (2 * sizeof (grub_uint32_t)) + +#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator_##x##_end \ + - &grub_relocator_##x##_start) +#define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \ + + REGW32_SIZEOF * 3) +grub_size_t grub_relocator_align = sizeof (grub_uint32_t); +grub_size_t grub_relocator_forward_size; +grub_size_t grub_relocator_backward_size; +grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW64_SIZEOF; + +void +grub_cpu_relocator_init (void) +{ + grub_relocator_forward_size = RELOCATOR_SIZEOF(forward); + grub_relocator_backward_size = RELOCATOR_SIZEOF(backward); +} + +/* + * Create machine code in memory @ *target to write val + * to register regn using 64 bit register width + */ +static void +write_reg64 (int regn, grub_uint64_t val, void **target) +{ + grub_uint16_t hword; + + hword = val >> 48 & 0xFFFF; + *(grub_uint32_t *) *target = AARCH64_INSTR_MOVZ_64 | AARCH64_INSTR_SHIFT_48 | + (hword << 5) | regn; + *target = ((grub_uint32_t *) *target) + 1; + + hword = val >> 32 & 0xFFFF; + *(grub_uint32_t *) *target = AARCH64_INSTR_MOVK_64 | AARCH64_INSTR_SHIFT_32 | + (hword << 5) | regn; + *target = ((grub_uint32_t *) *target) + 1; + + hword = val >> 16 & 0xFFFF; + *(grub_uint32_t *) *target = AARCH64_INSTR_MOVK_64 | AARCH64_INSTR_SHIFT_16 | + (hword << 5) | regn; + *target = ((grub_uint32_t *) *target) + 1; + + hword = val >> 0 & 0xFFFF; + *(grub_uint32_t *) *target = AARCH64_INSTR_MOVK_64 | (hword << 5) | regn; + *target = ((grub_uint32_t *) *target) + 1; +} + +/* + * Create machine code in memory @ *target to write val + * to register regn using 32 bit register width + */ +static void +write_reg32 (int regn, grub_uint32_t val, void **target) +{ + grub_uint16_t hword; + + hword = val >> 16 & 0xFFFF; + *(grub_uint32_t *) *target = AARCH64_INSTR_MOVZ_32 | AARCH64_INSTR_SHIFT_16 | + (hword << 5) | regn; + *target = ((grub_uint32_t *) *target) + 1; + + + hword = val & 0xFFFF; + *(grub_uint32_t *) *target = AARCH64_INSTR_MOVK_32 | (hword << 5) | regn; + + *target = ((grub_uint32_t *) *target) + 1; +} + + + +/* + * Create machine code in memory @ *target to jump to the + * address in register regn + */ +static void +write_jump (int regn, void **target) +{ + + /* br x(regn) */ + *(grub_uint32_t *) *target = AARCH64_INSTR_BR | (regn << 5); + *target = ((grub_uint32_t *) *target) + 1; + + /* nop. */ + *(grub_uint32_t *) *target = AARCH64_INSTR_NOP; + *target = ((grub_uint32_t *) *target) + 1; +} + + +/* + * Write machine code to load a 64 bit memory location to + * a register and then jump to it + */ +void +grub_cpu_relocator_jumper (void *rels, grub_addr_t addr) +{ + /* Write address to the register */ + write_reg64(8,addr,&rels); + + /* Jump to the address in the register */ + write_jump(8,&rels); +} + +/* + * Use general purpose registers to pass variables + * src = x8, dest = x9, size = x10 + */ +void +grub_cpu_relocator_backward (void *ptr, void *src, void *dest, + grub_size_t size) +{ + + write_reg64(8,(grub_uint64_t) src, &ptr); + write_reg64(9,(grub_uint64_t) dest, &ptr); + write_reg64(10,(grub_uint64_t) size, &ptr); + + grub_memcpy (ptr, &grub_relocator_backward_start, + RELOCATOR_SRC_SIZEOF (backward)); +} + + +void +grub_cpu_relocator_forward (void *ptr, void *src, void *dest, + grub_size_t size) +{ + write_reg64(8,(grub_uint64_t) src, &ptr); + write_reg64(9,(grub_uint64_t) dest, &ptr); + write_reg64(10,(grub_uint64_t) size, &ptr); + + grub_memcpy (ptr, &grub_relocator_forward_start, + RELOCATOR_SRC_SIZEOF (forward)); +} + + +grub_err_t +grub_relocator32_boot (struct grub_relocator *rel, + struct grub_relocator32_state state) +{ + grub_relocator_chunk_t ch; + void *ptr; + grub_err_t err; + void *relst; + grub_size_t relsize; + grub_size_t stateset_size = 32 * REGW32_SIZEOF + JUMP_SIZEOF; + unsigned i; + grub_addr_t vtarget; + + err = grub_relocator_alloc_chunk_align (rel, &ch, 0, + (0xffffffff - stateset_size) + + 1, stateset_size, + sizeof (grub_uint32_t), + GRUB_RELOCATOR_PREFERENCE_NONE, 0); + + if (err) + return err; + + ptr = get_virtual_current_address (ch); + + for (i = 0; i < 32; i++) + write_reg32 (i, state.w[i], &ptr); + + write_jump (state.pc_reg, &ptr); + + vtarget = (grub_addr_t) grub_map_memory (get_physical_target_address (ch), + stateset_size); + + err = grub_relocator_prepare_relocs (rel, vtarget, &relst, &relsize); + if (err) + return err; + + grub_arch_sync_caches ((void *) relst, relsize); + + ((void (*) (void)) (relst)) (); + + /* Not reached. */ + return GRUB_ERR_NONE; + +} + +grub_err_t +grub_relocator64_boot (struct grub_relocator *rel, + struct grub_relocator64_state state) +{ + grub_relocator_chunk_t ch; + void *ptr; + grub_err_t err; + void *relst; + grub_size_t relsize; + grub_size_t stateset_size = 32 * REGW64_SIZEOF + JUMP_SIZEOF; + unsigned i; + + err = grub_relocator_alloc_chunk_align (rel, &ch, 0, + (0xffffffff - stateset_size) + + 1, stateset_size, + sizeof (grub_uint32_t), + GRUB_RELOCATOR_PREFERENCE_NONE, 0); + if (err) + return err; + + ptr = get_virtual_current_address (ch); + for (i = 0; i < 32; i++) + write_reg64 (i, state.x[i], &ptr); + write_jump (state.pc_reg, &ptr); + + err = grub_relocator_prepare_relocs (rel, get_physical_target_address(ch), &relst, &relsize); + if (err) + return err; + + grub_arch_sync_caches ((void *) relst, relsize); + + ((void (*) (void)) relst) (); + + /* Not reached. */ + return GRUB_ERR_NONE; + + +} diff --git a/grub-core/lib/arm64/relocator_asm.S b/grub- core/lib/arm64/relocator_asm.S new file mode 100644 index 000000000..117f98dbe --- /dev/null +++ b/grub-core/lib/arm64/relocator_asm.S @@ -0,0 +1,57 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2020 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 ;. + */ + +/* + * aarch64/ARM64 relocator code, heavily based on MIPS code + * adapted by Chris Plant + */ + +#include + + .p2align 4 /* force 16-byte alignment */ + +VARIABLE (grub_relocator_forward_start) + +copycont1: + ldr x11,[x8] + str x11,[x9] + add x8,x8,#1 + add x9,x9,#1 + sub x10,x10,#1 + cbnz x10, copycont1 + +VARIABLE (grub_relocator_forward_end) + +VARIABLE (grub_relocator_backward_start) + + add x9,x9,x10 + add x8,x8,x10 + /* Backward movsl is implicitly off-by-one. compensate that. */ + sub x9,x9,#1 + sub x8,x8,#1 +copycont2: + ldr x11,[x8] + str x11,[x9] + sub x8,x8,#1 + sub x9,x9,#1 + sub x10,x10, #1 + cbnz x10, copycont2 + + +VARIABLE (grub_relocator_backward_end) + diff --git a/include/grub/arm64/relocator.h b/include/grub/arm64/relocator.h new file mode 100644 index 000000000..4409c472a --- /dev/null +++ b/include/grub/arm64/relocator.h @@ -0,0 +1,52 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2020 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_RELOCATOR_CPU_HEADER +#define GRUB_RELOCATOR_CPU_HEADER 1 + +#include +#include +#include + +struct grub_relocator64_state +{ + /* General Purpose Registers (xn) */ + grub_uint64_t x[32]; + + /* The register containing the new pc value */ + int pc_reg; +}; + +struct grub_relocator32_state +{ + /* General Purpose Registers (xn) */ + grub_uint32_t w[32]; + + int pc_reg; +}; + +grub_err_t +grub_relocator64_boot (struct grub_relocator *rel, + struct grub_relocator64_state state); + + +grub_err_t +grub_relocator32_boot (struct grub_relocator *rel, + struct grub_relocator32_state state); + +#endif /* ! GRUB_RELOCATOR_CPU_HEADER */ -- 2.28.0