[coreboot-gerrit] Change in coreboot[master]: util/cbfstool: Add ARM64 Image support
Patrick Rudolph (Code Review)
gerrit at coreboot.org
Mon Feb 26 12:15:46 CET 2018
Patrick Rudolph has uploaded this change for review. ( https://review.coreboot.org/23869
Change subject: util/cbfstool: Add ARM64 Image support
......................................................................
util/cbfstool: Add ARM64 Image support
Add support for booting Linux ARM64 Image.
* Add new ARM64 trampoline code
* Add ARM64 Image detection
* Parse the Image and mark it relocateable if no loadaddress was given
* Place the trampoline 64 KiB before the Linux Image
Tested on qemu-armv8 and Linux 4.15.
Change-Id: I9a8183a87de4dc3a4c4f038fe5b4912ada5d75f9
---
M payloads/external/linux/Makefile.inc
A payloads/external/linux/arm64image_loader.h
A payloads/external/linux/linux_trampoline_arm64.S
A payloads/external/linux/linux_trampoline_arm64.c
M util/cbfstool/Makefile.inc
M util/cbfstool/cbfs-payload-linux.c
M util/cbfstool/cbfstool.c
M util/cbfstool/common.h
8 files changed, 358 insertions(+), 7 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/69/23869/1
diff --git a/payloads/external/linux/Makefile.inc b/payloads/external/linux/Makefile.inc
index c0a2b0c..e3c5924 100644
--- a/payloads/external/linux/Makefile.inc
+++ b/payloads/external/linux/Makefile.inc
@@ -4,6 +4,7 @@
##
## Copyright (C) 2009-2010 coresystems GmbH
## Copyright (C) 2015 Google Inc.
+## Copyright 2018-present Facebook, Inc.
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
@@ -20,6 +21,14 @@
linuxdir:=$(top)/payloads/external/linux
+ifneq ($(GCC_CC_arm64),)
+$(linuxdir)/linux_trampoline_arm64.c: $(linuxdir)/linux_trampoline_arm64.S $(top)/src/arch/arm64/include/*
+ $(MAKE) -C $(linuxdir) linux_trampoline_arm64.c \
+ HOSTCC="$(HOSTCC)" \
+ CC="$(GCC_CC_arm64)" \
+ OBJCOPY="$(OBJCOPY_arm64)" \
+ CFLAGS="$(CFLAGS_arm64) $(armv8_flags) -I$(top)/src/arch/arm64/include"
+endif
ifneq ($(GCC_CC_x86_32),)
$(linuxdir)/linux_trampoline_x86.c: $(linuxdir)/linux_trampoline_x86.S $(top)/src/arch/x86/include/*
$(MAKE) -C $(linuxdir) linux_trampoline_x86.c \
diff --git a/payloads/external/linux/arm64image_loader.h b/payloads/external/linux/arm64image_loader.h
new file mode 100644
index 0000000..fdc5dee
--- /dev/null
+++ b/payloads/external/linux/arm64image_loader.h
@@ -0,0 +1,20 @@
+/*
+ * This file is part of coreboot project.
+ *
+ * Copyright 2018-present Facebook, Inc.
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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.
+ */
+
+/* trampoline */
+extern unsigned char linux_trampoline_arm64_bin[];
+extern unsigned int linux_trampoline_arm64_bin_len;
+
+#define TRAMPOLINE_SIZE (64 * KiB)
diff --git a/payloads/external/linux/linux_trampoline_arm64.S b/payloads/external/linux/linux_trampoline_arm64.S
new file mode 100644
index 0000000..c28f3a9
--- /dev/null
+++ b/payloads/external/linux/linux_trampoline_arm64.S
@@ -0,0 +1,120 @@
+/*
+ * linux_trampoline
+ *
+ * Copyright (C) 2013 Patrick Georgi <patrick at georgi-clan.de>
+ * Copyright 2018-present Facebook, Inc.
+ *
+ * This program 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; version 2 of the License.
+ *
+ * This program 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.
+ */
+
+/* NOTE: THIS CODE MUST REMAIN POSITION INDEPENDENT
+ * IT SHOULDN'T USE THE STACK
+ * AND IN GENERAL EXPECT NOTHING BUT RAM TO WORK
+ */
+
+.data
+#define TRAMPOLINE_SIZE (64 * 1024)
+#define HEADER_SIG 0x4f49424c // LBIO little endian
+#define CB_TAG_FORWARD 0x11
+#define CB_TAG_DEVICETREE 0x0033
+
+/*
+ * Find the devicetree that should have been placed in a coreboot table.
+ * Register usage:
+ * x0: base pointer
+ * x1: working register
+ * x2: working register
+ * x3: counter, initial value is the number of coreboot tables
+ * x4: start of trampoline, to calculcate the kernel position
+ */
+trampoline_start:
+ // Store entry point for later use
+ adr x4, trampoline_start
+ // x0 contains pointer to coreboot tables
+
+ // Verify coreboot table header
+
+ mov w2, HEADER_SIG >> 16
+ lsl w2, w2, 16
+ mov w1, (HEADER_SIG & 0xffff)
+ orr w2, w2, w1
+
+ // verify signature32 (header magic)
+ ldr w1, [x0, 0]
+ cmp w1, w2
+ b.ne _halt
+
+ // verify header_bytes
+ ldr w1, [x0, 4]
+ cmp w1, #0
+ b.eq _halt
+
+ // verify table_bytes
+ ldr w1, [x0, 16]
+ cmp w1, #0
+ b.eq _halt
+
+ // TODO: Signature check
+
+ // Number of table entries goes into w3
+ ldr w3, [x0, 20]
+
+ // Set pointer to first entry
+ ldr w1, [x0, 4]
+ add x0, x1, x0
+
+ // x0 contains the table entry pointer
+
+tablescan:
+ ldr w1, [x0, 0]
+ cmp w1, #CB_TAG_FORWARD
+ b.ne devicetree
+
+ ldr w1, [x0, 8]
+ add x0, x0, x1
+ b next
+
+devicetree:
+ ldr w1, [x0, 0]
+ cmp w1, #CB_TAG_DEVICETREE
+ b.ne next
+
+ mov x1, #8
+ add x0, x0, x1
+ b done
+
+next:
+ // Increment table entries pointer
+ ldr w1, [x0, 4]
+ add x0, x0, x1
+
+ // Decrement table entry counter
+ subs w3, w3, #1
+
+ b.ne tablescan
+
+ // not found, call the kernel without devicetree ?
+ b _halt
+done:
+ // devicetree pointer is in x0
+
+ // kernel entry point is trampoline_start + 64 KiB
+ // CBFSTOOL did make sure that the kernel is at the given offset
+ mov x1, #(TRAMPOLINE_SIZE)
+ add x1, x1, x4
+
+ // Jump to kernel
+ br x1
+
+_halt:
+ wfi
+ b _halt
+
+trampoline_end:
diff --git a/payloads/external/linux/linux_trampoline_arm64.c b/payloads/external/linux/linux_trampoline_arm64.c
new file mode 100644
index 0000000..b4bc2c6
--- /dev/null
+++ b/payloads/external/linux/linux_trampoline_arm64.c
@@ -0,0 +1,14 @@
+/* This file is automatically generated. Do not manually change */
+unsigned char linux_trampoline_arm64_bin[] = {
+ 0x04, 0x00, 0x00, 0x10, 0x22, 0xe9, 0x89, 0x52, 0x42, 0x3c, 0x10, 0x53, 0x81, 0x49, 0x88, 0x52,
+ 0x42, 0x00, 0x01, 0x2a, 0x01, 0x00, 0x40, 0xb9, 0x3f, 0x00, 0x02, 0x6b, 0xc1, 0x03, 0x00, 0x54,
+ 0x01, 0x04, 0x40, 0xb9, 0x3f, 0x00, 0x00, 0x71, 0x60, 0x03, 0x00, 0x54, 0x01, 0x10, 0x40, 0xb9,
+ 0x3f, 0x00, 0x00, 0x71, 0x00, 0x03, 0x00, 0x54, 0x03, 0x14, 0x40, 0xb9, 0x01, 0x04, 0x40, 0xb9,
+ 0x20, 0x00, 0x00, 0x8b, 0x01, 0x00, 0x40, 0xb9, 0x3f, 0x44, 0x00, 0x71, 0x81, 0x00, 0x00, 0x54,
+ 0x01, 0x08, 0x40, 0xb9, 0x00, 0x00, 0x01, 0x8b, 0x07, 0x00, 0x00, 0x14, 0x01, 0x00, 0x40, 0xb9,
+ 0x3f, 0xcc, 0x00, 0x71, 0x81, 0x00, 0x00, 0x54, 0x01, 0x01, 0x80, 0xd2, 0x00, 0x00, 0x01, 0x8b,
+ 0x06, 0x00, 0x00, 0x14, 0x01, 0x04, 0x40, 0xb9, 0x00, 0x00, 0x01, 0x8b, 0x63, 0x04, 0x00, 0x71,
+ 0x21, 0xfe, 0xff, 0x54, 0x04, 0x00, 0x00, 0x14, 0x21, 0x00, 0xa0, 0xd2, 0x21, 0x00, 0x04, 0x8b,
+ 0x20, 0x00, 0x1f, 0xd6, 0x7f, 0x20, 0x03, 0xd5, 0xff, 0xff, 0xff, 0x17
+};
+unsigned int linux_trampoline_arm64_bin_len = 156;
diff --git a/util/cbfstool/Makefile.inc b/util/cbfstool/Makefile.inc
index 0575e1d..c1626c4 100644
--- a/util/cbfstool/Makefile.inc
+++ b/util/cbfstool/Makefile.inc
@@ -39,6 +39,7 @@
cbfsobj += valstr.o
# linux as payload
cbfsobj += linux_trampoline_x86.o
+cbfsobj += linux_trampoline_arm64.o
cbfsobj += cbfs-payload-linux.o
# compression algorithms
diff --git a/util/cbfstool/cbfs-payload-linux.c b/util/cbfstool/cbfs-payload-linux.c
index 17e18ca..7e73db0 100644
--- a/util/cbfstool/cbfs-payload-linux.c
+++ b/util/cbfstool/cbfs-payload-linux.c
@@ -2,6 +2,7 @@
* cbfs-payload-linux
*
* Copyright (C) 2013 Patrick Georgi <patrick at georgi-clan.de>
+ * Copyright 2018-present Facebook, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -20,18 +21,20 @@
#include "common.h"
#include "cbfs.h"
#include "bzimage_loader.h"
+#include "arm64image_loader.h"
/*
* Current max number of segments include:
*
* 1. parameters
* 2. kernel
- * 3. trampoline
- * 4. optional cmdline
- * 5. optional initrd
- * 6. terminating entry segment
+ * 3. flags
+ * 4. trampoline
+ * 5. optional cmdline
+ * 6. optional initrd
+ * 7. terminating entry segment
*/
-#define MAX_NUM_SEGMENTS 6
+#define MAX_NUM_SEGMENTS 7
struct bzpayload {
/* Input variables. */
@@ -39,6 +42,7 @@
struct cbfs_payload_segment segs[MAX_NUM_SEGMENTS];
struct buffer parameters;
struct buffer kernel;
+ struct buffer flags;
struct buffer trampoline;
struct buffer cmdline;
struct buffer initrd;
@@ -93,6 +97,31 @@
(header->header == BZI_SIGNATURE);
}
+#define ARM64_IMAGE_KERNEL_HEADER_MAGIC 0x644d5241
+
+struct Arm64KernelHeader {
+ u32 code0;
+ u32 code1;
+ u64 text_offset;
+ u64 image_size;
+ u64 flags;
+ u64 res2;
+ u64 res3;
+ u64 res4;
+ u32 magic;
+ u32 res5;
+};
+
+/* Return true if buffer looks like an ARM64 Image */
+int probe_for_ARM64Image_header(const struct buffer *input)
+{
+ const struct Arm64KernelHeader *header =
+ (const struct Arm64KernelHeader *)input->data;
+ if (input->size < sizeof(*header))
+ return 0;
+ return (header->magic == ARM64_IMAGE_KERNEL_HEADER_MAGIC);
+}
+
static int bzp_init(struct bzpayload *bzp, enum comp_algo algo)
{
memset(bzp, 0, sizeof(*bzp));
@@ -169,12 +198,23 @@
return 0;
}
+static int bzp_add_flags(struct bzpayload *bzp,
+ struct cbfs_payload_flags *flags)
+{
+ bzp_add_segment(bzp, &bzp->flags, flags, 0);
+ xdr_be.put64(&bzp->flags, flags->f.u);
+ xdr_be.put32(&bzp->flags, flags->align);
+
+ return 0;
+}
+
static int bzp_init_output(struct bzpayload *bzp, const char *name)
{
size_t sz = 0;
sz += buffer_size(&bzp->parameters);
sz += buffer_size(&bzp->kernel);
+ sz += buffer_size(&bzp->flags);
sz += buffer_size(&bzp->trampoline);
sz += buffer_size(&bzp->cmdline);
sz += buffer_size(&bzp->initrd);
@@ -371,3 +411,137 @@
xdr_segs(output, bzp.segs, bzp.num_segments);
return 0;
}
+
+/*
+ * Add an ARM64 Linux Kernel Image as payload.
+ *
+ * The trampoline will locate the devicetree and pass it as argument x0.
+ *
+ * Memory map
+ * ...
+ * | |
+ * | Usable DRAM |
+ * | |
+ * --------------------------------| n * 2MiB + text-offset + image-size
+ * | |
+ * | Linux Kernel |
+ * | |
+ * --------------------------------| n * 2MiB + text-offset
+ * | |
+ * | Trampoline |
+ * | |
+ * --------------------------------| n * 2MiB + text-offset - 64 KiB (entry)
+ * | |
+ * | Usable DRAM |
+ * | |
+ * --------------------------------|
+ * | Devicetree |
+ * ------------------------------- | >= MAX((n - 256) * 2MiB, 0)
+ * | |
+ * ...
+ */
+
+int parse_ARM64Image_to_payload(const struct buffer *input,
+ struct buffer *output, uint64_t load_address,
+ enum comp_algo algo)
+{
+ const struct Arm64KernelHeader *header =
+ (const struct Arm64KernelHeader *)input->data;
+ struct buffer tmp;
+ struct bzpayload bzp;
+ uint64_t offset, image_size;
+ struct cbfs_payload_flags flags = {0};
+
+ if (bzp_init(&bzp, algo) != 0)
+ return -1;
+
+ if (linux_trampoline_arm64_bin_len > TRAMPOLINE_SIZE) {
+ ERROR("FIXME: trampoline size is too big\n");
+ return -1;
+ }
+
+ /*
+ * Prior to v3.17, the endianness of text_offset was not specified. In
+ * these cases image_size is zero and text_offset is 0x80000 in the
+ * endianness of the kernel. Where image_size is non-zero image_size is
+ * little-endian and must be respected. Where image_size is zero,
+ * text_offset can be assumed to be 0x80000.
+ */
+ if (header->image_size) {
+ offset = header->text_offset;
+ image_size = header->image_size;
+ } else {
+ offset = 0x80000;
+ // FIXME: How much space to reserve ?
+ image_size = input->size + 4 * MiB;
+ }
+ /*
+ * The Image must be placed text_offset bytes from a 2MB aligned base
+ * address anywhere in usable system RAM and called there. The region
+ * between the 2 MB aligned base address and the start of the image has
+ * no special significance to the kernel, and may be used for other
+ * purposes. At least image_size bytes from the start of the image must
+ * be free for use by the kernel.
+ */
+ load_address = ALIGN_UP(load_address, 2 * MiB);
+
+ /* Reserve some extra space if the trampoline doesn't fit */
+ if (offset < TRAMPOLINE_SIZE)
+ offset += 2 * MiB;
+
+ if (buffer_create(&tmp, image_size + offset, input->name)) {
+ ERROR("Failed to allocate a buffer\n");
+ return -1;
+ }
+
+ /* Clear trampoline memory */
+ memset(tmp.data, 0, tmp.size);
+
+ /* Place trampoline right before kernel */
+ memcpy(tmp.data + offset - TRAMPOLINE_SIZE, linux_trampoline_arm64_bin,
+ linux_trampoline_arm64_bin_len);
+
+ /* Place kernel at offset, right after trampoline */
+ memcpy(tmp.data + offset, input->data, input->size);
+
+ if (bzp_add_kernel(&bzp, &tmp, 0) != 0)
+ return -1;
+
+ /* Dynamic load address, tell the align */
+ if (!load_address) {
+ flags.f.relocateable = 1;
+ flags.align = 2 * MiB;
+
+ if (bzp_add_flags(&bzp, &flags))
+ return -1;
+ }
+
+ if (bzp_init_output(&bzp, input->name) != 0)
+ return -1;
+
+ if (!load_address) {
+ /* data block */
+ bzp_output_segment(&bzp, &bzp.flags, PAYLOAD_SEGMENT_FLAGS, 0);
+ ERROR("Adding flags\n");
+ }
+
+ /* code block */
+ bzp_output_segment(&bzp, &bzp.kernel, PAYLOAD_SEGMENT_CODE,
+ load_address);
+
+ /* Terminating entry segment. */
+ bzp_output_segment(&bzp, NULL, PAYLOAD_SEGMENT_ENTRY,
+ load_address + offset - TRAMPOLINE_SIZE);
+
+ /* Set size of buffer taking into account potential compression. */
+ buffer_set_size(&bzp.output, bzp.offset);
+ /* Make passed-in output buffer be valid. */
+ buffer_clone(output, &bzp.output);
+
+ /* Serialize the segments with the correct encoding. */
+ xdr_segs(output, bzp.segs, bzp.num_segments);
+
+ buffer_delete(&tmp);
+
+ return 0;
+}
diff --git a/util/cbfstool/cbfstool.c b/util/cbfstool/cbfstool.c
index 91b0290..899e32a 100644
--- a/util/cbfstool/cbfstool.c
+++ b/util/cbfstool/cbfstool.c
@@ -5,6 +5,7 @@
* written by Patrick Georgi <patrick.georgi at coresystems.de>
* Copyright (C) 2012 Google, Inc.
* Copyright (C) 2016 Siemens AG
+ * Copyright 2018-present Facebook, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -640,6 +641,11 @@
ret = parse_bzImage_to_payload(buffer, &output,
param.initrd, param.cmdline, param.compression);
+ /* Try ARM64 Image */
+ if (ret != 0 && probe_for_ARM64Image_header(buffer))
+ ret = parse_ARM64Image_to_payload(buffer, &output,
+ param.loadaddress, param.compression);
+
/* Not a supported payload type */
if (ret != 0) {
ERROR("Not a supported payload type (ELF / FV).\n");
@@ -1169,7 +1175,7 @@
{"add", "H:r:f:n:t:c:b:a:p:yvA:gh?", cbfs_add, true, true},
{"add-flat-binary", "H:r:f:n:l:e:c:b:p:vA:gh?", cbfs_add_flat_binary,
true, true},
- {"add-payload", "H:r:f:n:t:c:b:C:I:p:vA:gh?", cbfs_add_payload,
+ {"add-payload", "H:r:f:n:t:c:b:C:I:p:l:vA:gh?", cbfs_add_payload,
true, true},
{"add-stage", "a:H:r:f:n:t:c:b:P:S:p:yvA:gh?", cbfs_add_stage,
true, true},
@@ -1299,7 +1305,8 @@
"Add a component\n"
" add-payload [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
" [-c compression] [-b base-address] \\\n"
- " (linux specific: [-C cmdline] [-I initrd]) "
+ " (linux specific: [-C cmdline] [-I initrd] \\\n"
+ " [-l loadaddress]) "
"Add a payload to the ROM\n"
" add-stage [-r image,regions] -f FILE -n NAME [-A hash] \\\n"
" [-c compression] [-b base] [-S section-to-ignore] \\\n"
diff --git a/util/cbfstool/common.h b/util/cbfstool/common.h
index 6e366a1..4361191 100644
--- a/util/cbfstool/common.h
+++ b/util/cbfstool/common.h
@@ -193,6 +193,12 @@
int parse_bzImage_to_payload(const struct buffer *input,
struct buffer *output, const char *initrd,
char *cmdline, enum comp_algo algo);
+
+int probe_for_ARM64Image_header(const struct buffer *input);
+int parse_ARM64Image_to_payload(const struct buffer *input,
+ struct buffer *output, uint64_t load_address,
+ enum comp_algo algo);
+
int parse_flat_binary_to_payload(const struct buffer *input,
struct buffer *output,
uint32_t loadaddress,
--
To view, visit https://review.coreboot.org/23869
To unsubscribe, or for help writing mail filters, visit https://review.coreboot.org/settings
Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I9a8183a87de4dc3a4c4f038fe5b4912ada5d75f9
Gerrit-Change-Number: 23869
Gerrit-PatchSet: 1
Gerrit-Owner: Patrick Rudolph <patrick.rudolph at 9elements.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.coreboot.org/pipermail/coreboot-gerrit/attachments/20180226/73733a19/attachment-0001.html>
More information about the coreboot-gerrit
mailing list