From 08190ef7de1b9b155fda22bec28edd747223a421 Mon Sep 17 00:00:00 2001 From: Stanislav Galabov Date: Wed, 9 Mar 2016 11:45:48 +0000 Subject: [PATCH] Improve U-Boot API detection Until now, ubldr has been trying to locate the U-Boot API using a hint address (U-Boot's current stack pointer), aligning it to 1MiB and going over a 3MiB (or 1MiB in case of MIPS) memory region searching for a valid API signature. This change introduces an alternative way of doing this, namely the following: - both U-Boot's bootelf and go commands actually pass argc and argv to the entry point (e.g., ubldr's start function, but they should also be passed over to main() transparently) - so, instead of trying to go and look for a valid API signature, we look at the parameters passed to main() - if there's an option '-a' with argument, which is a valid hexadecimal unsigned long number (x), we try to verify whether we have a valid API signature at address x. If so - we use it. If not - we fallback to the original way of locating the API signature. The U-Boot change, which causes the API structure address to be exported as an environment variable, was committed to mainline U-Boot as commit 22aa61f707574dd569296f521fcfc46a05f51c48 Reviewed by: andrew, adrian Approved by: adrian (mentor) Sponsored by: Smartcom - Bulgaria AD Differential Revision: https://reviews.freebsd.org/D5492 --- sys/boot/uboot/common/main.c | 7 +++++-- sys/boot/uboot/lib/glue.c | 35 +++++++++++++++++++++++++++++++++++ sys/boot/uboot/lib/glue.h | 1 + 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/sys/boot/uboot/common/main.c b/sys/boot/uboot/common/main.c index f4fe214e7e99..d5c76644b0c7 100644 --- a/sys/boot/uboot/common/main.c +++ b/sys/boot/uboot/common/main.c @@ -387,7 +387,7 @@ probe_disks(int devidx, int load_type, int load_unit, int load_slice, } int -main(void) +main(int argc, char **argv) { struct api_signature *sig = NULL; int load_type, load_unit, load_slice, load_partition; @@ -395,12 +395,15 @@ main(void) const char *ldev; /* + * We first check if a command line argument was passed to us containing + * API's signature address. If it wasn't then we try to search for the + * API signature via the usual hinted address. * If we can't find the magic signature and related info, exit with a * unique error code that U-Boot reports as "## Application terminated, * rc = 0xnnbadab1". Hopefully 'badab1' looks enough like "bad api" to * provide a clue. It's better than 0xffffffff anyway. */ - if (!api_search_sig(&sig)) + if (!api_parse_cmdline_sig(argc, argv, &sig) && !api_search_sig(&sig)) return (0x01badab1); syscall_ptr = sig->syscall; diff --git a/sys/boot/uboot/lib/glue.c b/sys/boot/uboot/lib/glue.c index 4c843f0c422d..07db23dba0a7 100644 --- a/sys/boot/uboot/lib/glue.c +++ b/sys/boot/uboot/lib/glue.c @@ -67,6 +67,41 @@ valid_sig(struct api_signature *sig) return (1); } +/* + * Checks to see if API signature's address was given to us as a command line + * argument by U-Boot. + * + * returns 1/0 depending on found/not found result + */ +int +api_parse_cmdline_sig(int argc, char **argv, struct api_signature **sig) +{ + unsigned long api_address; + int c; + + api_address = 0; + opterr = 0; + optreset = 1; + optind = 1; + + while ((c = getopt (argc, argv, "a:")) != -1) + switch (c) { + case 'a': + api_address = strtoul(optarg, NULL, 16); + break; + default: + break; + } + + if (api_address != 0) { + *sig = (struct api_signature *)api_address; + if (valid_sig(*sig)) + return (1); + } + + return (0); +} + /* * Searches for the U-Boot API signature * diff --git a/sys/boot/uboot/lib/glue.h b/sys/boot/uboot/lib/glue.h index b9c60b625c0b..4c2da66ccb27 100644 --- a/sys/boot/uboot/lib/glue.h +++ b/sys/boot/uboot/lib/glue.h @@ -58,6 +58,7 @@ int syscall(int, int *, ...); void *syscall_ptr; +int api_parse_cmdline_sig(int argc, char **argv, struct api_signature **sig); int api_search_sig(struct api_signature **sig); #define UB_MAX_MR 16 /* max mem regions number */