Module Name: src
Committed By: jmcneill
Date: Sun Feb 4 15:44:51 UTC 2018
Modified Files:
src/usr.bin/mkubootimage: mkubootimage.1 mkubootimage.c
Added Files:
src/usr.bin/mkubootimage: arm64.h
Log Message:
Add support for writing "AArch64 Linux kernel image" format images.
These images begin with a 64-byte header that includes a load offset,
image size, some flags, and a small (2 word) area at the start for
executable code.
These images are compatible with U-Boot's "booti" command, and can be
used to make U-Boot relocate our kernel to a 2MB aligned base address.
After relocation, U-Boot will jump to the code at the beginning of the
header, where we encode a relative branch forward instruction to branch
to the beginning of the kernel at offset +0x40.
To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/usr.bin/mkubootimage/arm64.h
cvs rdiff -u -r1.11 -r1.12 src/usr.bin/mkubootimage/mkubootimage.1
cvs rdiff -u -r1.22 -r1.23 src/usr.bin/mkubootimage/mkubootimage.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/usr.bin/mkubootimage/mkubootimage.1
diff -u src/usr.bin/mkubootimage/mkubootimage.1:1.11 src/usr.bin/mkubootimage/mkubootimage.1:1.12
--- src/usr.bin/mkubootimage/mkubootimage.1:1.11 Fri Sep 29 21:18:28 2017
+++ src/usr.bin/mkubootimage/mkubootimage.1 Sun Feb 4 15:44:51 2018
@@ -1,4 +1,4 @@
-.\" $NetBSD: mkubootimage.1,v 1.11 2017/09/29 21:18:28 jmcneill Exp $
+.\" $NetBSD: mkubootimage.1,v 1.12 2018/02/04 15:44:51 jmcneill Exp $
.\"
.\" Copyright (c) 2012 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -27,7 +27,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd September 29, 2017
+.Dd February 4, 2018
.Dt MKUBOOTIMAGE 1
.Os
.Sh NAME
@@ -41,6 +41,7 @@
.Op Fl C Po bz2 Ns | Ns gz Ns | Ns lzma Ns | Ns lzo Ns | Ns none Pc
.Op Fl E Ar address
.Op Fl e Ar address
+.Op Fl f Po arm64 Ns | Ns uimg Pc
.Op Fl m Ar magic
.Fl n Ar image
.Op Fl O Po freebsd Ns | Ns linux Ns | Ns netbsd Ns | Ns openbsd Pc
@@ -57,12 +58,16 @@ The arguments are as follows:
.Bl -tag -width indent
.It Fl A No ( arm Ns | Ns arm64 Ns | Ns i386 Ns | Ns mips Ns | Ns mips64 Ns | Ns or1k Ns | Ns powerpc Ns | Ns sh )
Defines the architecture.
-This is required.
+This is required for
+.Qq uimg
+format images.
.It Fl a Ar address
Sets the image load address.
This is an integer between 0 and
.Dv UINT32_MAX .
-This is required for all image types except for script, ramdisk, and kernel_noload.
+This is required for all
+.Qq uimg
+image types except for script, ramdisk, and kernel_noload.
.It Fl C No ( bz2 Ns | Ns gz Ns | Ns lzma Ns | Ns lzo Ns | Ns none )
Defines the compression.
The default is
@@ -93,10 +98,16 @@ or
are not set, the entry point defaults to the
image load address
.Pq Fl a .
+.It Fl f No ( arm64 Ns | Ns uimg )
+Defines the output image format type.
+The default is
+.Qq uimg .
.It Fl h
Display the usage and exit.
.It Fl m Ar magic
-Set the magic.
+Set the magic used for
+.Qq uimg
+format images.
This is an integer between 0 and
.Dv UINT32_MAX .
The default is
@@ -110,7 +121,9 @@ The default OS name is
.Qq netbsd .
.It Fl T No ( fs Ns | Ns kernel Ns | Ns kernel_noload Ns | Ns ramdisk Ns | Ns standalone Ns | Ns script )
Defines the image type.
-This is required.
+This is required for
+.Qq uimg
+format images.
.El
.Pp
The required
@@ -161,7 +174,7 @@ command first appeared in
The
.Nm
utility was originally written by
-.An Jared D. McNeill .
+.An Jared McNeill .
This manual page was written by
.An Jeremy C. Reed .
.\" .Sh CAVEATS
Index: src/usr.bin/mkubootimage/mkubootimage.c
diff -u src/usr.bin/mkubootimage/mkubootimage.c:1.22 src/usr.bin/mkubootimage/mkubootimage.c:1.23
--- src/usr.bin/mkubootimage/mkubootimage.c:1.22 Sun Nov 5 11:07:32 2017
+++ src/usr.bin/mkubootimage/mkubootimage.c Sun Feb 4 15:44:51 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: mkubootimage.c,v 1.22 2017/11/05 11:07:32 jmcneill Exp $ */
+/* $NetBSD: mkubootimage.c,v 1.23 2018/02/04 15:44:51 jmcneill Exp $ */
/*-
* Copyright (c) 2010 Jared D. McNeill <[email protected]>
@@ -30,15 +30,17 @@
#endif
#include <sys/cdefs.h>
-__RCSID("$NetBSD: mkubootimage.c,v 1.22 2017/11/05 11:07:32 jmcneill Exp $");
+__RCSID("$NetBSD: mkubootimage.c,v 1.23 2018/02/04 15:44:51 jmcneill Exp $");
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/endian.h>
+#include <sys/param.h>
#include <sys/uio.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
@@ -48,11 +50,18 @@ __RCSID("$NetBSD: mkubootimage.c,v 1.22
#include <unistd.h>
#include "uboot.h"
+#include "arm64.h"
#ifndef __arraycount
#define __arraycount(__x) (sizeof(__x) / sizeof(__x[0]))
#endif
+enum image_format {
+ FMT_UNKNOWN,
+ FMT_UIMG, /* Legacy U-Boot image */
+ FMT_ARM64, /* Linux ARM64 image (booti) */
+};
+
extern uint32_t crc32(const void *, size_t);
extern uint32_t crc32v(const struct iovec *, int);
@@ -64,6 +73,41 @@ static uint32_t image_loadaddr = 0;
static uint32_t image_entrypoint = 0;
static char *image_name;
static uint32_t image_magic = IH_MAGIC;
+static enum image_format image_format = FMT_UIMG;
+
+static const struct uboot_image_format {
+ enum image_format format;
+ const char *name;
+} uboot_image_format[] = {
+ { FMT_UIMG, "uimg" },
+ { FMT_ARM64, "arm64" },
+};
+
+static enum image_format
+get_image_format(const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < __arraycount(uboot_image_format); i++) {
+ if (strcmp(uboot_image_format[i].name, name) == 0)
+ return uboot_image_format[i].format;
+ }
+
+ return FMT_UNKNOWN;
+}
+
+static const char *
+get_image_format_name(enum image_format format)
+{
+ unsigned int i;
+
+ for (i = 0; i < __arraycount(uboot_image_format); i++) {
+ if (uboot_image_format[i].format == format)
+ return uboot_image_format[i].name;
+ }
+
+ return "Unknown";
+}
static const struct uboot_os {
enum uboot_image_os os;
@@ -225,13 +269,14 @@ usage(void)
fprintf(stderr, " -O <openbsd|netbsd|freebsd|linux>");
fprintf(stderr, " -T <standalone|kernel|kernel_noload|ramdisk|fs|script>");
fprintf(stderr, " -a <addr> [-e <ep>] [-m <magic>] -n <name>");
+ fprintf(stderr, " [-f <uimg|arm64>]");
fprintf(stderr, " <srcfile> <dstfile>\n");
exit(EXIT_FAILURE);
}
static void
-dump_header(struct uboot_image_header *hdr)
+dump_header_uimg(struct uboot_image_header *hdr)
{
time_t tm = ntohl(hdr->ih_time);
@@ -254,7 +299,7 @@ dump_header(struct uboot_image_header *h
}
static int
-generate_header(struct uboot_image_header *hdr, int kernel_fd)
+generate_header_uimg(struct uboot_image_header *hdr, int kernel_fd)
{
uint8_t *p;
struct stat st;
@@ -310,13 +355,56 @@ generate_header(struct uboot_image_heade
crc = crc32((void *)hdr, sizeof(*hdr));
hdr->ih_hcrc = htonl(crc);
- dump_header(hdr);
+ dump_header_uimg(hdr);
return 0;
}
+static void
+dump_header_arm64(struct arm64_image_header *hdr)
+{
+ printf(" magic: 0x%" PRIx32 "\n", le32toh(hdr->magic));
+ printf(" text offset: 0x%" PRIx64 "\n", le64toh(hdr->text_offset));
+ printf(" image size: %" PRIu64 "\n", le64toh(hdr->image_size));
+ printf(" flags: 0x%" PRIx64 "\n", le64toh(hdr->flags));
+}
+
static int
-write_image(struct uboot_image_header *hdr, int kernel_fd, int image_fd)
+generate_header_arm64(struct arm64_image_header *hdr, int kernel_fd)
+{
+ struct stat st;
+ uint32_t flags;
+ int error;
+
+ error = fstat(kernel_fd, &st);
+ if (error == -1) {
+ perror("stat");
+ return errno;
+ }
+
+ flags = 0;
+
+ flags |= __SHIFTIN(ARM64_FLAGS_PAGE_SIZE_4K,
+ ARM64_FLAGS_PAGE_SIZE);
+#if 0
+ flags |= __SHIFTIN(ARM64_FLAGS_PHYS_PLACEMENT_ANY,
+ ARM64_FLAGS_PHYS_PLACEMENT);
+#endif
+
+ memset(hdr, 0, sizeof(*hdr));
+ hdr->code0 = htole32(ARM64_CODE0);
+ hdr->text_offset = htole64(image_entrypoint);
+ hdr->image_size = htole64(st.st_size + sizeof(*hdr));
+ hdr->flags = htole32(flags);
+ hdr->magic = htole32(ARM64_MAGIC);
+
+ dump_header_arm64(hdr);
+
+ return 0;
+}
+
+static int
+write_image(void *hdr, size_t hdrlen, int kernel_fd, int image_fd)
{
uint8_t buf[4096];
ssize_t rlen, wlen;
@@ -330,8 +418,8 @@ write_image(struct uboot_image_header *h
return errno;
}
- wlen = write(image_fd, hdr, sizeof(*hdr));
- if (wlen != sizeof(*hdr)) {
+ wlen = write(image_fd, hdr, hdrlen);
+ if (wlen != (ssize_t)hdrlen) {
perror("short write");
return errno;
}
@@ -360,14 +448,15 @@ write_image(struct uboot_image_header *h
int
main(int argc, char *argv[])
{
- struct uboot_image_header hdr;
+ struct uboot_image_header hdr_uimg;
+ struct arm64_image_header hdr_arm64;
const char *src, *dest;
char *ep;
int kernel_fd, image_fd;
int ch;
unsigned long long num;
- while ((ch = getopt(argc, argv, "A:C:E:O:T:a:e:hm:n:")) != -1) {
+ while ((ch = getopt(argc, argv, "A:C:E:O:T:a:e:f:hm:n:")) != -1) {
switch (ch) {
case 'A': /* arch */
image_arch = get_arch(optarg);
@@ -404,6 +493,9 @@ main(int argc, char *argv[])
if (ch == 'E')
image_entrypoint = bswap32(image_entrypoint);
break;
+ case 'f': /* image format */
+ image_format = get_image_format(optarg);
+ break;
case 'm': /* magic */
errno = 0;
num = strtoul(optarg, &ep, 0);
@@ -430,21 +522,38 @@ main(int argc, char *argv[])
if (image_entrypoint == 0)
image_entrypoint = image_loadaddr;
- if (image_arch == IH_ARCH_UNKNOWN ||
- image_type == IH_TYPE_UNKNOWN ||
- image_name == NULL)
- usage();
+ switch (image_format) {
+ case FMT_UIMG:
+ if (image_arch == IH_ARCH_UNKNOWN ||
+ image_type == IH_TYPE_UNKNOWN ||
+ image_name == NULL)
+ usage();
+ /* NOTREACHED */
- switch (image_type) {
- case IH_TYPE_SCRIPT:
- case IH_TYPE_RAMDISK:
- case IH_TYPE_KERNEL_NOLOAD:
+ switch (image_type) {
+ case IH_TYPE_SCRIPT:
+ case IH_TYPE_RAMDISK:
+ case IH_TYPE_KERNEL_NOLOAD:
+ break;
+ default:
+ if (image_loadaddr == 0)
+ usage();
+ /* NOTREACHED */
+ break;
+ }
break;
- default:
- if (image_loadaddr == 0)
+
+ case FMT_ARM64:
+ if (image_arch != IH_ARCH_UNKNOWN &&
+ image_arch != IH_ARCH_ARM64)
usage();
/* NOTREACHED */
+
break;
+
+ default:
+ usage();
+ /* NOTREACHED */
}
src = argv[0];
@@ -461,11 +570,30 @@ main(int argc, char *argv[])
return EXIT_FAILURE;
}
- if (generate_header(&hdr, kernel_fd) != 0)
- return EXIT_FAILURE;
+ printf(" image type: %s\n", get_image_format_name(image_format));
- if (write_image(&hdr, kernel_fd, image_fd) != 0)
- return EXIT_FAILURE;
+ switch (image_format) {
+ case FMT_UIMG:
+ if (generate_header_uimg(&hdr_uimg, kernel_fd) != 0)
+ return EXIT_FAILURE;
+
+ if (write_image(&hdr_uimg, sizeof(hdr_uimg),
+ kernel_fd, image_fd) != 0)
+ return EXIT_FAILURE;
+
+ break;
+ case FMT_ARM64:
+ if (generate_header_arm64(&hdr_arm64, kernel_fd) != 0)
+ return EXIT_FAILURE;
+
+ if (write_image(&hdr_arm64, sizeof(hdr_arm64),
+ kernel_fd, image_fd) != 0)
+ return EXIT_FAILURE;
+
+ break;
+ default:
+ break;
+ }
close(image_fd);
close(kernel_fd);
Added files:
Index: src/usr.bin/mkubootimage/arm64.h
diff -u /dev/null src/usr.bin/mkubootimage/arm64.h:1.1
--- /dev/null Sun Feb 4 15:44:51 2018
+++ src/usr.bin/mkubootimage/arm64.h Sun Feb 4 15:44:51 2018
@@ -0,0 +1,67 @@
+/* $NetBSD: arm64.h,v 1.1 2018/02/04 15:44:51 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2018 Jared McNeill <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _HAVE_ARM64_H
+#define _HAVE_ARM64_H
+
+/*
+ * AArch64 Linux kernel image header, as specified in
+ * https://www.kernel.org/doc/Documentation/arm64/booting.txt
+ */
+
+/* 64-byte kernel image header */
+struct arm64_image_header {
+ uint32_t code0; /* Executable code */
+ uint32_t code1; /* Executable code */
+ uint64_t text_offset; /* Image load offset */
+ uint64_t image_size; /* Effective image size */
+ uint64_t flags; /* kernel flags */
+ uint64_t res2; /* reserved */
+ uint64_t res3; /* reserved */
+ uint64_t res4; /* reserved */
+ uint32_t magic; /* Magic number ("ARM\x64") */
+ uint32_t res5; /* reserved (used for PE COFF offset) */
+};
+
+/* Kernel flags */
+#define ARM64_FLAGS_ENDIAN_BE __BIT(0)
+#define ARM64_FLAGS_PAGE_SIZE __BITS(2,1)
+#define ARM64_FLAGS_PAGE_SIZE_UNSPEC 0
+#define ARM64_FLAGS_PAGE_SIZE_4K 1
+#define ARM64_FLAGS_PAGE_SIZE_16K 2
+#define ARM64_FLAGS_PAGE_SIZE_64K 3
+#define ARM64_FLAGS_PHYS_PLACEMENT __BIT(3)
+#define ARM64_FLAGS_PHYS_PLACEMENT_DRAM_BASE 0
+#define ARM64_FLAGS_PHYS_PLACEMENT_ANY 1
+
+/* Magic */
+#define ARM64_MAGIC 0x644d5241
+
+/* Executable code. Program relative branch forward 64 bytes. */
+#define ARM64_CODE0 0x14000010
+
+#endif /* !_HAVE_ARM64_H */