[PATCH v4] arm64: Add purgatory printing
Bhupesh Sharma
bhsharma at redhat.com
Fri Oct 2 14:34:35 EDT 2020
Hello Matthias,
Thanks for the updated revision.
On Fri, Oct 2, 2020 at 7:13 PM <matthias.bgg at kernel.org> wrote:
>
> From: Matthias Brugger <mbrugger at suse.com>
>
> Add option to allow purgatory printing on arm64 hardware
> by passing the console name which should be used.
> Based on a patch by Geoff Levand.
>
> Cc: Geoff Levand <geoff at infradead.org>
> Signed-off-by: Matthias Brugger <mbrugger at suse.com>
>
> ---
>
> Changes in v4:
> - fix snprintf error handling
>
> Changes in v3:
> - check return value of snprintf
>
> Changes in v2:
> - use sizeof(buffer)
> - user serial command option instead of console
> - reduce buffer to size 10
> - use snprintf
> - fix error handling for wrong serial console parameter
> - Update help information
>
> kexec/arch/arm64/include/arch/options.h | 6 ++-
> kexec/arch/arm64/kexec-arm64.c | 71 +++++++++++++++++++++++++
> purgatory/arch/arm64/purgatory-arm64.c | 17 +++++-
> 3 files changed, 92 insertions(+), 2 deletions(-)
>
> diff --git a/kexec/arch/arm64/include/arch/options.h b/kexec/arch/arm64/include/arch/options.h
> index a17d933..8c695f3 100644
> --- a/kexec/arch/arm64/include/arch/options.h
> +++ b/kexec/arch/arm64/include/arch/options.h
> @@ -5,7 +5,8 @@
> #define OPT_DTB ((OPT_MAX)+1)
> #define OPT_INITRD ((OPT_MAX)+2)
> #define OPT_REUSE_CMDLINE ((OPT_MAX)+3)
> -#define OPT_ARCH_MAX ((OPT_MAX)+4)
> +#define OPT_SERIAL ((OPT_MAX)+4)
> +#define OPT_ARCH_MAX ((OPT_MAX)+5)
>
> #define KEXEC_ARCH_OPTIONS \
> KEXEC_OPTIONS \
> @@ -13,6 +14,7 @@
> { "command-line", 1, NULL, OPT_APPEND }, \
> { "dtb", 1, NULL, OPT_DTB }, \
> { "initrd", 1, NULL, OPT_INITRD }, \
> + { "serial", 1, NULL, OPT_SERIAL }, \
> { "ramdisk", 1, NULL, OPT_INITRD }, \
> { "reuse-cmdline", 0, NULL, OPT_REUSE_CMDLINE }, \
>
> @@ -25,6 +27,7 @@ static const char arm64_opts_usage[] __attribute__ ((unused)) =
> " --command-line=STRING Set the kernel command line to STRING.\n"
> " --dtb=FILE Use FILE as the device tree blob.\n"
> " --initrd=FILE Use FILE as the kernel initial ramdisk.\n"
> +" --serial=STRING Name of console used for purgatory printing. (e.g. ttyAMA0)\n"
> " --ramdisk=FILE Use FILE as the kernel initial ramdisk.\n"
> " --reuse-cmdline Use kernel command line from running system.\n";
>
> @@ -32,6 +35,7 @@ struct arm64_opts {
> const char *command_line;
> const char *dtb;
> const char *initrd;
> + const char *console;
> };
>
> extern struct arm64_opts arm64_opts;
> diff --git a/kexec/arch/arm64/kexec-arm64.c b/kexec/arch/arm64/kexec-arm64.c
> index 45ebc54..6f572ed 100644
> --- a/kexec/arch/arm64/kexec-arm64.c
> +++ b/kexec/arch/arm64/kexec-arm64.c
> @@ -165,6 +165,8 @@ int arch_process_options(int argc, char **argv)
> break;
> case OPT_KEXEC_FILE_SYSCALL:
> do_kexec_file_syscall = 1;
> + case OPT_SERIAL:
> + arm64_opts.console = optarg;
> break;
> default:
> break; /* Ignore core and unknown options. */
> @@ -180,12 +182,72 @@ int arch_process_options(int argc, char **argv)
> dbgprintf("%s:%d: dtb: %s\n", __func__, __LINE__,
> (do_kexec_file_syscall && arm64_opts.dtb ? "(ignored)" :
> arm64_opts.dtb));
> + dbgprintf("%s:%d: console: %s\n", __func__, __LINE__,
> + arm64_opts.console);
> +
> if (do_kexec_file_syscall)
> arm64_opts.dtb = NULL;
>
> return 0;
> }
>
> +/**
> + * find_purgatory_sink - Find a sink for purgatory output.
> + */
> +
> +static uint64_t find_purgatory_sink(const char *console)
> +{
> + int fd, ret;
> + char device[255], mem[255];
> + struct stat sb;
> + char buffer[10];
> + uint64_t iomem = 0x0;
> +
> + if (!console)
> + return 0;
> +
> + ret = snprintf(device, sizeof(device), "/sys/class/tty/%s", console);
> + if (ret < 0 || ret >= sizeof(device)) {
> + fprintf(stderr, "snprintf failed: %s\n", strerror(errno));
> + return 0;
> + }
> +
> + if (stat(device, &sb) || !S_ISDIR(sb.st_mode)) {
> + fprintf(stderr, "kexec: %s: No valid console found for %s\n",
> + __func__, device);
> + return 0;
> + }
> +
> + ret = snprintf(mem, sizeof(mem), "%s%s", device, "/iomem_base");
> + if (ret < 0 || ret >= sizeof(mem)) {
> + fprintf(stderr, "snprintf failed: %s\n", strerror(errno));
> + return 0;
> + }
> +
> + printf("console memory read from %s\n", mem);
> +
> + fd = open(mem, O_RDONLY);
> + if (fd < 0) {
> + fprintf(stderr, "kexec: %s: No able to open %s\n",
> + __func__, mem);
> + return 0;
> + }
> +
> + memset(buffer, '\0', sizeof(buffer));
> + ret = read(fd, buffer, sizeof(buffer));
> + if (ret < 0) {
> + fprintf(stderr, "kexec: %s: not able to read fd\n", __func__);
> + close(fd);
> + return 0;
> + }
> +
> + sscanf(buffer, "%lx", &iomem);
> + printf("console memory is at %#lx\n", iomem);
> +
> + close(fd);
> + return iomem;
> +}
> +
> /**
> * struct dtb - Info about a binary device tree.
> *
> @@ -637,6 +699,7 @@ int arm64_load_other_segments(struct kexec_info *info,
> unsigned long hole_min;
> unsigned long hole_max;
> unsigned long initrd_end;
> + uint64_t purgatory_sink;
> char *initrd_buf = NULL;
> struct dtb dtb;
> char command_line[COMMAND_LINE_SIZE] = "";
> @@ -654,6 +717,11 @@ int arm64_load_other_segments(struct kexec_info *info,
> command_line[sizeof(command_line) - 1] = 0;
> }
>
> + purgatory_sink = find_purgatory_sink(arm64_opts.console);
> +
> + dbgprintf("%s:%d: purgatory sink: 0x%" PRIx64 "\n", __func__, __LINE__,
> + purgatory_sink);
> +
> if (arm64_opts.dtb) {
> dtb.name = "dtb_user";
> dtb.buf = slurp_file(arm64_opts.dtb, &dtb.size);
> @@ -742,6 +810,9 @@ int arm64_load_other_segments(struct kexec_info *info,
>
> info->entry = (void *)elf_rel_get_addr(&info->rhdr, "purgatory_start");
>
> + elf_rel_set_symbol(&info->rhdr, "arm64_sink", &purgatory_sink,
> + sizeof(purgatory_sink));
> +
> elf_rel_set_symbol(&info->rhdr, "arm64_kernel_entry", &image_base,
> sizeof(image_base));
>
> diff --git a/purgatory/arch/arm64/purgatory-arm64.c b/purgatory/arch/arm64/purgatory-arm64.c
> index fe50fcf..b4d8578 100644
> --- a/purgatory/arch/arm64/purgatory-arm64.c
> +++ b/purgatory/arch/arm64/purgatory-arm64.c
> @@ -5,15 +5,30 @@
> #include <stdint.h>
> #include <purgatory.h>
>
> +/* Symbols set by kexec. */
> +
> +uint8_t *arm64_sink __attribute__ ((section ("data")));
> +extern void (*arm64_kernel_entry)(uint64_t, uint64_t, uint64_t, uint64_t);
> +extern uint64_t arm64_dtb_addr;
> +
> void putchar(int ch)
> {
> - /* Nothing for now */
> + if (!arm64_sink)
> + return;
> +
> + *arm64_sink = ch;
> +
> + if (ch == '\n')
> + *arm64_sink = '\r';
> }
>
> void post_verification_setup_arch(void)
> {
> + printf("purgatory: booting kernel now\n");
> }
>
> void setup_arch(void)
> {
> + printf("purgatory: entry=%lx\n", (unsigned long)arm64_kernel_entry);
> + printf("purgatory: dtb=%lx\n", arm64_dtb_addr);
> }
> --
> 2.28.0
Looks good to me, so:
Acked-by: Bhupesh Sharma <bhsharma at redhat.com>
Thanks.
More information about the kexec
mailing list