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 <jmcne...@invisible.ca>
@@ -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 <jmcne...@invisible.ca>
+ * 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 */

Reply via email to