From 1aa2e89551fbfc1734ed8e42105310034cdaf5cb Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Thu, 3 Aug 2023 09:24:18 -0700 Subject: [PATCH 1/2] Refactor process_args to return the argv index instead of the value This makes it possible for a follow-up commit to add logic that allows loading more than one ELF file (e.g. M-mode firmware and S-mode kernel). --- c_emulator/riscv_sim.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/c_emulator/riscv_sim.c b/c_emulator/riscv_sim.c index fdb9ce01d..8c78dbe58 100644 --- a/c_emulator/riscv_sim.c +++ b/c_emulator/riscv_sim.c @@ -217,7 +217,11 @@ static void read_dtb(const char *path) fprintf(stdout, "Read %zd bytes of DTB from %s.\n", dtb_len, path); } -char *process_args(int argc, char **argv) +/** + * Parses the command line arguments and returns the argv index for the ELF file + * that should be loaded. + */ +static int process_args(int argc, char **argv) { int c; uint64_t ram_size = 0; @@ -375,7 +379,7 @@ char *process_args(int argc, char **argv) if (!rvfi_dii) #endif fprintf(stdout, "Running file %s.\n", argv[optind]); - return argv[optind]; + return optind; } void check_elf(bool is32bit) @@ -1022,7 +1026,8 @@ int main(int argc, char **argv) // Initialize model so that we can check or report its architecture. preinit_sail(); - char *file = process_args(argc, argv); + int files_start = process_args(argc, argv); + char *file = argv[files_start]; init_logs(); if (gettimeofday(&init_start, NULL) < 0) { From f6b8ef8cff3612f99a00b6775827ba671eca9f67 Mon Sep 17 00:00:00 2001 From: Alex Richardson Date: Thu, 3 Aug 2023 09:35:03 -0700 Subject: [PATCH 2/2] Allow loading more than one ELF binary This makes it easier to use a separate M-mode bootloader and kernel payload (e.g. OpenSBI fw_jump). It also makes it easier to test booting systems such as FreeBSD without bundling the kernel with the bootloader. --- c_emulator/riscv_sim.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/c_emulator/riscv_sim.c b/c_emulator/riscv_sim.c index 8c78dbe58..2e2748382 100644 --- a/c_emulator/riscv_sim.c +++ b/c_emulator/riscv_sim.c @@ -142,12 +142,9 @@ static struct option options[] = { static void print_usage(const char *argv0, int ec) { + fprintf(stdout, "Usage: %s [options] [ ...]\n", argv0); #ifdef RVFI_DII - fprintf(stdout, - "Usage: %s [options] \n %s [options] -r \n", - argv0, argv0); -#else - fprintf(stdout, "Usage: %s [options] \n", argv0); + fprintf(stdout, " %s [options] -r \n", argv0); #endif struct option *opt = options; while (opt->name) { @@ -218,8 +215,11 @@ static void read_dtb(const char *path) } /** - * Parses the command line arguments and returns the argv index for the ELF file - * that should be loaded. + * Parses the command line arguments and returns the argv index for the first + * ELF file that should be loaded. As getopt transforms the argv array, all + * argv values following that index are non-options and can be treated as + * additional ELF files that should be loaded into memory (but not scanned + * for the magic tohost/{begin,end}_signature symbols). */ static int process_args(int argc, char **argv) { @@ -398,13 +398,17 @@ void check_elf(bool is32bit) } } } -uint64_t load_sail(char *f) +uint64_t load_sail(char *f, bool main_file) { bool is32bit; uint64_t entry; uint64_t begin_sig, end_sig; load_elf(f, &is32bit, &entry); check_elf(is32bit); + if (!main_file) { + /* Don't scan for test-signature/htif symbols for additional ELF files. */ + return entry; + } fprintf(stdout, "ELF Entry @ 0x%" PRIx64 "\n", entry); /* locate htif ports */ if (lookup_sym(f, "tohost", &rv_htif_tohost) < 0) { @@ -1027,7 +1031,7 @@ int main(int argc, char **argv) preinit_sail(); int files_start = process_args(argc, argv); - char *file = argv[files_start]; + char *initial_elf_file = argv[files_start]; init_logs(); if (gettimeofday(&init_start, NULL) < 0) { @@ -1093,15 +1097,20 @@ int main(int argc, char **argv) } printf("Connected\n"); } else - entry = load_sail(file); + entry = load_sail(initial_elf_file, /*main_file=*/true); #else - uint64_t entry = load_sail(file); + uint64_t entry = load_sail(initial_elf_file, /*main_file=*/true); #endif + /* Load any additional ELF files into memory */ + for (int i = files_start + 1; i < argc; i++) { + fprintf(stdout, "Loading additional ELF file %s.\n", argv[i]); + (void)load_sail(argv[i], /*main_file=*/false); + } /* initialize spike before sail so that we can access the device-tree blob, * until we roll our own. */ - init_spike(file, entry, rv_ram_size); + init_spike(initial_elf_file, entry, rv_ram_size); init_sail(entry); if (!init_check(s))