Merge pull request #3483 from klauskiwi/op-build-2.3.y_petitboot_fixes

Petitboot: Bump to 1.10.4 and Bring-in upstream fixes
diff --git a/openpower/package/petitboot/0001-discover-platform-powerpc-add-missing-mbox-block-sel.patch b/openpower/package/petitboot/0001-discover-platform-powerpc-add-missing-mbox-block-sel.patch
new file mode 100644
index 0000000..c742ad8
--- /dev/null
+++ b/openpower/package/petitboot/0001-discover-platform-powerpc-add-missing-mbox-block-sel.patch
@@ -0,0 +1,80 @@
+From e92e3204cc494de8d41160e3d3a5bd5d03fdbb15 Mon Sep 17 00:00:00 2001
+From: Maxim Polyakov <m.polyakov@yadro.com>
+Date: Mon, 8 Jul 2019 12:12:43 +0300
+Subject: [PATCH 01/18] discover/platform-powerpc: add missing mbox block
+ selector
+
+According to IPMI Specification, in the IPMI response message with
+boot initiator mailbox information block, byte 4 should be used as
+the block selector (1). However, this parameter isn`t taken into
+account in the code and bytes 4-6 in the block 0 are defined as the
+IANA enterprise ID number. Thus, IANA contains an invalid value and
+doesn`t match the IBM ID. For this reason, the get_ipmi_boot_mailbox()
+procedure fails with error and the boot options from mailbox doesn`t
+apply.
+/var/log/petitboot/pb-discover.log:
+
+IANA number unrecognised: 0x00:0x02:0x00
+
+This patch adds the missing block selector parameter.
+It has been tested on the YADRO Vesnin P8 Server with the Openbmc
+
+[1] page 398, IPMI Specification v2.0, Revision 1.1, October 1, 2013
+
+Signed-off-by: Maxim Polyakov <m.polyakov@yadro.com>
+(cherry picked from commit 43813e6f5e7e051b9c0c077bef71f4a423d7f6c0)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/platform-powerpc.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c
+index 5d7cc59..6651e3f 100644
+--- a/discover/platform-powerpc.c
++++ b/discover/platform-powerpc.c
+@@ -440,7 +440,7 @@ static int get_ipmi_boot_mailbox_block(struct platform_powerpc *platform,
+ 		char *buf, uint8_t block)
+ {
+ 	size_t blocksize = 16;
+-	uint8_t resp[3 + 16];
++	uint8_t resp[3 + 1 + 16];
+ 	uint16_t resp_len;
+ 	char *debug_buf;
+ 	int rc;
+@@ -462,7 +462,7 @@ static int get_ipmi_boot_mailbox_block(struct platform_powerpc *platform,
+ 	}
+ 
+ 	if (resp_len < sizeof(resp)) {
+-		if (resp_len < 3) {
++		if (resp_len < 4) {
+ 			pb_log("platform: unexpected length (%d) in "
+ 					"boot options mailbox response\n",
+ 					resp_len);
+@@ -474,7 +474,7 @@ static int get_ipmi_boot_mailbox_block(struct platform_powerpc *platform,
+ 			return 0;
+ 		}
+ 
+-		blocksize = sizeof(resp) - 3;
++		blocksize = sizeof(resp) - 4;
+ 		pb_debug_fn("Mailbox block %hu returns only %zu bytes in block\n",
+ 				block, blocksize);
+ 	}
+@@ -502,7 +502,14 @@ static int get_ipmi_boot_mailbox_block(struct platform_powerpc *platform,
+ 		return -1;
+ 	}
+ 
+-	memcpy(buf, &resp[3], blocksize);
++	/* check for block number */
++	if (resp[3] != block) {
++		pb_debug("platform: returned boot mailbox block doesn't match "
++				  "requested\n");
++		return -1;
++	}
++
++	memcpy(buf, &resp[4], blocksize);
+ 
+ 	return blocksize;
+ }
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0002-discover-platform-powerpc-limit-mailbox-response-siz.patch b/openpower/package/petitboot/0002-discover-platform-powerpc-limit-mailbox-response-siz.patch
new file mode 100644
index 0000000..feecd41
--- /dev/null
+++ b/openpower/package/petitboot/0002-discover-platform-powerpc-limit-mailbox-response-siz.patch
@@ -0,0 +1,68 @@
+From 40fd13ec2c7518dc7afa67dae2cf5c460b92997c Mon Sep 17 00:00:00 2001
+From: Maxim Polyakov <m.polyakov@yadro.com>
+Date: Mon, 8 Jul 2019 12:12:59 +0300
+Subject: [PATCH 02/18] discover/platform-powerpc: limit mailbox response size
+
+The maximum size of the mailbox with Boot Initiator info is defined in
+the specification (1). The code should not extract data from the IPMI
+response message if its size exceeds the maximum limit from the
+specification.
+
+[1] page 398, IPMI Specification v2.0, Revision 1.1, October 1, 2013
+
+Signed-off-by: Maxim Polyakov <m.polyakov@yadro.com>
+(cherry picked from commit 1088a8ab532bfe008a714613497909d19bcfb8c4)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/platform-powerpc.c | 31 +++++++++++++++++--------------
+ 1 file changed, 17 insertions(+), 14 deletions(-)
+
+diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c
+index 6651e3f..1e33bf1 100644
+--- a/discover/platform-powerpc.c
++++ b/discover/platform-powerpc.c
+@@ -461,24 +461,27 @@ static int get_ipmi_boot_mailbox_block(struct platform_powerpc *platform,
+ 		return -1;
+ 	}
+ 
+-	if (resp_len < sizeof(resp)) {
+-		if (resp_len < 4) {
+-			pb_log("platform: unexpected length (%d) in "
+-					"boot options mailbox response\n",
+-					resp_len);
+-			return -1;
+-		}
++	if (resp_len > sizeof(resp)) {
++		pb_debug("platform: invalid mailbox response size!\n");
++		return -1;
++	}
+ 
+-		if (resp_len == 4) {
+-			pb_debug_fn("block %hu empty\n", block);
+-			return 0;
+-		}
++	if (resp_len < 4) {
++		pb_log("platform: unexpected length (%d) in "
++				"boot options mailbox response\n",
++				resp_len);
++		return -1;
++	}
+ 
+-		blocksize = sizeof(resp) - 4;
+-		pb_debug_fn("Mailbox block %hu returns only %zu bytes in block\n",
+-				block, blocksize);
++	if (resp_len == 4) {
++		pb_debug_fn("block %hu empty\n", block);
++		return 0;
+ 	}
+ 
++	blocksize = sizeof(resp) - 4;
++	pb_debug_fn("Mailbox block %hu returns only %zu bytes in block\n",
++			block, blocksize);
++
+ 	debug_buf = format_buffer(platform, resp, resp_len);
+ 	pb_debug_fn("IPMI bootdev mailbox block %hu:\n%s\n", block, debug_buf);
+ 	talloc_free(debug_buf);
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0003-discover-platform-powerpc-return-the-actual-mailbox-.patch b/openpower/package/petitboot/0003-discover-platform-powerpc-return-the-actual-mailbox-.patch
new file mode 100644
index 0000000..b790a71
--- /dev/null
+++ b/openpower/package/petitboot/0003-discover-platform-powerpc-return-the-actual-mailbox-.patch
@@ -0,0 +1,50 @@
+From b3ee03b155dad86bad8fd197764e2d340b1eb8c6 Mon Sep 17 00:00:00 2001
+From: Maxim Polyakov <m.polyakov@yadro.com>
+Date: Mon, 8 Jul 2019 12:13:18 +0300
+Subject: [PATCH 03/18] discover/platform-powerpc: return the actual mailbox
+ size
+
+get_ipmi_boot_mailbox_block() should return the actual size
+of the received IPMI mailbox data
+
+Signed-off-by: Maxim Polyakov <m.polyakov@yadro.com>
+(cherry picked from commit 5f8321eb6479113a09c771c49e6781571ec8e2e2)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/platform-powerpc.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c
+index 1e33bf1..c874560 100644
+--- a/discover/platform-powerpc.c
++++ b/discover/platform-powerpc.c
+@@ -473,12 +473,7 @@ static int get_ipmi_boot_mailbox_block(struct platform_powerpc *platform,
+ 		return -1;
+ 	}
+ 
+-	if (resp_len == 4) {
+-		pb_debug_fn("block %hu empty\n", block);
+-		return 0;
+-	}
+-
+-	blocksize = sizeof(resp) - 4;
++	blocksize = resp_len - 4;
+ 	pb_debug_fn("Mailbox block %hu returns only %zu bytes in block\n",
+ 			block, blocksize);
+ 
+@@ -512,6 +507,12 @@ static int get_ipmi_boot_mailbox_block(struct platform_powerpc *platform,
+ 		return -1;
+ 	}
+ 
++	if (!blocksize) {
++		pb_debug_fn("block %hu empty\n", block);
++		return 0;
++	}
++
++
+ 	memcpy(buf, &resp[4], blocksize);
+ 
+ 	return blocksize;
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0004-discover-grub2-search-set-variable-defaults-to-root.patch b/openpower/package/petitboot/0004-discover-grub2-search-set-variable-defaults-to-root.patch
new file mode 100644
index 0000000..bc5a0e1
--- /dev/null
+++ b/openpower/package/petitboot/0004-discover-grub2-search-set-variable-defaults-to-root.patch
@@ -0,0 +1,40 @@
+From 3794b8f14fe94fcaa7b5cdb9171aef488f93ec7e Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Thu, 31 Oct 2019 13:56:42 +0800
+Subject: [PATCH 04/18] discover/grub2: 'search' set-variable defaults to root
+
+If no --set= argument is specified, default to the variable named
+'root', as per current grub docs.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit e558da19475d747e6f8e83d07305d35da33102f9)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/grub2/builtins.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/discover/grub2/builtins.c b/discover/grub2/builtins.c
+index 7e92299..3f09319 100644
+--- a/discover/grub2/builtins.c
++++ b/discover/grub2/builtins.c
+@@ -113,7 +113,7 @@ static int builtin_search(struct grub2_script *script,
+ 	const char *env_var, *spec;
+ 	int i;
+ 
+-	env_var = NULL;
++	env_var = "root";
+ 
+ 	for (i = 1; i < argc - 1; i++) {
+ 		if (!strncmp(argv[i], "--set=", strlen("--set="))) {
+@@ -122,7 +122,7 @@ static int builtin_search(struct grub2_script *script,
+ 		}
+ 	}
+ 
+-	if (!env_var)
++	if (!strlen(env_var))
+ 		return 0;
+ 
+ 	spec = argv[argc - 1];
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0005-discover-grub2-Use-getopt-for-search-argument-parsin.patch b/openpower/package/petitboot/0005-discover-grub2-Use-getopt-for-search-argument-parsin.patch
new file mode 100644
index 0000000..8e8114d
--- /dev/null
+++ b/openpower/package/petitboot/0005-discover-grub2-Use-getopt-for-search-argument-parsin.patch
@@ -0,0 +1,142 @@
+From 0ddab9194fb2a24dbe25c848f27eb4d66e556113 Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Thu, 31 Oct 2019 17:31:10 +0800
+Subject: [PATCH 05/18] discover/grub2: Use getopt for `search` argument
+ parsing
+
+The search command will be extended to add the full set of grub2-style
+arguments, so switch to using getopt, rather than manual parsing.
+
+This means we now support `--set=foo` and `--set foo` style arguments,
+both of which appear in the docs and common grub configs.
+
+Also, add a small test for the search argument handling.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit 61ede5e0bea7d999acfdda9931e5c1f3c13c0694)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/grub2/builtins.c            | 33 +++++++++++++++++++++++-----
+ test/parser/Makefile.am              |  1 +
+ test/parser/test-grub2-search-args.c | 33 ++++++++++++++++++++++++++++
+ 3 files changed, 62 insertions(+), 5 deletions(-)
+ create mode 100644 test/parser/test-grub2-search-args.c
+
+diff --git a/discover/grub2/builtins.c b/discover/grub2/builtins.c
+index 3f09319..ab6b0ec 100644
+--- a/discover/grub2/builtins.c
++++ b/discover/grub2/builtins.c
+@@ -1,4 +1,7 @@
+ 
++#define _GNU_SOURCE
++
++#include <getopt.h>
+ #include <stdio.h>
+ #include <string.h>
+ 
+@@ -106,18 +109,35 @@ static int builtin_initrd(struct grub2_script *script,
+ 	return 0;
+ }
+ 
++static const struct option search_options[] = {
++	{
++		.name = "set",
++		.has_arg = required_argument,
++		.val = 's',
++	},
++	{ 0 },
++};
++
+ static int builtin_search(struct grub2_script *script,
+ 		void *data __attribute__((unused)),
+ 		int argc, char *argv[])
+ {
+ 	const char *env_var, *spec;
+-	int i;
+ 
+ 	env_var = "root";
++	optind = 0;
++
++	for (;;) {
++		int c = getopt_long(argc, argv, ":", search_options, NULL);
++		if (c == -1)
++			break;
+ 
+-	for (i = 1; i < argc - 1; i++) {
+-		if (!strncmp(argv[i], "--set=", strlen("--set="))) {
+-			env_var = argv[i] + strlen("--set=");
++		switch (c) {
++		case 's':
++			env_var = optarg;
++			break;
++		case '?':
++		case ':':
+ 			break;
+ 		}
+ 	}
+@@ -125,7 +145,10 @@ static int builtin_search(struct grub2_script *script,
+ 	if (!strlen(env_var))
+ 		return 0;
+ 
+-	spec = argv[argc - 1];
++	if (optind >= argc)
++		return -1;
++
++	spec = argv[optind];
+ 
+ 	script_env_set(script, env_var, spec);
+ 
+diff --git a/test/parser/Makefile.am b/test/parser/Makefile.am
+index 748c836..df9c539 100644
+--- a/test/parser/Makefile.am
++++ b/test/parser/Makefile.am
+@@ -29,6 +29,7 @@ parser_TESTS = \
+ 	test/parser/test-grub2-multiple-id \
+ 	test/parser/test-grub2-single-line-if \
+ 	test/parser/test-grub2-pos-param \
++	test/parser/test-grub2-search-args \
+ 	test/parser/test-grub2-load-env \
+ 	test/parser/test-grub2-save-env \
+ 	test/parser/test-grub2-save-env-dash-f \
+diff --git a/test/parser/test-grub2-search-args.c b/test/parser/test-grub2-search-args.c
+new file mode 100644
+index 0000000..ffce853
+--- /dev/null
++++ b/test/parser/test-grub2-search-args.c
+@@ -0,0 +1,33 @@
++
++/* check for multiple styles of option parsing for the 'search' command */
++
++#include "parser-test.h"
++
++#if 0 /* PARSER_EMBEDDED_CONFIG */
++
++# no --set arugment will set the 'root' var
++search a
++search --set=v1 b
++search --set v2 c
++
++menuentry $root$v1$v2 {
++    linux /vmlinux
++}
++
++#endif
++
++void run_test(struct parser_test *test)
++{
++	struct discover_boot_option *opt;
++	struct discover_context *ctx;
++
++	ctx = test->ctx;
++
++	test_read_conf_embedded(test, "/grub/grub.cfg");
++
++	test_run_parser(test, "grub2");
++
++	check_boot_option_count(ctx, 1);
++	opt = get_boot_option(ctx, 0);
++	check_name(opt, "abc");
++}
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0006-discover-grub2-test-for-ignored-no-floppy-argument.patch b/openpower/package/petitboot/0006-discover-grub2-test-for-ignored-no-floppy-argument.patch
new file mode 100644
index 0000000..4f6864d
--- /dev/null
+++ b/openpower/package/petitboot/0006-discover-grub2-test-for-ignored-no-floppy-argument.patch
@@ -0,0 +1,41 @@
+From 1b71108e411178d90cef5744595ae4d50e040732 Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Fri, 1 Nov 2019 07:18:08 +0800
+Subject: [PATCH 06/18] discover/grub2: test for (ignored) --no-floppy argument
+
+--no-floppy is used almost everywhere, so add it to the tests. The code
+will already ignore unknown arguments, but ensure that this works OK.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit 76e97c5d9dab40236a589cd96a69967d3ef17cab)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ test/parser/test-grub2-search-args.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/test/parser/test-grub2-search-args.c b/test/parser/test-grub2-search-args.c
+index ffce853..0eb5762 100644
+--- a/test/parser/test-grub2-search-args.c
++++ b/test/parser/test-grub2-search-args.c
+@@ -9,8 +9,10 @@
+ search a
+ search --set=v1 b
+ search --set v2 c
++search --set=v3 --no-floppy d
++search --no-floppy --set=v4 e
+ 
+-menuentry $root$v1$v2 {
++menuentry $root$v1$v2$v3$v4 {
+     linux /vmlinux
+ }
+ 
+@@ -29,5 +31,5 @@ void run_test(struct parser_test *test)
+ 
+ 	check_boot_option_count(ctx, 1);
+ 	opt = get_boot_option(ctx, 0);
+-	check_name(opt, "abc");
++	check_name(opt, "abcde");
+ }
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0007-discover-grub2-Add-support-for-UUID-and-label-for-se.patch b/openpower/package/petitboot/0007-discover-grub2-Add-support-for-UUID-and-label-for-se.patch
new file mode 100644
index 0000000..04bd8a4
--- /dev/null
+++ b/openpower/package/petitboot/0007-discover-grub2-Add-support-for-UUID-and-label-for-se.patch
@@ -0,0 +1,245 @@
+From 6b25dcfea5b84aebbfd830236c489fc8c2cde02c Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Mon, 4 Nov 2019 14:58:01 +0800
+Subject: [PATCH 07/18] discover/grub2: Add support for UUID and label for
+ 'search' command
+
+This change adds support for searching by UUID and filesystem label.
+We still fall back to passthrough if the UUID is not found, but we now
+resolve to device ID strings.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit 1580c6557d4e703348edb0dda83814f8972e9f3d)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/grub2/builtins.c             | 55 +++++++++++++++++++++++++--
+ test/parser/Makefile.am               |  2 +
+ test/parser/test-grub2-search-label.c | 47 +++++++++++++++++++++++
+ test/parser/test-grub2-search-uuid.c  | 55 +++++++++++++++++++++++++++
+ 4 files changed, 156 insertions(+), 3 deletions(-)
+ create mode 100644 test/parser/test-grub2-search-label.c
+ create mode 100644 test/parser/test-grub2-search-uuid.c
+
+diff --git a/discover/grub2/builtins.c b/discover/grub2/builtins.c
+index ab6b0ec..7cac9f1 100644
+--- a/discover/grub2/builtins.c
++++ b/discover/grub2/builtins.c
+@@ -115,6 +115,21 @@ static const struct option search_options[] = {
+ 		.has_arg = required_argument,
+ 		.val = 's',
+ 	},
++	{
++		.name = "file",
++		.has_arg = no_argument,
++		.val = 'f',
++	},
++	{
++		.name = "label",
++		.has_arg = no_argument,
++		.val = 'l',
++	},
++	{
++		.name = "fs-uuid",
++		.has_arg = no_argument,
++		.val = 'u',
++	},
+ 	{ 0 },
+ };
+ 
+@@ -122,13 +137,23 @@ static int builtin_search(struct grub2_script *script,
+ 		void *data __attribute__((unused)),
+ 		int argc, char *argv[])
+ {
+-	const char *env_var, *spec;
++	const char *env_var, *spec, *res;
++	struct discover_device *dev;
++	enum {
++		LOOKUP_UUID = 'u',
++		LOOKUP_LABEL = 'l',
++		LOOKUP_FILE = 'f',
++	} lookup_type;
+ 
+ 	env_var = "root";
+ 	optind = 0;
+ 
++	/* Default to UUID, for backwards compat with earlier petitboot
++	 * versions. This argument is non-optional in GRUB. */
++	lookup_type = LOOKUP_UUID;
++
+ 	for (;;) {
+-		int c = getopt_long(argc, argv, ":", search_options, NULL);
++		int c = getopt_long(argc, argv, ":flu", search_options, NULL);
+ 		if (c == -1)
+ 			break;
+ 
+@@ -136,6 +161,11 @@ static int builtin_search(struct grub2_script *script,
+ 		case 's':
+ 			env_var = optarg;
+ 			break;
++		case LOOKUP_UUID:
++		case LOOKUP_LABEL:
++		case LOOKUP_FILE:
++			lookup_type = c;
++			break;
+ 		case '?':
+ 		case ':':
+ 			break;
+@@ -149,8 +179,27 @@ static int builtin_search(struct grub2_script *script,
+ 		return -1;
+ 
+ 	spec = argv[optind];
++	res = NULL;
++
++	switch (lookup_type) {
++	case LOOKUP_UUID:
++		dev = device_lookup_by_uuid(script->ctx->handler,
++				spec);
++		res = dev ? dev->device->id : spec;
++		break;
++	case LOOKUP_LABEL:
++		dev = device_lookup_by_label(script->ctx->handler,
++				spec);
++		if (dev)
++			res = dev->device->id;
++		break;
++	case LOOKUP_FILE:
++		/* not yet implemented */
++		break;
++	}
+ 
+-	script_env_set(script, env_var, spec);
++	if (res)
++		script_env_set(script, env_var, res);
+ 
+ 	return 0;
+ }
+diff --git a/test/parser/Makefile.am b/test/parser/Makefile.am
+index df9c539..f5985d6 100644
+--- a/test/parser/Makefile.am
++++ b/test/parser/Makefile.am
+@@ -30,6 +30,8 @@ parser_TESTS = \
+ 	test/parser/test-grub2-single-line-if \
+ 	test/parser/test-grub2-pos-param \
+ 	test/parser/test-grub2-search-args \
++	test/parser/test-grub2-search-uuid \
++	test/parser/test-grub2-search-label \
+ 	test/parser/test-grub2-load-env \
+ 	test/parser/test-grub2-save-env \
+ 	test/parser/test-grub2-save-env-dash-f \
+diff --git a/test/parser/test-grub2-search-label.c b/test/parser/test-grub2-search-label.c
+new file mode 100644
+index 0000000..b9ee034
+--- /dev/null
++++ b/test/parser/test-grub2-search-label.c
+@@ -0,0 +1,47 @@
++/* check for grub2 search command, searching by partition label */
++
++#include "parser-test.h"
++
++#if 0 /* PARSER_EMBEDDED_CONFIG */
++
++# valid label
++search --set=v1 --label testlabel
++
++v2=prev
++# invalid label: does not alter v2
++search --set=v2 --label invalidlabel
++
++menuentry $v1 {
++    linux /vmlinux
++}
++
++menuentry $v2 {
++    linux /vmlinux
++}
++
++#endif
++
++void run_test(struct parser_test *test)
++{
++	struct discover_boot_option *opt;
++	struct discover_context *ctx;
++	struct discover_device *dev;
++
++	ctx = test->ctx;
++
++	dev = test_create_device(test, "testdev");
++	dev->label = "testlabel";
++	device_handler_add_device(test->handler, dev);
++
++	test_read_conf_embedded(test, "/grub/grub.cfg");
++
++	test_run_parser(test, "grub2");
++
++	check_boot_option_count(ctx, 2);
++
++	opt = get_boot_option(ctx, 0);
++	check_name(opt, "testdev");
++
++	opt = get_boot_option(ctx, 1);
++	check_name(opt, "prev");
++}
+diff --git a/test/parser/test-grub2-search-uuid.c b/test/parser/test-grub2-search-uuid.c
+new file mode 100644
+index 0000000..7eacd1d
+--- /dev/null
++++ b/test/parser/test-grub2-search-uuid.c
+@@ -0,0 +1,55 @@
++/* check for grub2 search command, searching by FS UUID */
++
++#include "parser-test.h"
++
++#if 0 /* PARSER_EMBEDDED_CONFIG */
++
++# valid UUID
++search --set=v1 --fs-uuid ee0cc6fa-1dba-48f2-8f5b-19e4b8de8c37
++
++# invalid UUID: will fall back to passing the UUID through
++search --set=v2 --fs-uuid 92b0da57-6e04-4e54-960b-85e6bb060433
++
++# no 'type' argument defaults to UUID search
++search --set=v3 ee0cc6fa-1dba-48f2-8f5b-19e4b8de8c37
++
++menuentry $v1 {
++    linux /vmlinux
++}
++
++menuentry $v2 {
++    linux /vmlinux
++}
++
++menuentry $v3 {
++    linux /vmlinux
++}
++#endif
++
++void run_test(struct parser_test *test)
++{
++	struct discover_boot_option *opt;
++	struct discover_context *ctx;
++	struct discover_device *dev;
++
++	ctx = test->ctx;
++
++	dev = test_create_device(test, "testdev");
++	dev->uuid = "ee0cc6fa-1dba-48f2-8f5b-19e4b8de8c37";
++	device_handler_add_device(test->handler, dev);
++
++	test_read_conf_embedded(test, "/grub/grub.cfg");
++
++	test_run_parser(test, "grub2");
++
++	check_boot_option_count(ctx, 3);
++
++	opt = get_boot_option(ctx, 0);
++	check_name(opt, dev->device->id);
++
++	opt = get_boot_option(ctx, 1);
++	check_name(opt, "92b0da57-6e04-4e54-960b-85e6bb060433");
++
++	opt = get_boot_option(ctx, 2);
++	check_name(opt, dev->device->id);
++}
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0008-discover-grub2-expose-a-struct-for-grub2-file-refere.patch b/openpower/package/petitboot/0008-discover-grub2-expose-a-struct-for-grub2-file-refere.patch
new file mode 100644
index 0000000..e12b6f3
--- /dev/null
+++ b/openpower/package/petitboot/0008-discover-grub2-expose-a-struct-for-grub2-file-refere.patch
@@ -0,0 +1,112 @@
+From 108772a058d1bbecf8a1d413a0c365e90cd8b6c0 Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Tue, 5 Nov 2019 16:42:14 +0800
+Subject: [PATCH 08/18] discover/grub2: expose a struct for grub2 file
+ references
+
+Currently, we have struct grub2_resource_info to keep references to boot
+payloads that may be returned in boot options, and be (conditionally)
+resolved by the parser.
+
+We'd also like to use the same semantics for other file references in
+the grub2 parser, for arbitrary usage in scripts - where files are
+also referenced by a path and an optional device.
+
+To do this, this change moves struct grub2_resource_info to grub2.h, and
+renames to struct grub2_file. Future changes will use this for
+script-internal file handling.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit 8cb74c4502712162ba899bc06e2d0cf249a8697b)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/grub2/grub2.c | 24 +++++++++---------------
+ discover/grub2/grub2.h |  8 ++++++++
+ 2 files changed, 17 insertions(+), 15 deletions(-)
+
+diff --git a/discover/grub2/grub2.c b/discover/grub2/grub2.c
+index f62ccdd..412298b 100644
+--- a/discover/grub2/grub2.c
++++ b/discover/grub2/grub2.c
+@@ -33,17 +33,12 @@ static const char *const grub2_conf_files[] = {
+ 	NULL
+ };
+ 
+-struct grub2_resource_info {
+-	char *root;
+-	char *path;
+-};
+-
+ /* we use slightly different resources for grub2 */
+ struct resource *create_grub2_resource(struct discover_boot_option *opt,
+ 		struct discover_device *orig_device,
+ 		const char *root, const char *path)
+ {
+-	struct grub2_resource_info *info;
++	struct grub2_file *file;
+ 	struct resource *res;
+ 
+ 	if (strstr(path, "://")) {
+@@ -55,13 +50,12 @@ struct resource *create_grub2_resource(struct discover_boot_option *opt,
+ 	res = talloc(opt, struct resource);
+ 
+ 	if (root) {
+-		info = talloc(res, struct grub2_resource_info);
+-		talloc_reference(info, root);
+-		info->root = talloc_strdup(info, root);
+-		info->path = talloc_strdup(info, path);
++		file = talloc(res, struct grub2_file);
++		file->dev = talloc_strdup(file, root);
++		file->path = talloc_strdup(file, path);
+ 
+ 		res->resolved = false;
+-		res->info = info;
++		res->info = file;
+ 
+ 	} else
+ 		resolve_resource_against_device(res, orig_device, path);
+@@ -72,18 +66,18 @@ struct resource *create_grub2_resource(struct discover_boot_option *opt,
+ bool resolve_grub2_resource(struct device_handler *handler,
+ 		struct resource *res)
+ {
+-	struct grub2_resource_info *info = res->info;
++	struct grub2_file *file = res->info;
+ 	struct discover_device *dev;
+ 
+ 	assert(!res->resolved);
+ 
+-	dev = device_lookup_by_uuid(handler, info->root);
++	dev = device_lookup_by_uuid(handler, file->dev);
+ 
+ 	if (!dev)
+ 		return false;
+ 
+-	resolve_resource_against_device(res, dev, info->path);
+-	talloc_free(info);
++	resolve_resource_against_device(res, dev, file->path);
++	talloc_free(file);
+ 
+ 	return true;
+ }
+diff --git a/discover/grub2/grub2.h b/discover/grub2/grub2.h
+index 68176fb..73d91b2 100644
+--- a/discover/grub2/grub2.h
++++ b/discover/grub2/grub2.h
+@@ -107,6 +107,14 @@ struct grub2_parser {
+ 	bool			inter_word;
+ };
+ 
++/* References to files in grub2 consist of an optional device and a path
++ * (specified here by UUID). If the dev is unspecified, we fall back to a
++ * default - usually the 'root' environment variable. */
++struct grub2_file {
++	char *dev;
++	char *path;
++};
++
+ /* type for builtin functions */
+ typedef int (*grub2_function)(struct grub2_script *script, void *data,
+ 				int argc, char *argv[]);
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0009-discover-grub2-Add-parsing-code-for-grub2-file-speci.patch b/openpower/package/petitboot/0009-discover-grub2-Add-parsing-code-for-grub2-file-speci.patch
new file mode 100644
index 0000000..cc97858
--- /dev/null
+++ b/openpower/package/petitboot/0009-discover-grub2-Add-parsing-code-for-grub2-file-speci.patch
@@ -0,0 +1,84 @@
+From a4716f32814e6624f975da0a261175e4fee5f79d Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Wed, 6 Nov 2019 11:04:54 +0800
+Subject: [PATCH 09/18] discover/grub2: Add parsing code for grub2 file
+ specifiers
+
+This change adds a (currently unused) function to parse (device)/path
+references from grub scripts.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit 51f71178cd82a1cb7fae1a4e6bf40290e41b7d0e)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/grub2/grub2.c | 38 ++++++++++++++++++++++++++++++++++++++
+ discover/grub2/grub2.h |  4 ++++
+ 2 files changed, 42 insertions(+)
+
+diff --git a/discover/grub2/grub2.c b/discover/grub2/grub2.c
+index 412298b..3873720 100644
+--- a/discover/grub2/grub2.c
++++ b/discover/grub2/grub2.c
+@@ -82,6 +82,44 @@ bool resolve_grub2_resource(struct device_handler *handler,
+ 	return true;
+ }
+ 
++struct grub2_file *grub2_parse_file(struct grub2_script *script,
++		const char *str)
++{
++	struct grub2_file *file;
++	size_t dev_len;
++	char *pos;
++
++	if (!str)
++		return NULL;
++
++	file = talloc_zero(script, struct grub2_file);
++
++	if (*str != '(') {
++		/* just a path - no device, return path as-is */
++		file->path = talloc_strdup(file, str);
++
++	} else {
++		/* device plus path - split into components */
++
++		pos = strchr(str, ')');
++
++		/* no closing bracket, or zero-length path? */
++		if (!pos || *(pos+1) == '\0') {
++			talloc_free(file);
++			return NULL;
++		}
++
++		file->path = talloc_strdup(file, pos + 1);
++
++		dev_len = pos - str - 1;
++		if (dev_len)
++			file->dev = talloc_strndup(file, str + 1, dev_len);
++	}
++
++	return file;
++}
++
++
+ static int grub2_parse(struct discover_context *dc)
+ {
+ 	const char * const *filename;
+diff --git a/discover/grub2/grub2.h b/discover/grub2/grub2.h
+index 73d91b2..8c4839b 100644
+--- a/discover/grub2/grub2.h
++++ b/discover/grub2/grub2.h
+@@ -198,6 +198,10 @@ struct resource *create_grub2_resource(struct discover_boot_option *opt,
+ bool resolve_grub2_resource(struct device_handler *handler,
+ 		struct resource *res);
+ 
++/* grub-style device+path parsing */
++struct grub2_file *grub2_parse_file(struct grub2_script *script,
++		const char *str);
++
+ /* external parser api */
+ struct grub2_parser *grub2_parser_create(struct discover_context *ctx);
+ void grub2_parser_parse(struct grub2_parser *parser, const char *filename,
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0010-discover-grub2-add-support-for-grub2-style-path-spec.patch b/openpower/package/petitboot/0010-discover-grub2-add-support-for-grub2-style-path-spec.patch
new file mode 100644
index 0000000..01c0c4e
--- /dev/null
+++ b/openpower/package/petitboot/0010-discover-grub2-add-support-for-grub2-style-path-spec.patch
@@ -0,0 +1,340 @@
+From c8c56d06e2bba0a743a88033d00d8472e84923b4 Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Mon, 11 Nov 2019 17:10:30 +0800
+Subject: [PATCH 10/18] discover/grub2: add support for grub2-style path
+ specifiers in resources
+
+This change incorporates the grub2-style (device)/path specifiers in the
+grub2 parser's resource code. This allows the boot option paths to use
+device-specific references.
+
+Device names are looked-up using the UUID and kernel IDs, but with the
+lookup logic specific to a new function (grub2_lookup_device), so that
+can be extended in a future change.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit 9fc2ac627df17ddc8e7c2735053aeb9e1252ff6e)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/grub2/blscfg.c          | 19 +++----
+ discover/grub2/builtins.c        | 15 ++----
+ discover/grub2/grub2.c           | 56 +++++++++++++++-----
+ discover/grub2/grub2.h           |  5 +-
+ test/parser/Makefile.am          |  1 +
+ test/parser/test-grub2-devpath.c | 88 ++++++++++++++++++++++++++++++++
+ 6 files changed, 147 insertions(+), 37 deletions(-)
+ create mode 100644 test/parser/test-grub2-devpath.c
+
+diff --git a/discover/grub2/blscfg.c b/discover/grub2/blscfg.c
+index d4754aa..d08f8f0 100644
+--- a/discover/grub2/blscfg.c
++++ b/discover/grub2/blscfg.c
+@@ -166,7 +166,6 @@ static void bls_finish(struct conf_context *conf)
+ 	struct discover_context *dc = conf->dc;
+ 	struct discover_boot_option *opt = state->opt;
+ 	struct boot_option *option = opt->option;
+-	const char *root;
+ 	char *filename;
+ 
+ 	if (!state->image) {
+@@ -192,23 +191,21 @@ static void bls_finish(struct conf_context *conf)
+ 	else
+ 		option->name = talloc_strdup(option, state->image);
+ 
+-	root = script_env_get(state->script, "root");
+-
+-	opt->boot_image = create_grub2_resource(opt, conf->dc->device,
+-						root, state->image);
++	opt->boot_image = create_grub2_resource(state->script, opt,
++						state->image);
+ 
+ 	if (state->initrd)
+-		opt->initrd = create_grub2_resource(opt, conf->dc->device,
+-						    root, state->initrd);
++		opt->initrd = create_grub2_resource(state->script, opt,
++						    state->initrd);
+ 
+ 	if (state->dtb)
+-		opt->dtb = create_grub2_resource(opt, conf->dc->device,
+-						 root, state->dtb);
++		opt->dtb = create_grub2_resource(state->script, opt,
++						 state->dtb);
+ 
+ 	char* args_sigfile_default = talloc_asprintf(opt,
+ 		"%s.cmdline.sig", state->image);
+-	opt->args_sig_file = create_grub2_resource(opt, conf->dc->device,
+-						root, args_sigfile_default);
++	opt->args_sig_file = create_grub2_resource(state->script, opt,
++						args_sigfile_default);
+ 	talloc_free(args_sigfile_default);
+ 
+ 	option->is_default = option_is_default(state, option);
+diff --git a/discover/grub2/builtins.c b/discover/grub2/builtins.c
+index 7cac9f1..765c4d7 100644
+--- a/discover/grub2/builtins.c
++++ b/discover/grub2/builtins.c
+@@ -46,7 +46,6 @@ static int builtin_linux(struct grub2_script *script,
+ 		int argc, char *argv[])
+ {
+ 	struct discover_boot_option *opt = script->opt;
+-	const char *root;
+ 	int i;
+ 
+ 	if (!opt) {
+@@ -61,10 +60,7 @@ static int builtin_linux(struct grub2_script *script,
+ 		return -1;
+ 	}
+ 
+-	root = script_env_get(script, "root");
+-
+-	opt->boot_image = create_grub2_resource(opt, script->ctx->device,
+-						root, argv[1]);
++	opt->boot_image = create_grub2_resource(script, opt, argv[1]);
+ 	opt->option->boot_args = NULL;
+ 
+ 	if (argc > 2)
+@@ -77,8 +73,8 @@ static int builtin_linux(struct grub2_script *script,
+ 
+ 	char* args_sigfile_default = talloc_asprintf(opt,
+ 		"%s.cmdline.sig", argv[1]);
+-	opt->args_sig_file = create_grub2_resource(opt, script->ctx->device,
+-						root, args_sigfile_default);
++	opt->args_sig_file = create_grub2_resource(script, opt,
++						args_sigfile_default);
+ 	talloc_free(args_sigfile_default);
+ 	return 0;
+ }
+@@ -88,7 +84,6 @@ static int builtin_initrd(struct grub2_script *script,
+ 		int argc, char *argv[])
+ {
+ 	struct discover_boot_option *opt = script->opt;
+-	const char *root;
+ 
+ 	if (!opt) {
+ 		pb_log("grub2 syntax error: 'initrd' statement outside "
+@@ -102,9 +97,7 @@ static int builtin_initrd(struct grub2_script *script,
+ 		return -1;
+ 	}
+ 
+-	root = script_env_get(script, "root");
+-	opt->initrd = create_grub2_resource(opt, script->ctx->device,
+-						root, argv[1]);
++	opt->initrd = create_grub2_resource(script, opt, argv[1]);
+ 
+ 	return 0;
+ }
+diff --git a/discover/grub2/grub2.c b/discover/grub2/grub2.c
+index 3873720..a08a320 100644
+--- a/discover/grub2/grub2.c
++++ b/discover/grub2/grub2.c
+@@ -33,13 +33,35 @@ static const char *const grub2_conf_files[] = {
+ 	NULL
+ };
+ 
++static struct discover_device *grub2_lookup_device(
++		struct device_handler *handler, const char *desc)
++{
++	struct discover_device *dev;
++
++	if (!desc || !*desc)
++		return NULL;
++
++	dev = device_lookup_by_id(handler, desc);
++	if (dev)
++		return dev;
++
++	/* for now, only lookup by UUID */
++	dev = device_lookup_by_uuid(handler, desc);
++	if (dev)
++		return dev;
++
++	return NULL;
++}
++
+ /* we use slightly different resources for grub2 */
+-struct resource *create_grub2_resource(struct discover_boot_option *opt,
+-		struct discover_device *orig_device,
+-		const char *root, const char *path)
++struct resource *create_grub2_resource(struct grub2_script *script,
++		struct discover_boot_option *opt,
++		const char *path)
+ {
++	struct discover_device *dev;
+ 	struct grub2_file *file;
+ 	struct resource *res;
++	const char *root;
+ 
+ 	if (strstr(path, "://")) {
+ 		struct pb_url *url = pb_url_parse(opt, path);
+@@ -47,18 +69,29 @@ struct resource *create_grub2_resource(struct discover_boot_option *opt,
+ 			return create_url_resource(opt, url);
+ 	}
+ 
++	file = grub2_parse_file(script, path);
++	if (!file)
++		return NULL;
++
+ 	res = talloc(opt, struct resource);
++	root = script_env_get(script, "root");
+ 
+-	if (root) {
+-		file = talloc(res, struct grub2_file);
++	if (!file->dev && root && strlen(root))
+ 		file->dev = talloc_strdup(file, root);
+-		file->path = talloc_strdup(file, path);
+ 
+-		res->resolved = false;
+-		res->info = file;
++	/* if we don't have a device specified, or the lookup succeeds now,
++	 * then we can resolve the resource right away */
++	if (file->dev)
++		dev = grub2_lookup_device(script->ctx->handler, file->dev);
++	else
++		dev = script->ctx->device;
+ 
+-	} else
+-		resolve_resource_against_device(res, orig_device, path);
++	if (dev) {
++		resolve_resource_against_device(res, dev, file->path);
++	} else {
++		res->resolved = false;
++		res->info = talloc_steal(opt, file);
++	}
+ 
+ 	return res;
+ }
+@@ -71,8 +104,7 @@ bool resolve_grub2_resource(struct device_handler *handler,
+ 
+ 	assert(!res->resolved);
+ 
+-	dev = device_lookup_by_uuid(handler, file->dev);
+-
++	dev = grub2_lookup_device(handler, file->dev);
+ 	if (!dev)
+ 		return false;
+ 
+diff --git a/discover/grub2/grub2.h b/discover/grub2/grub2.h
+index 8c4839b..ef32d4b 100644
+--- a/discover/grub2/grub2.h
++++ b/discover/grub2/grub2.h
+@@ -191,9 +191,8 @@ void script_register_function(struct grub2_script *script,
+ void register_builtins(struct grub2_script *script);
+ 
+ /* resources */
+-struct resource *create_grub2_resource(struct discover_boot_option *opt,
+-		struct discover_device *orig_device,
+-		const char *root, const char *path);
++struct resource *create_grub2_resource(struct grub2_script *script,
++		struct discover_boot_option *opt, const char *path);
+ 
+ bool resolve_grub2_resource(struct device_handler *handler,
+ 		struct resource *res);
+diff --git a/test/parser/Makefile.am b/test/parser/Makefile.am
+index f5985d6..0378317 100644
+--- a/test/parser/Makefile.am
++++ b/test/parser/Makefile.am
+@@ -32,6 +32,7 @@ parser_TESTS = \
+ 	test/parser/test-grub2-search-args \
+ 	test/parser/test-grub2-search-uuid \
+ 	test/parser/test-grub2-search-label \
++	test/parser/test-grub2-devpath \
+ 	test/parser/test-grub2-load-env \
+ 	test/parser/test-grub2-save-env \
+ 	test/parser/test-grub2-save-env-dash-f \
+diff --git a/test/parser/test-grub2-devpath.c b/test/parser/test-grub2-devpath.c
+new file mode 100644
+index 0000000..d1d00f1
+--- /dev/null
++++ b/test/parser/test-grub2-devpath.c
+@@ -0,0 +1,88 @@
++/* check grub2 device+path string parsing */
++
++#include "parser-test.h"
++
++#if 0 /* PARSER_EMBEDDED_CONFIG */
++
++# local
++menuentry a {
++	linux /vmlinux
++}
++
++# local, specified by root env var
++root=00000000-0000-0000-0000-000000000001
++menuentry b {
++	linux /vmlinux
++}
++
++# remote, specified by root env var
++root=00000000-0000-0000-0000-000000000002
++menuentry c {
++	linux /vmlinux
++}
++
++# local, full dev+path spec
++menuentry d {
++	linux (00000000-0000-0000-0000-000000000001)/vmlinux
++}
++
++# remote, full dev+path spec
++menuentry e {
++	linux (00000000-0000-0000-0000-000000000002)/vmlinux
++}
++
++# invalid: incomplete dev+path spec
++menuentry f {
++	linux (00000000-0000-0000-0000-000000000001
++}
++
++# invalid: no path
++menuentry g {
++	linux (00000000-0000-0000-0000-000000000001)
++}
++
++
++#endif
++
++void run_test(struct parser_test *test)
++{
++	struct discover_device *dev1, *dev2;
++	struct discover_boot_option *opt;
++	struct discover_context *ctx;
++
++	ctx = test->ctx;
++
++	/* set local uuid */
++	dev1 = test->ctx->device;
++	dev1->uuid = "00000000-0000-0000-0000-000000000001";
++
++	dev2 = test_create_device(test, "extdev");
++	dev2->uuid = "00000000-0000-0000-0000-000000000002";
++	device_handler_add_device(ctx->handler, dev2);
++
++	test_read_conf_embedded(test, "/grub/grub.cfg");
++
++	test_run_parser(test, "grub2");
++
++	check_boot_option_count(ctx, 5);
++
++	opt = get_boot_option(ctx, 0);
++	check_name(opt, "a");
++	check_resolved_local_resource(opt->boot_image, dev1, "/vmlinux");
++
++	opt = get_boot_option(ctx, 1);
++	check_name(opt, "b");
++	check_resolved_local_resource(opt->boot_image, dev1, "/vmlinux");
++
++	opt = get_boot_option(ctx, 2);
++	check_name(opt, "c");
++	check_resolved_local_resource(opt->boot_image, dev2, "/vmlinux");
++
++	opt = get_boot_option(ctx, 3);
++	check_name(opt, "d");
++	check_resolved_local_resource(opt->boot_image, dev1, "/vmlinux");
++
++	opt = get_boot_option(ctx, 4);
++	check_name(opt, "e");
++	check_resolved_local_resource(opt->boot_image, dev2, "/vmlinux");
++}
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0011-discover-grub2-Allow-device-path-references-in-gener.patch b/openpower/package/petitboot/0011-discover-grub2-Allow-device-path-references-in-gener.patch
new file mode 100644
index 0000000..e052bdc
--- /dev/null
+++ b/openpower/package/petitboot/0011-discover-grub2-Allow-device-path-references-in-gener.patch
@@ -0,0 +1,214 @@
+From ecc3b2ee3645e2a79236856783d3f803121874b8 Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Mon, 11 Nov 2019 19:30:41 +0800
+Subject: [PATCH 11/18] discover/grub2: Allow (device)/path references in
+ general script usage
+
+Currently, we have support for grub2 (device)/path syntax for boot
+resources. This change allows this syntax for general paths in grub2
+scripts (for example, -f tests).
+
+This involves exposing grub2_lookup_device, to allow the script
+execution code to resolve pathnames.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit b22445748f44ed6965f31f45b39abb690d24ec47)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/grub2/builtins.c                  | 50 ++++++++++++++++---
+ discover/grub2/grub2.c                     |  4 +-
+ discover/grub2/grub2.h                     |  2 +
+ test/parser/Makefile.am                    |  1 +
+ test/parser/test-grub2-devpath-scripting.c | 56 ++++++++++++++++++++++
+ 5 files changed, 104 insertions(+), 9 deletions(-)
+ create mode 100644 test/parser/test-grub2-devpath-scripting.c
+
+diff --git a/discover/grub2/builtins.c b/discover/grub2/builtins.c
+index 765c4d7..c726216 100644
+--- a/discover/grub2/builtins.c
++++ b/discover/grub2/builtins.c
+@@ -197,6 +197,32 @@ static int builtin_search(struct grub2_script *script,
+ 	return 0;
+ }
+ 
++static int parse_to_device_path(struct grub2_script *script,
++		const char *desc, struct discover_device **devp,
++		char **pathp)
++{
++	struct discover_device *dev;
++	struct grub2_file *file;
++
++	file = grub2_parse_file(script, desc);
++	if (!file)
++		return -1;
++
++	dev = script->ctx->device;
++	if (file->dev)
++		dev = grub2_lookup_device(script->ctx->handler, file->dev);
++
++	if (!dev)
++		return -1;
++
++	*devp = dev;
++	*pathp = talloc_strdup(script, file->path);
++
++	talloc_free(file);
++
++	return 0;
++}
++
+ /* Note that GRUB does not follow symlinks in evaluating all file
+  * tests but -s, unlike below. However, it seems like a bad idea to
+  * emulate GRUB's behavior (e.g., it would take extra work), so we
+@@ -204,12 +230,17 @@ static int builtin_search(struct grub2_script *script,
+ static bool builtin_test_op_file(struct grub2_script *script, char op,
+ 		const char *file)
+ {
++	struct discover_device *dev;
++	struct stat statbuf;
+ 	bool result;
++	char *path;
+ 	int rc;
+-	struct stat statbuf;
+ 
+-	rc = parser_stat_path(script->ctx, script->ctx->device,
+-			file, &statbuf);
++	rc = parse_to_device_path(script, file, &dev, &path);
++	if (rc)
++		return false;
++
++	rc = parser_stat_path(script->ctx, dev, path, &statbuf);
+ 	if (rc)
+ 		return false;
+ 
+@@ -237,16 +268,21 @@ static bool builtin_test_op_file(struct grub2_script *script, char op,
+ static bool builtin_test_op_dir(struct grub2_script *script, char op,
+ 		const char *dir)
+ {
+-	int rc;
++	struct discover_device *dev;
+ 	struct stat statbuf;
++	char *path;
++	int rc;
+ 
+ 	if (op != 'd')
+ 		return false;
+ 
+-	rc = parser_stat_path(script->ctx, script->ctx->device, dir, &statbuf);
+-	if (rc) {
++	rc = parse_to_device_path(script, dir, &dev, &path);
++	if (rc)
++		return false;
++
++	rc = parser_stat_path(script->ctx, dev, path, &statbuf);
++	if (rc)
+ 		return false;
+-	}
+ 
+ 	return S_ISDIR(statbuf.st_mode);
+ }
+diff --git a/discover/grub2/grub2.c b/discover/grub2/grub2.c
+index a08a320..a8d115f 100644
+--- a/discover/grub2/grub2.c
++++ b/discover/grub2/grub2.c
+@@ -33,8 +33,8 @@ static const char *const grub2_conf_files[] = {
+ 	NULL
+ };
+ 
+-static struct discover_device *grub2_lookup_device(
+-		struct device_handler *handler, const char *desc)
++struct discover_device *grub2_lookup_device(struct device_handler *handler,
++		const char *desc)
+ {
+ 	struct discover_device *dev;
+ 
+diff --git a/discover/grub2/grub2.h b/discover/grub2/grub2.h
+index ef32d4b..eabd6d6 100644
+--- a/discover/grub2/grub2.h
++++ b/discover/grub2/grub2.h
+@@ -200,6 +200,8 @@ bool resolve_grub2_resource(struct device_handler *handler,
+ /* grub-style device+path parsing */
+ struct grub2_file *grub2_parse_file(struct grub2_script *script,
+ 		const char *str);
++struct discover_device *grub2_lookup_device(struct device_handler *handler,
++		const char *desc);
+ 
+ /* external parser api */
+ struct grub2_parser *grub2_parser_create(struct discover_context *ctx);
+diff --git a/test/parser/Makefile.am b/test/parser/Makefile.am
+index 0378317..c8e059b 100644
+--- a/test/parser/Makefile.am
++++ b/test/parser/Makefile.am
+@@ -33,6 +33,7 @@ parser_TESTS = \
+ 	test/parser/test-grub2-search-uuid \
+ 	test/parser/test-grub2-search-label \
+ 	test/parser/test-grub2-devpath \
++	test/parser/test-grub2-devpath-scripting \
+ 	test/parser/test-grub2-load-env \
+ 	test/parser/test-grub2-save-env \
+ 	test/parser/test-grub2-save-env-dash-f \
+diff --git a/test/parser/test-grub2-devpath-scripting.c b/test/parser/test-grub2-devpath-scripting.c
+new file mode 100644
+index 0000000..9046ab6
+--- /dev/null
++++ b/test/parser/test-grub2-devpath-scripting.c
+@@ -0,0 +1,56 @@
++/* check grub2 device+path string parsing, as used in scripts */
++
++#include "parser-test.h"
++
++#if 0 /* PARSER_EMBEDDED_CONFIG */
++
++v=
++
++# local device, file present
++if [ -f "/1-present" ]; then v=${v}a; fi
++
++# local device, file absent
++if [ -f "/1-absent" ]; then v=${v}b; fi;
++
++# local device by UUID, file present
++if [ -f "(00000000-0000-0000-0000-000000000001)/1-present" ]; then v=${v}c; fi;
++
++# remote device by UUID, file present
++if [ -f "(00000000-0000-0000-0000-000000000002)/2-present" ]; then v=${v}d; fi;
++
++# non-existent device
++if [ -f "(00000000-0000-0000-0000-000000000003)/present" ]; then v=${v}e; fi;
++
++menuentry $v {
++	linux /vmlinux
++}
++
++#endif
++
++void run_test(struct parser_test *test)
++{
++	struct discover_device *dev1, *dev2;
++	struct discover_boot_option *opt;
++	struct discover_context *ctx;
++
++	ctx = test->ctx;
++
++	/* set local uuid */
++	dev1 = test->ctx->device;
++	dev1->uuid = "00000000-0000-0000-0000-000000000001";
++
++	dev2 = test_create_device(test, "extdev");
++	dev2->uuid = "00000000-0000-0000-0000-000000000002";
++	device_handler_add_device(ctx->handler, dev2);
++
++	test_add_file_data(test, dev1, "/1-present", "x", 1);
++	test_add_file_data(test, dev2, "/2-present", "x", 1);
++
++	test_read_conf_embedded(test, "/grub/grub.cfg");
++
++	test_run_parser(test, "grub2");
++
++	check_boot_option_count(ctx, 1);
++	opt = get_boot_option(ctx, 0);
++	check_name(opt, "acd");
++}
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0012-discover-grub2-Add-a-reference-from-script-to-parser.patch b/openpower/package/petitboot/0012-discover-grub2-Add-a-reference-from-script-to-parser.patch
new file mode 100644
index 0000000..8e83dbb
--- /dev/null
+++ b/openpower/package/petitboot/0012-discover-grub2-Add-a-reference-from-script-to-parser.patch
@@ -0,0 +1,43 @@
+From beb095c8b5fbae9eb5f3a77b7135bdeec036910f Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Thu, 14 Nov 2019 09:14:53 +0800
+Subject: [PATCH 12/18] discover/grub2: Add a reference from script to parser
+
+Future commands will need to access the parser, so add a reference from
+struct grub2_script.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit a9a9d575cdab5c32fcb374edf60f0e51f9f7ec9f)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/grub2/grub2.h  | 1 +
+ discover/grub2/script.c | 1 +
+ 2 files changed, 2 insertions(+)
+
+diff --git a/discover/grub2/grub2.h b/discover/grub2/grub2.h
+index eabd6d6..323b461 100644
+--- a/discover/grub2/grub2.h
++++ b/discover/grub2/grub2.h
+@@ -91,6 +91,7 @@ struct grub2_statement_for {
+ };
+ 
+ struct grub2_script {
++	struct grub2_parser		*parser;
+ 	struct grub2_statements		*statements;
+ 	struct list			environment;
+ 	struct list			symtab;
+diff --git a/discover/grub2/script.c b/discover/grub2/script.c
+index 8a9d91d..34e0400 100644
+--- a/discover/grub2/script.c
++++ b/discover/grub2/script.c
+@@ -518,6 +518,7 @@ struct grub2_script *create_script(struct grub2_parser *parser,
+ 	script = talloc_zero(parser, struct grub2_script);
+ 
+ 	script->ctx = ctx;
++	script->parser = parser;
+ 
+ 	list_init(&script->symtab);
+ 	list_init(&script->options);
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0013-discover-grub2-expose-internal-parse-function.patch b/openpower/package/petitboot/0013-discover-grub2-expose-internal-parse-function.patch
new file mode 100644
index 0000000..a5651e1
--- /dev/null
+++ b/openpower/package/petitboot/0013-discover-grub2-expose-internal-parse-function.patch
@@ -0,0 +1,96 @@
+From 706ca57516d2fc92a404a1ca44b2984f17f5eeb3 Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Thu, 14 Nov 2019 13:17:16 +0800
+Subject: [PATCH 13/18] discover/grub2: expose internal parse function
+
+Upcoming changes will need a method to parse a secondary file (to
+support the 'source' command), but not execute it as a new script.
+
+This change exposes the parsing code, separate from the execution code.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit 2c132ebc93a44b7550b1fdb3f5f7b010e51f47e8)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/grub2/grub2-parser.y | 17 +++++++++++++++--
+ discover/grub2/grub2.c        |  2 +-
+ discover/grub2/grub2.h        |  8 ++++++--
+ 3 files changed, 22 insertions(+), 5 deletions(-)
+
+diff --git a/discover/grub2/grub2-parser.y b/discover/grub2/grub2-parser.y
+index 527a61c..f99bbfd 100644
+--- a/discover/grub2/grub2-parser.y
++++ b/discover/grub2/grub2-parser.y
+@@ -331,14 +331,15 @@ struct grub2_parser *grub2_parser_create(struct discover_context *ctx)
+ 	return parser;
+ }
+ 
+-void grub2_parser_parse(struct grub2_parser *parser, const char *filename,
++/* performs a parse on buf, setting parser->script->statements */
++int grub2_parser_parse(struct grub2_parser *parser, const char *filename,
+ 		char *buf, int len)
+ {
+ 	YY_BUFFER_STATE bufstate;
+ 	int rc;
+ 
+ 	if (!len)
+-		return;
++		return -1;
+ 
+ 	parser->script->filename = filename;
+ 
+@@ -349,6 +350,18 @@ void grub2_parser_parse(struct grub2_parser *parser, const char *filename,
+ 
+ 	yy_delete_buffer(bufstate, parser->scanner);
+ 
++	parser->inter_word = false;
++
++	return rc;
++}
++
++void grub2_parser_parse_and_execute(struct grub2_parser *parser,
++		const char *filename, char *buf, int len)
++{
++	int rc;
++
++	rc = grub2_parser_parse(parser, filename, buf, len);
++
+ 	if (!rc)
+ 		script_execute(parser->script);
+ }
+diff --git a/discover/grub2/grub2.c b/discover/grub2/grub2.c
+index a8d115f..b176ce2 100644
+--- a/discover/grub2/grub2.c
++++ b/discover/grub2/grub2.c
+@@ -169,7 +169,7 @@ static int grub2_parse(struct discover_context *dc)
+ 			continue;
+ 
+ 		parser = grub2_parser_create(dc);
+-		grub2_parser_parse(parser, *filename, buf, len);
++		grub2_parser_parse_and_execute(parser, *filename, buf, len);
+ 		device_handler_status_dev_info(dc->handler, dc->device,
+ 				_("Parsed GRUB configuration from %s"),
+ 				*filename);
+diff --git a/discover/grub2/grub2.h b/discover/grub2/grub2.h
+index 323b461..668d070 100644
+--- a/discover/grub2/grub2.h
++++ b/discover/grub2/grub2.h
+@@ -204,9 +204,13 @@ struct grub2_file *grub2_parse_file(struct grub2_script *script,
+ struct discover_device *grub2_lookup_device(struct device_handler *handler,
+ 		const char *desc);
+ 
++/* internal parse api */
++int grub2_parser_parse(struct grub2_parser *parser, const char *filename,
++		char *buf, int len);
++
+ /* external parser api */
+ struct grub2_parser *grub2_parser_create(struct discover_context *ctx);
+-void grub2_parser_parse(struct grub2_parser *parser, const char *filename,
+-		char *buf, int len);
++void grub2_parser_parse_and_execute(struct grub2_parser *parser,
++		const char *filename, char *buf, int len);
+ #endif /* GRUB2_H */
+ 
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0014-discover-grub2-make-statements_execute-non-static.patch b/openpower/package/petitboot/0014-discover-grub2-make-statements_execute-non-static.patch
new file mode 100644
index 0000000..775a881
--- /dev/null
+++ b/openpower/package/petitboot/0014-discover-grub2-make-statements_execute-non-static.patch
@@ -0,0 +1,46 @@
+From 28c0801c20a819182bb59ca0662bf49040c35363 Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Thu, 14 Nov 2019 13:52:57 +0800
+Subject: [PATCH 14/18] discover/grub2: make statements_execute non-static
+
+We want to execute newly-parsed statements, so expose
+statements_execute() to the rest of the grub2 parser code.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit 9711179694bb0e52c5951dc7222f1f79fcba814d)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/grub2/grub2.h  | 3 +++
+ discover/grub2/script.c | 2 +-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/discover/grub2/grub2.h b/discover/grub2/grub2.h
+index 668d070..deaf976 100644
+--- a/discover/grub2/grub2.h
++++ b/discover/grub2/grub2.h
+@@ -165,6 +165,9 @@ void word_append(struct grub2_word *w1, struct grub2_word *w2);
+ /* script interface */
+ void script_execute(struct grub2_script *script);
+ 
++int statements_execute(struct grub2_script *script,
++		struct grub2_statements *stmts);
++
+ int statement_simple_execute(struct grub2_script *script,
+ 		struct grub2_statement *statement);
+ int statement_block_execute(struct grub2_script *script,
+diff --git a/discover/grub2/script.c b/discover/grub2/script.c
+index 34e0400..14931f9 100644
+--- a/discover/grub2/script.c
++++ b/discover/grub2/script.c
+@@ -229,7 +229,7 @@ static void process_expansions(struct grub2_script *script,
+ 		argv->argc--;
+ }
+ 
+-static int statements_execute(struct grub2_script *script,
++int statements_execute(struct grub2_script *script,
+ 		struct grub2_statements *stmts)
+ {
+ 	struct grub2_statement *stmt;
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0015-discover-grub2-implement-source-command.patch b/openpower/package/petitboot/0015-discover-grub2-implement-source-command.patch
new file mode 100644
index 0000000..e9f55ed
--- /dev/null
+++ b/openpower/package/petitboot/0015-discover-grub2-implement-source-command.patch
@@ -0,0 +1,352 @@
+From 772139fd8f8d8b290a5c0a320d88a896b628624b Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Thu, 14 Nov 2019 15:06:26 +0800
+Subject: [PATCH 15/18] discover/grub2: implement 'source' command
+
+This change add support for the grub2 'source' command, executing a
+referenced script in the current parse context.
+
+We impose a limit of 10 (concurrent) source commands, to prevent
+infinite recursion.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit 967cfa7e5c1bfb4d2cf78bb3de3dc6d36b78c440)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ discover/grub2/builtins.c                     | 51 +++++++++++++++-
+ discover/grub2/grub2.h                        |  1 +
+ test/parser/Makefile.am                       |  4 ++
+ test/parser/test-grub2-source-functions.c     | 46 +++++++++++++++
+ .../test-grub2-source-recursion-infinite.c    | 43 ++++++++++++++
+ test/parser/test-grub2-source-recursion.c     | 58 +++++++++++++++++++
+ test/parser/test-grub2-source.c               | 54 +++++++++++++++++
+ 7 files changed, 256 insertions(+), 1 deletion(-)
+ create mode 100644 test/parser/test-grub2-source-functions.c
+ create mode 100644 test/parser/test-grub2-source-recursion-infinite.c
+ create mode 100644 test/parser/test-grub2-source-recursion.c
+ create mode 100644 test/parser/test-grub2-source.c
+
+diff --git a/discover/grub2/builtins.c b/discover/grub2/builtins.c
+index c726216..ab1407a 100644
+--- a/discover/grub2/builtins.c
++++ b/discover/grub2/builtins.c
+@@ -401,6 +401,51 @@ static int builtin_test(struct grub2_script *script,
+ 	return rc ? 0 : 1;
+ }
+ 
++static int builtin_source(struct grub2_script *script,
++		void *data __attribute__((unused)),
++		int argc, char *argv[])
++{
++	struct grub2_statements *statements;
++	struct discover_device *dev;
++	const char *filename;
++	char *path, *buf;
++	int rc, len;
++
++	if (argc != 2)
++		return false;
++
++	/* limit script recursion */
++	if (script->include_depth >= 10)
++		return false;
++
++	rc = parse_to_device_path(script, argv[1], &dev, &path);
++	if (rc)
++		return false;
++
++	rc = parser_request_file(script->ctx, dev, path, &buf, &len);
++	if (rc)
++		return false;
++
++	/* save current script state */
++	statements = script->statements;
++	filename = script->filename;
++	script->include_depth++;
++
++	rc = grub2_parser_parse(script->parser, argv[1], buf, len);
++
++	if (!rc)
++		statements_execute(script, script->statements);
++
++	talloc_free(script->statements);
++
++	/* restore state */
++	script->statements = statements;
++	script->filename = filename;
++	script->include_depth--;
++
++	return !rc;
++}
++
+ static int builtin_true(struct grub2_script *script __attribute__((unused)),
+ 		void *data __attribute__((unused)),
+ 		int argc __attribute__((unused)),
+@@ -491,7 +536,11 @@ static struct {
+ 	{
+ 		.name = "blscfg",
+ 		.fn = builtin_blscfg,
+-	}
++	},
++	{
++		.name = "source",
++		.fn = builtin_source,
++	},
+ };
+ 
+ static const char *nops[] = {
+diff --git a/discover/grub2/grub2.h b/discover/grub2/grub2.h
+index deaf976..75f6aa0 100644
+--- a/discover/grub2/grub2.h
++++ b/discover/grub2/grub2.h
+@@ -100,6 +100,7 @@ struct grub2_script {
+ 	const char			*filename;
+ 	unsigned int			n_options;
+ 	struct list			options;
++	int				include_depth;
+ };
+ 
+ struct grub2_parser {
+diff --git a/test/parser/Makefile.am b/test/parser/Makefile.am
+index c8e059b..5f1a93b 100644
+--- a/test/parser/Makefile.am
++++ b/test/parser/Makefile.am
+@@ -46,6 +46,10 @@ parser_TESTS = \
+ 	test/parser/test-grub2-lexer-error \
+ 	test/parser/test-grub2-parser-error \
+ 	test/parser/test-grub2-test-file-ops \
++	test/parser/test-grub2-source \
++	test/parser/test-grub2-source-functions \
++	test/parser/test-grub2-source-recursion \
++	test/parser/test-grub2-source-recursion-infinite \
+ 	test/parser/test-grub2-single-yocto \
+ 	test/parser/test-grub2-blscfg-default-filename \
+ 	test/parser/test-grub2-blscfg-default-index \
+diff --git a/test/parser/test-grub2-source-functions.c b/test/parser/test-grub2-source-functions.c
+new file mode 100644
+index 0000000..a9da934
+--- /dev/null
++++ b/test/parser/test-grub2-source-functions.c
+@@ -0,0 +1,46 @@
++
++/* check that we can source other scripts, and functions can be defined
++ * and called across sourced scripts */
++
++#include "parser-test.h"
++
++#if 0 /* PARSER_EMBEDDED_CONFIG */
++
++function f1 {
++	menuentry "f1$1" { linux $2 }
++}
++
++source /grub/2.cfg
++
++f2 a /vmlinux
++
++#endif
++
++void run_test(struct parser_test *test)
++{
++	struct discover_boot_option *opt;
++	struct discover_context *ctx;
++	struct discover_device *dev;
++
++	ctx = test->ctx;
++	dev = ctx->device;
++
++	test_read_conf_embedded(test, "/grub/grub.cfg");
++
++	test_add_file_string(test, dev,
++			"/grub/2.cfg",
++			"function f2 { menuentry \"f2$1\" { linux $2 } }\n"
++			"f1 a /vmlinux\n");
++
++	test_run_parser(test, "grub2");
++
++	check_boot_option_count(ctx, 2);
++
++	opt = get_boot_option(ctx, 0);
++	check_name(opt, "f1a");
++	check_resolved_local_resource(opt->boot_image, dev, "/vmlinux");
++
++	opt = get_boot_option(ctx, 1);
++	check_name(opt, "f2a");
++	check_resolved_local_resource(opt->boot_image, dev, "/vmlinux");
++}
+diff --git a/test/parser/test-grub2-source-recursion-infinite.c b/test/parser/test-grub2-source-recursion-infinite.c
+new file mode 100644
+index 0000000..fbcc5a3
+--- /dev/null
++++ b/test/parser/test-grub2-source-recursion-infinite.c
+@@ -0,0 +1,43 @@
++
++/* check that have a maximum source recursion limit */
++
++#include "parser-test.h"
++
++#if 0 /* PARSER_EMBEDDED_CONFIG */
++
++name=a$name
++
++menuentry $name {
++	linux /a
++}
++
++source /grub/grub.cfg
++
++#endif
++
++void run_test(struct parser_test *test)
++{
++	struct discover_boot_option *opt;
++	struct discover_context *ctx;
++	struct discover_device *dev;
++
++	ctx = test->ctx;
++	dev = ctx->device;
++
++	test_read_conf_embedded(test, "/grub/grub.cfg");
++
++	test_run_parser(test, "grub2");
++
++	/* we error out after 10 levels, but we should still have
++	 * parse results up to that point
++	 */
++	check_boot_option_count(ctx, 11);
++
++	opt = get_boot_option(ctx, 0);
++	check_name(opt, "a");
++	check_resolved_local_resource(opt->boot_image, dev, "/a");
++
++	opt = get_boot_option(ctx,10);
++	check_name(opt, "aaaaaaaaaaa");
++	check_resolved_local_resource(opt->boot_image, dev, "/a");
++}
+diff --git a/test/parser/test-grub2-source-recursion.c b/test/parser/test-grub2-source-recursion.c
+new file mode 100644
+index 0000000..21b6bd2
+--- /dev/null
++++ b/test/parser/test-grub2-source-recursion.c
+@@ -0,0 +1,58 @@
++/* check that we can source other files recursively */
++
++#include "parser-test.h"
++
++#if 0 /* PARSER_EMBEDDED_CONFIG */
++
++menuentry a {
++	linux /a
++}
++
++source /grub/2.cfg
++
++menuentry c {
++	linux /c
++}
++
++#endif
++
++void run_test(struct parser_test *test)
++{
++	struct discover_boot_option *opt;
++	struct discover_context *ctx;
++	struct discover_device *dev;
++
++	ctx = test->ctx;
++	dev = ctx->device;
++
++	test_read_conf_embedded(test, "/grub/grub.cfg");
++
++	/* four levels of config files, the last defining a boot option */
++	test_add_file_string(test, dev,
++			"/grub/2.cfg",
++			"source /grub/3.cfg\n");
++
++	test_add_file_string(test, dev,
++			"/grub/3.cfg",
++			"source /grub/4.cfg\n");
++
++	test_add_file_string(test, dev,
++			"/grub/4.cfg",
++			"menuentry b { linux /b }\n");
++
++	test_run_parser(test, "grub2");
++
++	check_boot_option_count(ctx, 3);
++
++	opt = get_boot_option(ctx, 0);
++	check_name(opt, "a");
++	check_resolved_local_resource(opt->boot_image, dev, "/a");
++
++	opt = get_boot_option(ctx, 1);
++	check_name(opt, "b");
++	check_resolved_local_resource(opt->boot_image, dev, "/b");
++
++	opt = get_boot_option(ctx, 2);
++	check_name(opt, "c");
++	check_resolved_local_resource(opt->boot_image, dev, "/c");
++}
+diff --git a/test/parser/test-grub2-source.c b/test/parser/test-grub2-source.c
+new file mode 100644
+index 0000000..a14bef7
+--- /dev/null
++++ b/test/parser/test-grub2-source.c
+@@ -0,0 +1,54 @@
++
++/* check that we can source other scripts, and variables get passed
++ * in to and out of sourced scripts */
++
++#include "parser-test.h"
++
++#if 0 /* PARSER_EMBEDDED_CONFIG */
++
++menuentry a {
++	linux /a
++}
++
++# var: outer -> inner -> outer
++v=b
++
++source /grub/2.cfg
++
++menuentry $v {
++	linux /c
++}
++
++#endif
++
++void run_test(struct parser_test *test)
++{
++	struct discover_boot_option *opt;
++	struct discover_context *ctx;
++	struct discover_device *dev;
++
++	ctx = test->ctx;
++	dev = ctx->device;
++
++	test_read_conf_embedded(test, "/grub/grub.cfg");
++
++	test_add_file_string(test, dev,
++			"/grub/2.cfg",
++			"menuentry $v { linux /b }\nv=c\n");
++
++	test_run_parser(test, "grub2");
++
++	check_boot_option_count(ctx, 3);
++
++	opt = get_boot_option(ctx, 0);
++	check_name(opt, "a");
++	check_resolved_local_resource(opt->boot_image, dev, "/a");
++
++	opt = get_boot_option(ctx, 1);
++	check_name(opt, "b");
++	check_resolved_local_resource(opt->boot_image, dev, "/b");
++
++	opt = get_boot_option(ctx, 2);
++	check_name(opt, "c");
++	check_resolved_local_resource(opt->boot_image, dev, "/c");
++}
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0016-test-parser-Add-test-for-recent-RHCOS-grub2-config.patch b/openpower/package/petitboot/0016-test-parser-Add-test-for-recent-RHCOS-grub2-config.patch
new file mode 100644
index 0000000..de8e4c2
--- /dev/null
+++ b/openpower/package/petitboot/0016-test-parser-Add-test-for-recent-RHCOS-grub2-config.patch
@@ -0,0 +1,278 @@
+From dd5c8ee1440bde77c6829a084c0116d059949720 Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Thu, 14 Nov 2019 15:08:21 +0800
+Subject: [PATCH 16/18] test/parser: Add test for recent RHCOS grub2 config
+
+Add a test for a RHCOS grub2 boot config, using the ignition firstboot
+facility.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit 1ef95c2606eb6c9fcf3530504317f3a0b1a1ba34)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ test/parser/Makefile.am                 |   1 +
+ test/parser/data/grub2-rhcos-ootpa.conf | 194 ++++++++++++++++++++++++
+ test/parser/test-grub2-rhcos-ootpa.c    |  38 +++++
+ 3 files changed, 233 insertions(+)
+ create mode 100644 test/parser/data/grub2-rhcos-ootpa.conf
+ create mode 100644 test/parser/test-grub2-rhcos-ootpa.c
+
+diff --git a/test/parser/Makefile.am b/test/parser/Makefile.am
+index 5f1a93b..5f7922c 100644
+--- a/test/parser/Makefile.am
++++ b/test/parser/Makefile.am
+@@ -43,6 +43,7 @@ parser_TESTS = \
+ 	test/parser/test-grub2-f20-ppc64 \
+ 	test/parser/test-grub2-ubuntu-13_04-x86 \
+ 	test/parser/test-grub2-sles-btrfs-snapshot \
++	test/parser/test-grub2-rhcos-ootpa \
+ 	test/parser/test-grub2-lexer-error \
+ 	test/parser/test-grub2-parser-error \
+ 	test/parser/test-grub2-test-file-ops \
+diff --git a/test/parser/data/grub2-rhcos-ootpa.conf b/test/parser/data/grub2-rhcos-ootpa.conf
+new file mode 100644
+index 0000000..329980e
+--- /dev/null
++++ b/test/parser/data/grub2-rhcos-ootpa.conf
+@@ -0,0 +1,194 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -f ${config_directory}/grubenv ]; then
++  load_env -f ${config_directory}/grubenv
++elif [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output ofconsole
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=1
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=1
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/01_menu_auto_hide ###
++if [ "${boot_success}" = "1" -o "${boot_indeterminate}" = "1" ]; then
++  set last_boot_ok=1
++else
++  set last_boot_ok=0
++fi
++
++# Reset boot_indeterminate after a successful boot
++if [ "${boot_success}" = "1" ] ; then
++  set boot_indeterminate=0
++# Avoid boot_indeterminate causing the menu to be hidden more then once
++elif [ "${boot_indeterminate}" = "1" ]; then
++  set boot_indeterminate=2
++fi
++set boot_success=0
++save_env boot_success boot_indeterminate
++
++if [ x$feature_timeout_style = xy ] ; then
++  if [ "${menu_show_once}" ]; then
++    unset menu_show_once
++    save_env menu_show_once
++    set timeout_style=menu
++    set timeout=60
++  elif [ "${menu_auto_hide}" -a "${last_boot_ok}" = "1" ]; then
++    set orig_timeout_style=${timeout_style}
++    set orig_timeout=${timeout}
++    if [ "${fastboot}" = "1" ]; then
++      # timeout_style=menu + timeout=0 avoids the countdown code keypress check
++      set timeout_style=menu
++      set timeout=0
++    else
++      set timeout_style=hidden
++      set timeout=1
++    fi
++  fi
++fi
++### END /etc/grub.d/01_menu_auto_hide ###
++
++### BEGIN /etc/grub.d/01_users ###
++if [ -f ${prefix}/user.cfg ]; then
++  source ${prefix}/user.cfg
++  if [ -n "${GRUB2_PASSWORD}" ]; then
++    set superusers="root"
++    export superusers
++    password_pbkdf2 root ${GRUB2_PASSWORD}
++  fi
++fi
++### END /etc/grub.d/01_users ###
++
++### BEGIN /etc/grub.d/02_ignition_firstboot ###
++# We store the file on the /boot/ partition so find the
++# boot partition. On UEFI this may different than the grub
++# $root so we search for it here.
++# https://github.com/coreos/ignition-dracut/issues/51
++search --set=bootpart --label boot
++# Determine if this is a first boot and set the variable
++# to be used later on the kernel command line.
++set ignition_firstboot=""
++if [ -f "(${bootpart})/ignition.firstboot" ]; then
++    # default to dhcp networking parameters to be used with ignition 
++    set ignition_network_kcmdline='rd.neednet=1 ip=dhcp'
++
++    # source in the `ignition.firstboot` file which could override the
++    # above $ignition_network_kcmdline with static networking config.
++    # This override feature is primarily used by coreos-installer to
++    # persist static networking config provided during install to the    
++    # first boot of the machine.
++    source "(${bootpart})/ignition.firstboot"
++    
++    # we support setting variables in the 
++    set ignition_firstboot="ignition.firstboot $ignition_network_kcmdline $ignition_extra_kcmdline"
++fi
++### END /etc/grub.d/02_ignition_firstboot ###
++
++### BEGIN /etc/grub.d/10_linux_bls ###
++
++### END /etc/grub.d/10_linux_bls ###
++
++### BEGIN /etc/grub.d/15_ostree ###
++menuentry 'Red Hat Enterprise Linux CoreOS 42.80.20191030.0 (Ootpa) (ostree)' --class gnu-linux --class gnu --class os --unrestricted 'ostree-0-645e1535-a6f3-4fa6-a82c-b8c032619a7b' {
++load_video
++set gfxpayload=keep
++insmod gzio
++insmod part_gpt
++insmod ext2
++set root='hd0,gpt2'
++if [ x$feature_platform_search_hint = xy ]; then
++  search --no-floppy --fs-uuid --set=root --hint='hd0,gpt2'  645e1535-a6f3-4fa6-a82c-b8c032619a7b
++else
++  search --no-floppy --fs-uuid --set=root 645e1535-a6f3-4fa6-a82c-b8c032619a7b
++fi
++linux /ostree/rhcos-6264e4be818e20cf1021bd6e7aa8c76147ce07dec186468c7dfbbc9c5dfc7d8b/vmlinuz-4.18.0-80.11.2.el8_0.ppc64le console=tty0 console=hvc0,115200n8 rootflags=defaults,prjquota rw $ignition_firstboot root=UUID=8d8a5c3b-97e6-4d7b-bb87-206af5a9d851 ostree=/ostree/boot.0/rhcos/6264e4be818e20cf1021bd6e7aa8c76147ce07dec186468c7dfbbc9c5dfc7d8b/0 ignition.platform.id=openstack
++initrd /ostree/rhcos-6264e4be818e20cf1021bd6e7aa8c76147ce07dec186468c7dfbbc9c5dfc7d8b/initramfs-4.18.0-80.11.2.el8_0.ppc64le.img
++}
++### END /etc/grub.d/15_ostree ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++  terminfo -g 80x24 ofconsole
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/30_uefi-firmware ###
++### END /etc/grub.d/30_uefi-firmware ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/parser/test-grub2-rhcos-ootpa.c b/test/parser/test-grub2-rhcos-ootpa.c
+new file mode 100644
+index 0000000..19299be
+--- /dev/null
++++ b/test/parser/test-grub2-rhcos-ootpa.c
+@@ -0,0 +1,38 @@
++
++#include "parser-test.h"
++
++void run_test(struct parser_test *test)
++{
++	struct discover_boot_option *opt;
++	struct discover_context *ctx;
++	struct discover_device *dev;
++
++	ctx = test->ctx;
++
++	dev = test_create_device(test, "bootdev");
++	dev->label = "boot";
++	device_handler_add_device(test->handler, dev);
++
++	test_read_conf_file(test, "grub2-rhcos-ootpa.conf",
++			"/grub/grub.cfg");
++
++	/* add the ignition.firstboot file on the boot-labelled partition,
++	 * to check that we can source this correctly */
++	test_add_file_string(test, dev,
++			"/ignition.firstboot",
++			"ignition_extra_kcmdline=meep\n");
++
++	test_run_parser(test, "grub2");
++
++	check_boot_option_count(ctx, 1);
++
++	opt = get_boot_option(ctx, 0);
++	check_name(opt,
++		"Red Hat Enterprise Linux CoreOS 42.80.20191030.0 (Ootpa) (ostree)");
++	check_args(opt, "console=tty0 console=hvc0,115200n8 "
++			"rootflags=defaults,prjquota rw "
++			"ignition.firstboot rd.neednet=1 ip=dhcp meep "
++			"root=UUID=8d8a5c3b-97e6-4d7b-bb87-206af5a9d851 "
++			"ostree=/ostree/boot.0/rhcos/6264e4be818e20cf1021bd6e7aa8c76147ce07dec186468c7dfbbc9c5dfc7d8b/0 "
++			"ignition.platform.id=openstack");
++}
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0017-test-parser-Add-RHEL8-grub-config-test.patch b/openpower/package/petitboot/0017-test-parser-Add-RHEL8-grub-config-test.patch
new file mode 100644
index 0000000..51bcb74
--- /dev/null
+++ b/openpower/package/petitboot/0017-test-parser-Add-RHEL8-grub-config-test.patch
@@ -0,0 +1,254 @@
+From 1e8fc53f15c4703a76911e75d906965e3d967e8f Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Thu, 14 Nov 2019 15:22:35 +0800
+Subject: [PATCH 17/18] test/parser: Add RHEL8 grub config test
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit 057dce2dadee2e2fca370d4497c8c792b001c2d3)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ test/parser/Makefile.am           |   1 +
+ test/parser/data/grub2-rhel8.conf | 190 ++++++++++++++++++++++++++++++
+ test/parser/test-grub2-rhel8.c    |  21 ++++
+ 3 files changed, 212 insertions(+)
+ create mode 100644 test/parser/data/grub2-rhel8.conf
+ create mode 100644 test/parser/test-grub2-rhel8.c
+
+diff --git a/test/parser/Makefile.am b/test/parser/Makefile.am
+index 5f7922c..9d1141c 100644
+--- a/test/parser/Makefile.am
++++ b/test/parser/Makefile.am
+@@ -43,6 +43,7 @@ parser_TESTS = \
+ 	test/parser/test-grub2-f20-ppc64 \
+ 	test/parser/test-grub2-ubuntu-13_04-x86 \
+ 	test/parser/test-grub2-sles-btrfs-snapshot \
++	test/parser/test-grub2-rhel8 \
+ 	test/parser/test-grub2-rhcos-ootpa \
+ 	test/parser/test-grub2-lexer-error \
+ 	test/parser/test-grub2-parser-error \
+diff --git a/test/parser/data/grub2-rhel8.conf b/test/parser/data/grub2-rhel8.conf
+new file mode 100644
+index 0000000..563b3e5
+--- /dev/null
++++ b/test/parser/data/grub2-rhel8.conf
+@@ -0,0 +1,190 @@
++#
++# DO NOT EDIT THIS FILE
++#
++# It is automatically generated by grub2-mkconfig using templates
++# from /etc/grub.d and settings from /etc/default/grub
++#
++
++### BEGIN /etc/grub.d/00_header ###
++set pager=1
++
++if [ -f ${config_directory}/grubenv ]; then
++  load_env -f ${config_directory}/grubenv
++elif [ -s $prefix/grubenv ]; then
++  load_env
++fi
++if [ "${next_entry}" ] ; then
++   set default="${next_entry}"
++   set next_entry=
++   save_env next_entry
++   set boot_once=true
++else
++   set default="${saved_entry}"
++fi
++
++if [ x"${feature_menuentry_id}" = xy ]; then
++  menuentry_id_option="--id"
++else
++  menuentry_id_option=""
++fi
++
++export menuentry_id_option
++
++if [ "${prev_saved_entry}" ]; then
++  set saved_entry="${prev_saved_entry}"
++  save_env saved_entry
++  set prev_saved_entry=
++  save_env prev_saved_entry
++  set boot_once=true
++fi
++
++function savedefault {
++  if [ -z "${boot_once}" ]; then
++    saved_entry="${chosen}"
++    save_env saved_entry
++  fi
++}
++
++function load_video {
++  if [ x$feature_all_video_module = xy ]; then
++    insmod all_video
++  else
++    insmod efi_gop
++    insmod efi_uga
++    insmod ieee1275_fb
++    insmod vbe
++    insmod vga
++    insmod video_bochs
++    insmod video_cirrus
++  fi
++}
++
++terminal_output ofconsole
++if [ x$feature_timeout_style = xy ] ; then
++  set timeout_style=menu
++  set timeout=5
++# Fallback normal timeout code in case the timeout_style feature is
++# unavailable.
++else
++  set timeout=5
++fi
++### END /etc/grub.d/00_header ###
++
++### BEGIN /etc/grub.d/00_tuned ###
++set tuned_params=""
++set tuned_initrd=""
++### END /etc/grub.d/00_tuned ###
++
++### BEGIN /etc/grub.d/01_menu_auto_hide ###
++if [ "${boot_success}" = "1" -o "${boot_indeterminate}" = "1" ]; then
++  set last_boot_ok=1
++else
++  set last_boot_ok=0
++fi
++
++# Reset boot_indeterminate after a successful boot
++if [ "${boot_success}" = "1" ] ; then
++  set boot_indeterminate=0
++# Avoid boot_indeterminate causing the menu to be hidden more then once
++elif [ "${boot_indeterminate}" = "1" ]; then
++  set boot_indeterminate=2
++fi
++set boot_success=0
++save_env boot_success boot_indeterminate
++
++if [ x$feature_timeout_style = xy ] ; then
++  if [ "${menu_show_once}" ]; then
++    unset menu_show_once
++    save_env menu_show_once
++    set timeout_style=menu
++    set timeout=60
++  elif [ "${menu_auto_hide}" -a "${last_boot_ok}" = "1" ]; then
++    set orig_timeout_style=${timeout_style}
++    set orig_timeout=${timeout}
++    if [ "${fastboot}" = "1" ]; then
++      # timeout_style=menu + timeout=0 avoids the countdown code keypress check
++      set timeout_style=menu
++      set timeout=0
++    else
++      set timeout_style=hidden
++      set timeout=1
++    fi
++  fi
++fi
++### END /etc/grub.d/01_menu_auto_hide ###
++
++### BEGIN /etc/grub.d/01_users ###
++if [ -f ${prefix}/user.cfg ]; then
++  source ${prefix}/user.cfg
++  if [ -n "${GRUB2_PASSWORD}" ]; then
++    set superusers="root"
++    export superusers
++    password_pbkdf2 root ${GRUB2_PASSWORD}
++  fi
++fi
++### END /etc/grub.d/01_users ###
++
++### BEGIN /etc/grub.d/10_linux_bls ###
++insmod part_msdos
++insmod xfs
++set root='hd0,msdos2'
++if [ x$feature_platform_search_hint = xy ]; then
++  search --no-floppy --fs-uuid --set=root --hint-ieee1275='ieee1275//pciex@600c3c0100000/pci@0/pci@0/pci@9/raid@0/disk@8,msdos2' --hint-bios=hd0,msdos2 --hint-efi=hd0,msdos2 --hint-baremetal=ahci0,msdos2 --hint='hd0,msdos2'  9a8ea027-4829-45b9-829b-18ed6cc1f33b
++else
++  search --no-floppy --fs-uuid --set=root 9a8ea027-4829-45b9-829b-18ed6cc1f33b
++fi
++insmod part_msdos
++insmod xfs
++set boot='hd0,msdos2'
++if [ x$feature_platform_search_hint = xy ]; then
++  search --no-floppy --fs-uuid --set=boot --hint-ieee1275='ieee1275//pciex@600c3c0100000/pci@0/pci@0/pci@9/raid@0/disk@8,msdos2' --hint-bios=hd0,msdos2 --hint-efi=hd0,msdos2 --hint-baremetal=ahci0,msdos2 --hint='hd0,msdos2'  9a8ea027-4829-45b9-829b-18ed6cc1f33b
++else
++  search --no-floppy --fs-uuid --set=boot 9a8ea027-4829-45b9-829b-18ed6cc1f33b
++fi
++
++# This section was generated by a script. Do not modify the generated file - all changes
++# will be lost the next time file is regenerated. Instead edit the BootLoaderSpec files.
++
++menuentry 'Red Hat Enterprise Linux (4.18.0-80.11.2.el8_0.ppc64le) 8.0 (Ootpa)' --class kernel --unrestricted --users $grub_users --id 8e15296c9cc14deb9e3f8548d49fd6fc-4.18.0-80.11.2.el8_0.ppc64le {
++	 linux /vmlinuz-4.18.0-80.11.2.el8_0.ppc64le $kernelopts $tuned_params
++	 initrd /initramfs-4.18.0-80.11.2.el8_0.ppc64le.img $tuned_initrd
++}
++
++menuentry 'Red Hat Enterprise Linux (4.18.0-80.el8.ppc64le) 8.0 (Ootpa)' --class kernel --unrestricted --users $grub_users --id 8e15296c9cc14deb9e3f8548d49fd6fc-4.18.0-80.el8.ppc64le {
++	 linux /vmlinuz-4.18.0-80.el8.ppc64le $kernelopts $tuned_params
++	 initrd /initramfs-4.18.0-80.el8.ppc64le.img $tuned_initrd
++}
++
++menuentry 'Red Hat Enterprise Linux (0-rescue-8e15296c9cc14deb9e3f8548d49fd6fc) 8.0 (Ootpa)' --class kernel --unrestricted --users $grub_users --id 8e15296c9cc14deb9e3f8548d49fd6fc-0-rescue {
++	 linux /vmlinuz-0-rescue-8e15296c9cc14deb9e3f8548d49fd6fc $kernelopts
++	 initrd /initramfs-0-rescue-8e15296c9cc14deb9e3f8548d49fd6fc.img
++}
++
++### END /etc/grub.d/10_linux_bls ###
++
++### BEGIN /etc/grub.d/20_linux_xen ###
++### END /etc/grub.d/20_linux_xen ###
++
++### BEGIN /etc/grub.d/20_ppc_terminfo ###
++  terminfo -g 80x24 ofconsole
++### END /etc/grub.d/20_ppc_terminfo ###
++
++### BEGIN /etc/grub.d/30_os-prober ###
++### END /etc/grub.d/30_os-prober ###
++
++### BEGIN /etc/grub.d/30_uefi-firmware ###
++### END /etc/grub.d/30_uefi-firmware ###
++
++### BEGIN /etc/grub.d/40_custom ###
++# This file provides an easy way to add custom menu entries.  Simply type the
++# menu entries you want to add after this comment.  Be careful not to change
++# the 'exec tail' line above.
++### END /etc/grub.d/40_custom ###
++
++### BEGIN /etc/grub.d/41_custom ###
++if [ -f  ${config_directory}/custom.cfg ]; then
++  source ${config_directory}/custom.cfg
++elif [ -z "${config_directory}" -a -f  $prefix/custom.cfg ]; then
++  source $prefix/custom.cfg;
++fi
++### END /etc/grub.d/41_custom ###
+diff --git a/test/parser/test-grub2-rhel8.c b/test/parser/test-grub2-rhel8.c
+new file mode 100644
+index 0000000..3e208bc
+--- /dev/null
++++ b/test/parser/test-grub2-rhel8.c
+@@ -0,0 +1,21 @@
++
++#include "parser-test.h"
++
++void run_test(struct parser_test *test)
++{
++	struct discover_context *ctx;
++	struct discover_device *dev;
++
++	ctx = test->ctx;
++
++	dev = test_create_device(test, "boot");
++	dev->uuid = "9a8ea027-4829-45b9-829b-18ed6cc1f33b";
++	device_handler_add_device(test->handler, dev);
++
++	test_read_conf_file(test, "grub2-rhel8.conf",
++			"/grub/grub.cfg");
++
++	test_run_parser(test, "grub2");
++
++	check_boot_option_count(ctx, 3);
++}
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/0018-lib-pb-protocol-fix-ordering-of-system-info-length-c.patch b/openpower/package/petitboot/0018-lib-pb-protocol-fix-ordering-of-system-info-length-c.patch
new file mode 100644
index 0000000..a1f0ba9
--- /dev/null
+++ b/openpower/package/petitboot/0018-lib-pb-protocol-fix-ordering-of-system-info-length-c.patch
@@ -0,0 +1,42 @@
+From 74226ad7cbb0c2a5b4e9fa3c0de6335a2540952e Mon Sep 17 00:00:00 2001
+From: Jeremy Kerr <jk@ozlabs.org>
+Date: Wed, 20 Nov 2019 12:20:43 +0800
+Subject: [PATCH 18/18] lib/pb-protocol: fix ordering of system info length
+ calculation
+
+... to match the definition of struct system_info.
+
+Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
+(cherry picked from commit 6ee9cbcb1bd6ef9fbf1a56322e3fe2fa2646159c)
+Signed-off-by: Klaus Heinrich Kiwi <klaus@linux.vnet.ibm.com>
+---
+ lib/pb-protocol/pb-protocol.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/lib/pb-protocol/pb-protocol.c b/lib/pb-protocol/pb-protocol.c
+index daf4ec9..e0cef36 100644
+--- a/lib/pb-protocol/pb-protocol.c
++++ b/lib/pb-protocol/pb-protocol.c
+@@ -253,6 +253,9 @@ int pb_protocol_system_info_len(const struct system_info *sysinfo)
+ 	for (i = 0; i < sysinfo->n_bmc_golden; i++)
+ 		len += 4 + optional_strlen(sysinfo->bmc_golden[i]);
+ 
++	/* BMC MAC */
++	len += HWADDR_SIZE;
++
+ 	for (i = 0; i < sysinfo->n_interfaces; i++) {
+ 		struct interface_info *if_info = sysinfo->interfaces[i];
+ 		len +=	4 + if_info->hwaddr_size +
+@@ -269,9 +272,6 @@ int pb_protocol_system_info_len(const struct system_info *sysinfo)
+ 			4 + optional_strlen(bd_info->mountpoint);
+ 	}
+ 
+-	/* BMC MAC */
+-	len += HWADDR_SIZE;
+-
+ 	return len;
+ }
+ 
+-- 
+2.17.1
+
diff --git a/openpower/package/petitboot/petitboot.hash b/openpower/package/petitboot/petitboot.hash
index e9c773d..9b9dd3d 100644
--- a/openpower/package/petitboot/petitboot.hash
+++ b/openpower/package/petitboot/petitboot.hash
@@ -1 +1 @@
-sha256 d2ae58adb8f69b5da854de890c1bbe12008c627b1921cd1c686ead642a134867  petitboot-v1.10.3.tar.gz
+sha256 8573b5c1bc22f49a5770618c99cc3e05f5bfbabd8c9474cd26754519d3175a85  petitboot-v1.10.4.tar.gz
diff --git a/openpower/package/petitboot/petitboot.mk b/openpower/package/petitboot/petitboot.mk
index 1d97a3e..2a699f8 100644
--- a/openpower/package/petitboot/petitboot.mk
+++ b/openpower/package/petitboot/petitboot.mk
@@ -4,7 +4,7 @@
 #
 ################################################################################
 
-PETITBOOT_VERSION = v1.10.3
+PETITBOOT_VERSION = v1.10.4
 PETITBOOT_SOURCE = petitboot-$(PETITBOOT_VERSION).tar.gz
 PETITBOOT_SITE ?= https://github.com/open-power/petitboot/releases/download/$(PETITBOOT_VERSION)
 PETITBOOT_DEPENDENCIES = ncurses udev host-bison host-flex lvm2
@@ -33,6 +33,12 @@
 PETITBOOT_CONF_OPTS += --with-ncursesw MENU_LIB=-lmenuw FORM_LIB=-lformw
 endif
 
+# Autoreconf is needed because we're touching a few Makefiles.am
+PETITBOOT_AUTORECONF = YES
+
+# And Gettext is needed because we'll update Makefile.in.in
+PETITBOOT_GETTEXTIZE = YES
+
 define PETITBOOT_POST_INSTALL
 	$(INSTALL) -D -m 0755 $(@D)/utils/bb-kexec-reboot \
 		$(TARGET_DIR)/usr/libexec/petitboot