Module Name: src
Committed By: martin
Date: Sun Sep 22 10:20:16 UTC 2019
Modified Files:
src/usr.sbin/installboot [netbsd-9]: evboards.c evboards.h
Log Message:
Pull up following revision(s) (requested by thorpej in ticket #210):
usr.sbin/installboot/evboards.h: revision 1.2
usr.sbin/installboot/evboards.c: revision 1.3
Add support for additional install step directives to enable using
installboot(8) to write u-boot images to SPI NOR and other types of
raw flash devices: input-block-size, input-pad-size, output-size, and
output-block-size.
Add the ability to create aliases for install objects, useful for when
e.g. sdmmc and emmc share the same steps.
Tested on an A20-OLinuXino-LIME2-e16Gs16M by bouyer@.
XXX pullup netbsd-9
To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.2.4.1 src/usr.sbin/installboot/evboards.c
cvs rdiff -u -r1.1 -r1.1.4.1 src/usr.sbin/installboot/evboards.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/usr.sbin/installboot/evboards.c
diff -u src/usr.sbin/installboot/evboards.c:1.2 src/usr.sbin/installboot/evboards.c:1.2.4.1
--- src/usr.sbin/installboot/evboards.c:1.2 Sun May 12 13:47:09 2019
+++ src/usr.sbin/installboot/evboards.c Sun Sep 22 10:20:16 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: evboards.c,v 1.2 2019/05/12 13:47:09 maya Exp $ */
+/* $NetBSD: evboards.c,v 1.2.4.1 2019/09/22 10:20:16 martin Exp $ */
/*-
* Copyright (c) 2019 The NetBSD Foundation, Inc.
@@ -35,10 +35,11 @@
#include <sys/cdefs.h>
#if !defined(__lint)
-__RCSID("$NetBSD: evboards.c,v 1.2 2019/05/12 13:47:09 maya Exp $");
+__RCSID("$NetBSD: evboards.c,v 1.2.4.1 2019/09/22 10:20:16 martin Exp $");
#endif /* !__lint */
#include <sys/types.h>
+#include <sys/param.h> /* for roundup() */
#include <sys/stat.h>
#include <assert.h>
#include <err.h>
@@ -199,6 +200,7 @@ __RCSID("$NetBSD: evboards.c,v 1.2 2019/
* -- "u-boot-install-sdmmc" (for SD cards)
* -- "u-boot-install-emmc" (for eMMC modules)
* -- "u-boot-install-usb" (for USB block storage)
+ * -- "u-boot-install-spi" (for SPI NOR flash)
* --
* -- These installation steps will be selectable using
* -- the "media=..." option to installboot(8).
@@ -324,6 +326,91 @@ __RCSID("$NetBSD: evboards.c,v 1.2 2019/
* <integer>512</integer>
* </dict>
* </array>
+ *
+ * There are some addditional directives for installing on raw flash devices:
+ *
+ * <key>u-boot-install-spi</key>
+ * <array>
+ * <!-- This board's SPI NOR flash is 16Mbit (2MB) in size,
+ * -- arranged as 32 512Kbit (64KB) blocks.
+ * <dict>
+ * <key>file-name</key>
+ * <string>u-boot-with-spl.bin</string>
+ *
+ * <!-- Key: "input-block-size".
+ * -- Value: an integer specifying how much file
+ * -- data to read per input block before
+ * -- padding. Must be used in conjunction
+ * -- with "input-pad-size".
+ * -- (optional)
+ * -->
+ * <key>input-block-size</key>
+ * <integer>2048</integer>
+ *
+ * <!-- Key: "input-pad-size".
+ * -- Value: an integer specifing the amount of
+ * -- zero padding inserted per input block.
+ * -- Must be used in cojunction with
+ * -- "input-block-size".
+ * -- (optional)
+ * -->
+ * <key>input-pad-size</key>
+ * <integer>2048</integer>
+ *
+ * <!-- Key: "output-size".
+ * -- Value: an integer specifying the total
+ * -- size to be written to the output
+ * -- device. This is used when writing
+ * -- a bootloader to a raw flash memory
+ * -- device such as a SPI NOR flash.
+ * -- The boot loader MUST fit within
+ * -- this size and the output will be
+ * -- padded to this size with zeros.
+ * --
+ * -- If the "output-block-size" key (below)
+ * -- is also specified, then this value
+ * -- must be a multiple of the output block
+ * -- size.
+ * -- (optional)
+ * -->
+ * <key>output-size</key>
+ * <integer>2097152</integer>
+ *
+ * <-- Key: "output-block-size"
+ * -- Value: an integer specifying the size of
+ * -- the blocks used to write to the
+ * -- output device. If the output device
+ * -- simulates a disk block storage device,
+ * -- then this value must be a multiple of
+ * -- the reported sector size.
+ * -- (optional)
+ * -->
+ * <key>output-block-size</key>
+ * <integer>65536</integer>
+ * </dict>
+ * </array>
+ *
+ * For boards that require a media specification to be provided, it
+ * may be the case that two media types have identical steps. It
+ * could be confusing for users to see a list of media types that does
+ * not include the media type on which they are installing, so there
+ * is an alias capability:
+ *
+ * <key>u-boot-install-spi</key>
+ * <array>
+ * .
+ * .
+ * .
+ * </array>
+ * <key>u-boot-install-sdmmc</key>
+ * <array>
+ * .
+ * .
+ * .
+ * </array>
+ * <-- Steps for eMMC are identical to SDMMC on this board. -->
+ * <key>u-boot-install-emmc</key>
+ * <string>u-boot-install-sdmmc</string>
*/
/*
@@ -466,6 +553,10 @@ static const char step_file_name_key[] =
static const char step_file_offset_key[] = "file-offset";
static const char step_file_size_key[] = "file-size";
static const char step_image_offset_key[] = "image-offset";
+static const char step_input_block_size_key[] = "input-block-size";
+static const char step_input_pad_size_key[] = "input-pad-size";
+static const char step_output_size_key[] = "output-size";
+static const char step_output_block_size_key[] = "output-block-size";
static const char step_preserve_key[] = "preserve";
static bool
@@ -474,11 +565,15 @@ validate_ubstep_object(evb_ubstep obj)
/*
* evb_ubstep is a dictionary with the following keys:
*
- * "file-name" (string) (required)
- * "file-offset" (number) (optional)
- * "file-size" (number) (optional)
- * "image-offset" (number) (optional)
- * "preserve" (bool) (optional)
+ * "file-name" (string) (required)
+ * "file-offset" (number) (optional)
+ * "file-size" (number) (optional)
+ * "image-offset" (number) (optional)
+ * "input-block-size" (number) (optional)
+ * "input-pad-size" (number) (optional)
+ * "output-size" (number) (optional)
+ * "output-block-size" (number) (optional)
+ * "preserve" (bool) (optional)
*/
if (prop_object_type(obj) != PROP_TYPE_DICTIONARY)
return false;
@@ -505,6 +600,37 @@ validate_ubstep_object(evb_ubstep obj)
prop_object_type(v) != PROP_TYPE_NUMBER)
return false;
+ bool have_input_block_size = false;
+ bool have_input_pad_size = false;
+
+ v = prop_dictionary_get(obj, step_input_block_size_key);
+ if (v != NULL) {
+ have_input_block_size = true;
+ if (prop_object_type(v) != PROP_TYPE_NUMBER)
+ return false;
+ }
+
+ v = prop_dictionary_get(obj, step_input_pad_size_key);
+ if (v != NULL) {
+ have_input_pad_size = true;
+ if (prop_object_type(v) != PROP_TYPE_NUMBER)
+ return false;
+ }
+
+ /* Must have both or neither of input-{block,pad}-size. */
+ if (have_input_block_size ^ have_input_pad_size)
+ return false;
+
+ v = prop_dictionary_get(obj, step_output_size_key);
+ if (v != NULL &&
+ prop_object_type(v) != PROP_TYPE_NUMBER)
+ return false;
+
+ v = prop_dictionary_get(obj, step_output_block_size_key);
+ if (v != NULL &&
+ prop_object_type(v) != PROP_TYPE_NUMBER)
+ return false;
+
v = prop_dictionary_get(obj, step_preserve_key);
if (v != NULL &&
prop_object_type(v) != PROP_TYPE_BOOL)
@@ -514,15 +640,34 @@ validate_ubstep_object(evb_ubstep obj)
}
static bool
-validate_ubinstall_object(evb_ubinstall obj)
+validate_ubinstall_object(evb_board board, evb_ubinstall obj)
{
/*
- * evb_ubinstall is an array with one or more evb_ubstep
- * objects.
+ * evb_ubinstall is either:
+ * -- an array with one or more evb_ubstep objects.
+ * -- a string representing an alias of another evb_ubinstall
+ * object
*
* (evb_ubsteps is just a convenience type for iterating
* over the steps.)
*/
+
+ if (prop_object_type(obj) == PROP_TYPE_STRING) {
+ evb_ubinstall tobj = prop_dictionary_get(board,
+ prop_string_cstring_nocopy((prop_string_t)obj));
+
+ /*
+ * The target evb_ubinstall object must exist
+ * and must itself be a proper evb_ubinstall,
+ * not another alias.
+ */
+ if (tobj == NULL ||
+ prop_object_type(tobj) != PROP_TYPE_ARRAY) {
+ return false;
+ }
+ return true;
+ }
+
if (prop_object_type(obj) != PROP_TYPE_ARRAY)
return false;
if (prop_array_count(obj) < 1)
@@ -605,7 +750,7 @@ validate_board_object(evb_board obj, boo
}
v = prop_dictionary_get_keysym(obj, key);
assert(v != NULL);
- if (!is_overlay || !validate_ubinstall_object(v))
+ if (!is_overlay || !validate_ubinstall_object(obj, v))
break;
}
prop_object_iterator_release(iter);
@@ -1287,8 +1432,18 @@ evb_board_get_uboot_install(ib_params *p
if (n < 0 || (size_t)n >= sizeof(install_key))
goto invalid_media;;
install = prop_dictionary_get(board, install_key);
- if (install != NULL)
+ if (install != NULL) {
+ if (prop_object_type(install) == PROP_TYPE_STRING) {
+ /*
+ * This is an alias. Fetch the target. We
+ * have already validated that the target
+ * exists.
+ */
+ install = prop_dictionary_get(board,
+ prop_string_cstring_nocopy((prop_string_t)install));
+ }
return install;
+ }
invalid_media:
warnx("invalid media specification: '%s'", params->media);
list_media:
@@ -1422,6 +1577,64 @@ evb_ubstep_get_image_offset(ib_params *p
}
/*
+ * evb_ubstep_get_input_block_size --
+ * Returns the input block size to use when reading the boot loader
+ * file.
+ */
+uint64_t
+evb_ubstep_get_input_block_size(ib_params *params, evb_ubstep step)
+{
+ prop_number_t number = prop_dictionary_get(step,
+ step_input_block_size_key);
+ if (number != NULL)
+ return prop_number_unsigned_integer_value(number);
+ return 0;
+}
+
+/*
+ * evb_ubstep_get_input_pad_size --
+ * Returns the input pad size to use when reading the boot loader
+ * file.
+ */
+uint64_t
+evb_ubstep_get_input_pad_size(ib_params *params, evb_ubstep step)
+{
+ prop_number_t number = prop_dictionary_get(step,
+ step_input_pad_size_key);
+ if (number != NULL)
+ return prop_number_unsigned_integer_value(number);
+ return 0;
+}
+
+/*
+ * evb_ubstep_get_output_size --
+ * Returns the total output size that will be written to the
+ * output device.
+ */
+uint64_t
+evb_ubstep_get_output_size(ib_params *params, evb_ubstep step)
+{
+ prop_number_t number = prop_dictionary_get(step, step_output_size_key);
+ if (number != NULL)
+ return prop_number_unsigned_integer_value(number);
+ return 0;
+}
+
+/*
+ * evb_ubstep_get_output_block_size --
+ * Returns the block size that must be written to the output device.
+ */
+uint64_t
+evb_ubstep_get_output_block_size(ib_params *params, evb_ubstep step)
+{
+ prop_number_t number = prop_dictionary_get(step,
+ step_output_block_size_key);
+ if (number != NULL)
+ return prop_number_unsigned_integer_value(number);
+ return 0;
+}
+
+/*
* evb_ubstep_preserves_partial_block --
* Returns true if the step preserves a partial block.
*/
@@ -1461,17 +1674,73 @@ evb_uboot_do_step(ib_params *params, con
{
struct stat sb;
int ifd = -1;
- char *blockbuf;
- size_t thisblock;
+ char *blockbuf = NULL;
off_t curoffset;
- off_t remaining;
+ off_t file_remaining;
bool rv = false;
uint64_t file_size = evb_ubstep_get_file_size(params, step);
uint64_t file_offset = evb_ubstep_get_file_offset(params, step);
uint64_t image_offset = evb_ubstep_get_image_offset(params, step);
+ uint64_t output_size = evb_ubstep_get_output_size(params, step);
+ size_t output_block_size =
+ (size_t)evb_ubstep_get_output_block_size(params, step);
+ size_t input_block_size =
+ (size_t)evb_ubstep_get_input_block_size(params, step);
+ size_t input_pad_size =
+ (size_t)evb_ubstep_get_input_pad_size(params, step);
+ bool preserves_partial_block =
+ evb_ubstep_preserves_partial_block(params, step);
+ const char *uboot_file_name =
+ evb_ubstep_get_file_name(params, step);
+
+ if (input_block_size == 0 && output_block_size == 0) {
+ if (params->flags & IB_VERBOSE) {
+ printf("Defaulting input-block-size and "
+ "output-block-size to sectorsize "
+ "(%" PRIu32 ")\n", params->sectorsize);
+ }
+ input_block_size = output_block_size = params->sectorsize;
+ } else if (input_block_size != 0 && output_block_size == 0) {
+ if (params->flags & IB_VERBOSE) {
+ printf("Defaulting output-block-size to "
+ "input-block-size (%zu)\n",
+ input_block_size);
+ }
+ output_block_size = input_block_size;
+ } else if (output_block_size != 0 && input_block_size == 0) {
+ if (params->flags & IB_VERBOSE) {
+ printf("Defaulting input-block-size to "
+ "output-block-size (%zu)\n",
+ output_block_size);
+ }
+ input_block_size = output_block_size;
+ }
+
+ if (output_block_size % params->sectorsize) {
+ warnx("output-block-size (%zu) is not a multiple of "
+ "device sector size (%" PRIu32 ")",
+ output_block_size, params->sectorsize);
+ goto out;
+ }
+
+ if ((input_block_size + input_pad_size) > output_block_size) {
+ warnx("input-{block+pad}-size (%zu) is larger than "
+ "output-block-size (%zu)",
+ input_block_size + input_pad_size,
+ output_block_size);
+ goto out;
+ }
- blockbuf = malloc(params->sectorsize);
+ if (output_block_size % (input_block_size + input_pad_size)) {
+ warnx("output-block-size (%zu) it not a multiple of "
+ "input-{block+pad}-size (%zu)",
+ output_block_size,
+ input_block_size + input_pad_size);
+ goto out;
+ }
+
+ blockbuf = malloc(output_block_size);
if (blockbuf == NULL)
goto out;
@@ -1486,19 +1755,28 @@ evb_uboot_do_step(ib_params *params, con
}
if (file_size)
- remaining = (off_t)file_size;
+ file_remaining = (off_t)file_size;
else
- remaining = sb.st_size - (off_t)file_offset;
+ file_remaining = sb.st_size - (off_t)file_offset;
+
+ if (output_size == 0) {
+ output_size = roundup(file_remaining, output_block_size);
+ } else if ((uint64_t)file_remaining > output_size) {
+ warnx("file size (%lld) is larger than output-size (%" PRIu64
+ ")", (long long)file_remaining, output_size);
+ goto out;
+ }
if (params->flags & IB_VERBOSE) {
if (file_offset) {
- printf("Writing '%s' -- %lld @ %" PRIu64 " ==> %" PRIu64 "\n",
- evb_ubstep_get_file_name(params, step),
- (long long)remaining, file_offset, image_offset);
+ printf("Writing '%s' %lld @ %" PRIu64
+ "to '%s' @ %" PRIu64 "\n",
+ uboot_file_name, (long long)file_remaining,
+ file_offset, params->filesystem, image_offset);
} else {
- printf("Writing '%s' -- %lld ==> %" PRIu64 "\n",
- evb_ubstep_get_file_name(params, step),
- (long long)remaining, image_offset);
+ printf("Writing '%s' %lld to '%s' @ %" PRIu64 "\n",
+ uboot_file_name, (long long)file_remaining,
+ params->filesystem, image_offset);
}
}
@@ -1508,34 +1786,75 @@ evb_uboot_do_step(ib_params *params, con
goto out;
}
- for (curoffset = (off_t)image_offset; remaining > 0;
- remaining -= thisblock, curoffset += params->sectorsize) {
- thisblock = params->sectorsize;
- if ((off_t)thisblock > remaining)
- thisblock = (size_t)remaining;
- if ((thisblock % params->sectorsize) != 0) {
- memset(blockbuf, 0, params->sectorsize);
- if (evb_ubstep_preserves_partial_block(params, step)) {
+ for (curoffset = (off_t)image_offset;
+ output_size != 0;
+ curoffset += output_block_size, output_size -= output_block_size) {
+
+ size_t outblock_remaining;
+ size_t this_inblock;
+ char *fill;
+
+ /*
+ * Initialize the output buffer. We're either
+ * filling it with zeros, or we're preserving
+ * device contents that we don't overwrite.
+ */
+ memset(blockbuf, 0, output_block_size);
+ if (preserves_partial_block) {
+ if (params->flags & IB_VERBOSE) {
+ printf("(Reading '%s' -- %zu @ %lld)\n",
+ params->filesystem,
+ output_block_size,
+ (long long)curoffset);
+ }
+ if (pread(params->fsfd, blockbuf,
+ output_block_size, curoffset) < 0) {
+ warn("pread '%s'", params->filesystem);
+ goto out;
+ }
+ }
+
+ /*
+ * Fill the output buffer with the file contents,
+ * interleaved with padding as necessary. (If
+ * there is no file left, we're going to be left
+ * with padding to cover the output-size.)
+ */
+ for (outblock_remaining = output_block_size, fill = blockbuf;
+ outblock_remaining != 0;
+ fill += input_block_size + input_pad_size,
+ outblock_remaining -= input_block_size + input_pad_size) {
+
+ this_inblock = input_block_size;
+ if ((off_t)this_inblock > file_remaining) {
+ this_inblock = file_remaining;
+ }
+
+ if (this_inblock) {
if (params->flags & IB_VERBOSE) {
- printf("(Reading '%s' -- %u @ %lld)\n",
- params->filesystem,
- params->sectorsize,
- (long long)curoffset);
+ printf("(Reading '%s' -- %zu @ %lld)\n",
+ uboot_file_name,
+ this_inblock,
+ (long long)lseek(ifd, 0,
+ SEEK_CUR));
}
- if (pread(params->fsfd, blockbuf,
- params->sectorsize, curoffset) < 0) {
- warn("pread '%s'", params->filesystem);
+ if (read(ifd, fill, this_inblock)
+ != (ssize_t)this_inblock) {
+ warn("read '%s'", uboot_file);
goto out;
}
+ file_remaining -= this_inblock;
}
}
- if (read(ifd, blockbuf, thisblock) != (ssize_t)thisblock) {
- warn("read '%s'", uboot_file);
- goto out;
+
+ if (params->flags & IB_VERBOSE) {
+ printf("(Writing '%s' -- %zu @ %lld)\n",
+ params->filesystem,
+ output_block_size, (long long)curoffset);
}
if (!(params->flags & IB_NOWRITE) &&
- pwrite(params->fsfd, blockbuf, params->sectorsize,
- curoffset) != (ssize_t)params->sectorsize) {
+ pwrite(params->fsfd, blockbuf, output_block_size,
+ curoffset) != (ssize_t)output_block_size) {
warn("pwrite '%s'", params->filesystem);
goto out;
}
Index: src/usr.sbin/installboot/evboards.h
diff -u src/usr.sbin/installboot/evboards.h:1.1 src/usr.sbin/installboot/evboards.h:1.1.4.1
--- src/usr.sbin/installboot/evboards.h:1.1 Tue May 7 05:02:42 2019
+++ src/usr.sbin/installboot/evboards.h Sun Sep 22 10:20:16 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: evboards.h,v 1.1 2019/05/07 05:02:42 thorpej Exp $ */
+/* $NetBSD: evboards.h,v 1.1.4.1 2019/09/22 10:20:16 martin Exp $ */
/*-
* Copyright (c) 2019 The NetBSD Foundation, Inc.
@@ -58,6 +58,10 @@ const char * evb_ubstep_get_file_name(ib
uint64_t evb_ubstep_get_file_offset(ib_params *, evb_ubstep);
uint64_t evb_ubstep_get_file_size(ib_params *, evb_ubstep);
uint64_t evb_ubstep_get_image_offset(ib_params *, evb_ubstep);
+uint64_t evb_ubstep_get_input_block_size(ib_params *, evb_ubstep);
+uint64_t evb_ubstep_get_input_pad_size(ib_params *, evb_ubstep);
+uint64_t evb_ubstep_get_output_size(ib_params *, evb_ubstep);
+uint64_t evb_ubstep_get_output_block_size(ib_params *, evb_ubstep);
bool evb_ubstep_preserves_partial_block(ib_params *, evb_ubstep);
int evb_uboot_setboot(ib_params *, evb_board);