Merge branch 'riscv/queue' into 'master'
riscv: Add EFI support and SBI base ext tests
See merge request kvm-unit-tests/kvm-unit-tests!54
diff --git a/configure b/configure
index 51edee8..49f047c 100755
--- a/configure
+++ b/configure
@@ -94,8 +94,9 @@
--[enable|disable]-efi-direct
Select whether to run EFI tests directly with QEMU's -kernel
option. When not enabled, tests will be placed in an EFI file
- system and run from the UEFI shell. Ignored when efi isn't enabled.
- (arm64 only)
+ system and run from the UEFI shell. Ignored when efi isn't enabled
+ and defaults to enabled when efi is enabled for riscv64.
+ (arm64 and riscv64 only)
EOF
exit 1
}
@@ -231,11 +232,16 @@
fi
fi
-if [ "$efi" ] && [ "$arch" != "x86_64" ] && [ "$arch" != "arm64" ]; then
+if [ "$efi" ] && [ "$arch" != "x86_64" ] &&
+ [ "$arch" != "arm64" ] && [ "$arch" != "riscv64" ]; then
echo "--[enable|disable]-efi is not supported for $arch"
usage
fi
+if [ "$efi" ] && [ "$arch" = "riscv64" ] && [ -z "$efi_direct" ]; then
+ efi_direct=y
+fi
+
if [ -z "$page_size" ]; then
if [ "$efi" = 'y' ] && [ "$arch" = "arm64" ]; then
page_size="4096"
diff --git a/lib/arm/stack.c b/lib/arm/stack.c
index 7d081be..66d18b4 100644
--- a/lib/arm/stack.c
+++ b/lib/arm/stack.c
@@ -8,13 +8,16 @@
#include <libcflat.h>
#include <stack.h>
-int backtrace_frame(const void *frame, const void **return_addrs,
- int max_depth)
+int arch_backtrace_frame(const void *frame, const void **return_addrs,
+ int max_depth, bool current_frame)
{
static int walking;
int depth;
const unsigned long *fp = (unsigned long *)frame;
+ if (current_frame)
+ fp = __builtin_frame_address(0);
+
if (walking) {
printf("RECURSIVE STACK WALK!!!\n");
return 0;
@@ -33,9 +36,3 @@
walking = 0;
return depth;
}
-
-int backtrace(const void **return_addrs, int max_depth)
-{
- return backtrace_frame(__builtin_frame_address(0),
- return_addrs, max_depth);
-}
diff --git a/lib/arm64/stack.c b/lib/arm64/stack.c
index 82611f4..f5eb57f 100644
--- a/lib/arm64/stack.c
+++ b/lib/arm64/stack.c
@@ -8,7 +8,8 @@
extern char vector_stub_start, vector_stub_end;
-int backtrace_frame(const void *frame, const void **return_addrs, int max_depth)
+int arch_backtrace_frame(const void *frame, const void **return_addrs,
+ int max_depth, bool current_frame)
{
const void *fp = frame;
static bool walking;
@@ -17,6 +18,9 @@
bool is_exception = false;
unsigned long addr;
+ if (current_frame)
+ fp = __builtin_frame_address(0);
+
if (walking) {
printf("RECURSIVE STACK WALK!!!\n");
return 0;
@@ -54,9 +58,3 @@
walking = false;
return depth;
}
-
-int backtrace(const void **return_addrs, int max_depth)
-{
- return backtrace_frame(__builtin_frame_address(0),
- return_addrs, max_depth);
-}
diff --git a/lib/efi.c b/lib/efi.c
index 12c66c6..5314eaa 100644
--- a/lib/efi.c
+++ b/lib/efi.c
@@ -29,6 +29,31 @@
efi_system_table_t *efi_system_table = NULL;
+#ifdef __riscv
+#define RISCV_EFI_BOOT_PROTOCOL_GUID EFI_GUID(0xccd15fec, 0x6f73, 0x4eec, 0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf)
+
+unsigned long boot_hartid;
+
+struct riscv_efi_boot_protocol {
+ u64 revision;
+ efi_status_t (*get_boot_hartid)(struct riscv_efi_boot_protocol *,
+ unsigned long *boot_hartid);
+};
+
+static efi_status_t efi_get_boot_hartid(void)
+{
+ efi_guid_t boot_protocol_guid = RISCV_EFI_BOOT_PROTOCOL_GUID;
+ struct riscv_efi_boot_protocol *boot_protocol;
+ efi_status_t status;
+
+ status = efi_bs_call(locate_protocol, &boot_protocol_guid, NULL,
+ (void **)&boot_protocol);
+ if (status != EFI_SUCCESS)
+ return status;
+ return efi_call_proto(boot_protocol, get_boot_hartid, &boot_hartid);
+}
+#endif
+
static void efi_free_pool(void *ptr)
{
efi_bs_call(free_pool, ptr);
@@ -421,6 +446,14 @@
goto efi_main_error;
}
+#ifdef __riscv
+ status = efi_get_boot_hartid();
+ if (status != EFI_SUCCESS) {
+ printf("Failed to get boot haritd\n");
+ goto efi_main_error;
+ }
+#endif
+
/*
* Exit EFI boot services, let kvm-unit-tests take full control of the
* guest
diff --git a/lib/elf.h b/lib/elf.h
index 7a7db57..fee2028 100644
--- a/lib/elf.h
+++ b/lib/elf.h
@@ -65,4 +65,9 @@
/* The following are used with relocations */
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
+/*
+ * riscv static relocation types.
+ */
+#define R_RISCV_RELATIVE 3
+
#endif /* _ELF_H_ */
diff --git a/lib/riscv/asm/setup.h b/lib/riscv/asm/setup.h
index e58dd53..7f81a70 100644
--- a/lib/riscv/asm/setup.h
+++ b/lib/riscv/asm/setup.h
@@ -12,4 +12,9 @@
void io_init(void);
void setup(const void *fdt, phys_addr_t freemem_start);
+#ifdef CONFIG_EFI
+#include <efi.h>
+efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo);
+#endif
+
#endif /* _ASMRISCV_SETUP_H_ */
diff --git a/lib/riscv/processor.c b/lib/riscv/processor.c
index e090420..ece7cbf 100644
--- a/lib/riscv/processor.c
+++ b/lib/riscv/processor.c
@@ -8,20 +8,20 @@
#include <asm/processor.h>
#include <asm/setup.h>
-extern unsigned long _text;
+extern unsigned long ImageBase;
void show_regs(struct pt_regs *regs)
{
struct thread_info *info = current_thread_info();
- uintptr_t text = (uintptr_t)&_text;
+ uintptr_t loadaddr = (uintptr_t)&ImageBase;
unsigned int w = __riscv_xlen / 4;
- printf("Load address: %" PRIxPTR "\n", text);
+ printf("Load address: %" PRIxPTR "\n", loadaddr);
printf("CPU%3d : hartid=%lx\n", info->cpu, info->hartid);
printf("status : %.*lx\n", w, regs->status);
printf("cause : %.*lx\n", w, regs->cause);
printf("badaddr: %.*lx\n", w, regs->badaddr);
- printf("pc: %.*lx ra: %.*lx\n", w, regs->epc, w, regs->ra);
+ printf("pc: %.*lx (%lx) ra: %.*lx (%lx)\n", w, regs->epc, regs->epc - loadaddr, w, regs->ra, regs->ra - loadaddr);
printf("sp: %.*lx gp: %.*lx tp : %.*lx\n", w, regs->sp, w, regs->gp, w, regs->tp);
printf("a0: %.*lx a1: %.*lx a2 : %.*lx a3 : %.*lx\n", w, regs->a0, w, regs->a1, w, regs->a2, w, regs->a3);
printf("a4: %.*lx a5: %.*lx a6 : %.*lx a7 : %.*lx\n", w, regs->a4, w, regs->a5, w, regs->a6, w, regs->a7);
@@ -43,7 +43,8 @@
}
show_regs(regs);
- assert(0);
+ dump_frame_stack((void *)regs->epc, (void *)regs->s0);
+ abort();
}
void install_exception_handler(unsigned long cause, void (*handler)(struct pt_regs *))
diff --git a/lib/riscv/setup.c b/lib/riscv/setup.c
index 40ff26a..50ffb0d 100644
--- a/lib/riscv/setup.c
+++ b/lib/riscv/setup.c
@@ -31,6 +31,8 @@
#define MAX_DT_MEM_REGIONS 16
#define NR_MEM_REGIONS (MAX_DT_MEM_REGIONS + 16)
+extern unsigned long _etext;
+
char *initrd;
u32 initrd_size;
@@ -81,25 +83,12 @@
cpu0_calls_idle = true;
}
-extern unsigned long _etext;
-
-static void mem_init(phys_addr_t freemem_start)
+static void mem_allocator_init(phys_addr_t freemem_start, phys_addr_t freemem_end)
{
- struct mem_region *freemem, *code, *data;
- phys_addr_t freemem_end, base, top;
+ phys_addr_t base, top;
- memregions_init(riscv_mem_regions, NR_MEM_REGIONS);
- memregions_add_dt_regions(MAX_DT_MEM_REGIONS);
-
- /* Split the region with the code into two regions; code and data */
- memregions_split((unsigned long)&_etext, &code, &data);
- assert(code);
- code->flags |= MR_F_CODE;
-
- freemem = memregions_find(freemem_start);
- assert(freemem && !(freemem->flags & (MR_F_IO | MR_F_CODE)));
-
- freemem_end = freemem->end & PAGE_MASK;
+ freemem_start = PAGE_ALIGN(freemem_start);
+ freemem_end &= PAGE_MASK;
/*
* The assert below is mostly checking that the free memory doesn't
@@ -129,6 +118,64 @@
page_alloc_ops_enable();
}
+static void mem_init(phys_addr_t freemem_start)
+{
+ struct mem_region *freemem, *code, *data;
+
+ memregions_init(riscv_mem_regions, NR_MEM_REGIONS);
+ memregions_add_dt_regions(MAX_DT_MEM_REGIONS);
+
+ /* Split the region with the code into two regions; code and data */
+ memregions_split((unsigned long)&_etext, &code, &data);
+ assert(code);
+ code->flags |= MR_F_CODE;
+
+ freemem = memregions_find(freemem_start);
+ assert(freemem && !(freemem->flags & (MR_F_IO | MR_F_CODE)));
+
+ mem_allocator_init(freemem_start, freemem->end);
+}
+
+static void freemem_push_fdt(void **freemem, const void *fdt)
+{
+ u32 fdt_size;
+ int ret;
+
+ fdt_size = fdt_totalsize(fdt);
+ ret = fdt_move(fdt, *freemem, fdt_size);
+ assert(ret == 0);
+ ret = dt_init(*freemem);
+ assert(ret == 0);
+ *freemem += fdt_size;
+}
+
+static void freemem_push_dt_initrd(void **freemem)
+{
+ const char *tmp;
+ int ret;
+
+ ret = dt_get_initrd(&tmp, &initrd_size);
+ assert(ret == 0 || ret == -FDT_ERR_NOTFOUND);
+ if (ret == 0) {
+ initrd = *freemem;
+ memmove(initrd, tmp, initrd_size);
+ *freemem += initrd_size;
+ }
+}
+
+static void initrd_setup(void)
+{
+ char *env;
+
+ if (!initrd)
+ return;
+
+ /* environ is currently the only file in the initrd */
+ env = malloc(initrd_size);
+ memcpy(env, initrd, initrd_size);
+ setup_env(env, initrd_size);
+}
+
static void banner(void)
{
puts("\n");
@@ -141,29 +188,14 @@
void setup(const void *fdt, phys_addr_t freemem_start)
{
void *freemem;
- const char *bootargs, *tmp;
- u32 fdt_size;
+ const char *bootargs;
int ret;
assert(sizeof(long) == 8 || freemem_start < VA_BASE);
freemem = __va(freemem_start);
- /* Move the FDT to the base of free memory */
- fdt_size = fdt_totalsize(fdt);
- ret = fdt_move(fdt, freemem, fdt_size);
- assert(ret == 0);
- ret = dt_init(freemem);
- assert(ret == 0);
- freemem += fdt_size;
-
- /* Move the initrd to the top of the FDT */
- ret = dt_get_initrd(&tmp, &initrd_size);
- assert(ret == 0 || ret == -FDT_ERR_NOTFOUND);
- if (ret == 0) {
- initrd = freemem;
- memmove(initrd, tmp, initrd_size);
- freemem += initrd_size;
- }
+ freemem_push_fdt(&freemem, fdt);
+ freemem_push_dt_initrd(&freemem);
mem_init(PAGE_ALIGN(__pa(freemem)));
cpu_init();
@@ -174,15 +206,73 @@
assert(ret == 0 || ret == -FDT_ERR_NOTFOUND);
setup_args_progname(bootargs);
- if (initrd) {
- /* environ is currently the only file in the initrd */
- char *env = malloc(initrd_size);
- memcpy(env, initrd, initrd_size);
- setup_env(env, initrd_size);
- }
+ initrd_setup();
if (!(auxinfo.flags & AUXINFO_MMU_OFF))
setup_vm();
banner();
}
+
+#ifdef CONFIG_EFI
+#include <efi.h>
+
+extern unsigned long exception_vectors;
+extern unsigned long boot_hartid;
+
+static efi_status_t efi_mem_init(efi_bootinfo_t *efi_bootinfo)
+{
+ struct mem_region *freemem_mr = NULL, *code, *data;
+ void *freemem;
+
+ memregions_init(riscv_mem_regions, NR_MEM_REGIONS);
+
+ memregions_efi_init(&efi_bootinfo->mem_map, &freemem_mr);
+ if (!freemem_mr)
+ return EFI_OUT_OF_RESOURCES;
+
+ memregions_split((unsigned long)&_etext, &code, &data);
+ assert(code && (code->flags & MR_F_CODE));
+ if (data)
+ data->flags &= ~MR_F_CODE;
+
+ for (struct mem_region *m = mem_regions; m->end; ++m)
+ assert(m == code || !(m->flags & MR_F_CODE));
+
+ freemem = (void *)PAGE_ALIGN(freemem_mr->start);
+
+ if (efi_bootinfo->fdt)
+ freemem_push_fdt(&freemem, efi_bootinfo->fdt);
+
+ mmu_disable();
+ mem_allocator_init((unsigned long)freemem, freemem_mr->end);
+
+ return EFI_SUCCESS;
+}
+
+efi_status_t setup_efi(efi_bootinfo_t *efi_bootinfo)
+{
+ efi_status_t status;
+
+ csr_write(CSR_STVEC, (unsigned long)&exception_vectors);
+ csr_write(CSR_SSCRATCH, boot_hartid);
+
+ status = efi_mem_init(efi_bootinfo);
+ if (status != EFI_SUCCESS) {
+ printf("Failed to initialize memory\n");
+ return status;
+ }
+
+ cpu_init();
+ thread_info_init();
+ io_init();
+ initrd_setup();
+
+ if (!(auxinfo.flags & AUXINFO_MMU_OFF))
+ setup_vm();
+
+ banner();
+
+ return EFI_SUCCESS;
+}
+#endif /* CONFIG_EFI */
diff --git a/lib/riscv/stack.c b/lib/riscv/stack.c
index 712a547..2cd7f01 100644
--- a/lib/riscv/stack.c
+++ b/lib/riscv/stack.c
@@ -2,12 +2,34 @@
#include <libcflat.h>
#include <stack.h>
-int backtrace_frame(const void *frame, const void **return_addrs, int max_depth)
+#ifdef CONFIG_RELOC
+extern char ImageBase, _text, _etext;
+
+bool arch_base_address(const void *rebased_addr, unsigned long *addr)
+{
+ unsigned long ra = (unsigned long)rebased_addr;
+ unsigned long base = (unsigned long)&ImageBase;
+ unsigned long start = (unsigned long)&_text;
+ unsigned long end = (unsigned long)&_etext;
+
+ if (ra < start || ra >= end)
+ return false;
+
+ *addr = ra - base;
+ return true;
+}
+#endif
+
+int arch_backtrace_frame(const void *frame, const void **return_addrs,
+ int max_depth, bool current_frame)
{
static bool walking;
const unsigned long *fp = (unsigned long *)frame;
int depth;
+ if (current_frame)
+ fp = __builtin_frame_address(0);
+
if (walking) {
printf("RECURSIVE STACK WALK!!!\n");
return 0;
@@ -24,9 +46,3 @@
walking = false;
return depth;
}
-
-int backtrace(const void **return_addrs, int max_depth)
-{
- return backtrace_frame(__builtin_frame_address(0),
- return_addrs, max_depth);
-}
diff --git a/lib/s390x/stack.c b/lib/s390x/stack.c
index 9f234a1..d194f65 100644
--- a/lib/s390x/stack.c
+++ b/lib/s390x/stack.c
@@ -14,11 +14,15 @@
#include <stack.h>
#include <asm/arch_def.h>
-int backtrace_frame(const void *frame, const void **return_addrs, int max_depth)
+int arch_backtrace_frame(const void *frame, const void **return_addrs,
+ int max_depth, bool current_frame)
{
int depth = 0;
struct stack_frame *stack = (struct stack_frame *)frame;
+ if (current_frame)
+ stack = __builtin_frame_address(0);
+
for (depth = 0; stack && depth < max_depth; depth++) {
return_addrs[depth] = (void *)stack->grs[8];
stack = stack->back_chain;
@@ -28,9 +32,3 @@
return depth;
}
-
-int backtrace(const void **return_addrs, int max_depth)
-{
- return backtrace_frame(__builtin_frame_address(0),
- return_addrs, max_depth);
-}
diff --git a/lib/stack.c b/lib/stack.c
index dd6bfa8..086fec5 100644
--- a/lib/stack.c
+++ b/lib/stack.c
@@ -14,7 +14,7 @@
#ifdef CONFIG_RELOC
extern char _text, _etext;
-static bool base_address(const void *rebased_addr, unsigned long *addr)
+bool __attribute__((weak)) arch_base_address(const void *rebased_addr, unsigned long *addr)
{
unsigned long ra = (unsigned long)rebased_addr;
unsigned long start = (unsigned long)&_text;
@@ -27,7 +27,7 @@
return true;
}
#else
-static bool base_address(const void *rebased_addr, unsigned long *addr)
+bool __attribute__((weak)) arch_base_address(const void *rebased_addr, unsigned long *addr)
{
*addr = (unsigned long)rebased_addr;
return true;
@@ -45,13 +45,13 @@
/* @addr indicates a non-return address, as expected by the stack
* pretty printer script. */
if (depth > 0 && !top_is_return_address) {
- if (base_address(return_addrs[0], &addr))
+ if (arch_base_address(return_addrs[0], &addr))
printf(" @%lx", addr);
i++;
}
for (; i < depth; i++) {
- if (base_address(return_addrs[i], &addr))
+ if (arch_base_address(return_addrs[i], &addr))
printf(" %lx", addr);
}
printf("\n");
diff --git a/lib/stack.h b/lib/stack.h
index 10fc2f7..df076d9 100644
--- a/lib/stack.h
+++ b/lib/stack.h
@@ -11,17 +11,29 @@
#include <asm/stack.h>
#ifdef HAVE_ARCH_BACKTRACE_FRAME
-extern int backtrace_frame(const void *frame, const void **return_addrs,
- int max_depth);
+extern int arch_backtrace_frame(const void *frame, const void **return_addrs,
+ int max_depth, bool current_frame);
+
+static inline int backtrace_frame(const void *frame, const void **return_addrs,
+ int max_depth)
+{
+ return arch_backtrace_frame(frame, return_addrs, max_depth, false);
+}
+
+static inline int backtrace(const void **return_addrs, int max_depth)
+{
+ return arch_backtrace_frame(NULL, return_addrs, max_depth, true);
+}
#else
-static inline int
-backtrace_frame(const void *frame __unused, const void **return_addrs __unused,
- int max_depth __unused)
+extern int backtrace(const void **return_addrs, int max_depth);
+
+static inline int backtrace_frame(const void *frame, const void **return_addrs,
+ int max_depth)
{
return 0;
}
#endif
-extern int backtrace(const void **return_addrs, int max_depth);
+bool __attribute__((weak)) arch_base_address(const void *rebased_addr, unsigned long *addr);
#endif
diff --git a/lib/x86/stack.c b/lib/x86/stack.c
index 5ecd97c..58ab6c4 100644
--- a/lib/x86/stack.c
+++ b/lib/x86/stack.c
@@ -1,12 +1,16 @@
#include <libcflat.h>
#include <stack.h>
-int backtrace_frame(const void *frame, const void **return_addrs, int max_depth)
+int arch_backtrace_frame(const void *frame, const void **return_addrs,
+ int max_depth, bool current_frame)
{
static int walking;
int depth = 0;
const unsigned long *bp = (unsigned long *) frame;
+ if (current_frame)
+ bp = __builtin_frame_address(0);
+
if (walking) {
printf("RECURSIVE STACK WALK!!!\n");
return 0;
@@ -23,9 +27,3 @@
walking = 0;
return depth;
}
-
-int backtrace(const void **return_addrs, int max_depth)
-{
- return backtrace_frame(__builtin_frame_address(0), return_addrs,
- max_depth);
-}
diff --git a/riscv/Makefile b/riscv/Makefile
index 85bbca1..919a3eb 100644
--- a/riscv/Makefile
+++ b/riscv/Makefile
@@ -17,7 +17,8 @@
all: $(tests)
-$(TEST_DIR)/sieve.elf: AUXFLAGS = 0x1
+# When built for EFI sieve needs extra memory, run with e.g. '-m 256' on QEMU
+$(TEST_DIR)/sieve.$(exe): AUXFLAGS = 0x1
cstart.o = $(TEST_DIR)/cstart.o
@@ -85,7 +86,29 @@
-DPROGNAME=\"$(notdir $(@:.aux.o=.$(exe)))\" -DAUXFLAGS=$(AUXFLAGS)
ifeq ($(CONFIG_EFI),y)
- # TODO
+# avoid jump tables before all relocations have been processed
+riscv/efi/reloc_riscv64.o: CFLAGS += -fno-jump-tables
+cflatobjs += riscv/efi/reloc_riscv64.o
+cflatobjs += lib/acpi.o
+cflatobjs += lib/efi.o
+
+.PRECIOUS: %.so
+
+%.so: EFI_LDFLAGS += -defsym=EFI_SUBSYSTEM=0xa --no-undefined
+%.so: %.o $(FLATLIBS) $(SRCDIR)/riscv/efi/elf_riscv64_efi.lds $(cstart.o) %.aux.o
+ $(LD) $(EFI_LDFLAGS) -o $@ -T $(SRCDIR)/riscv/efi/elf_riscv64_efi.lds \
+ $(filter %.o, $^) $(FLATLIBS) $(EFI_LIBS)
+
+%.efi: %.so
+ $(call arch_elf_check, $^)
+ $(OBJCOPY) --only-keep-debug $^ $@.debug
+ $(OBJCOPY) --strip-debug $^
+ $(OBJCOPY) --add-gnu-debuglink=$@.debug $^
+ $(OBJCOPY) \
+ -j .text -j .sdata -j .data -j .rodata -j .dynamic -j .dynsym \
+ -j .rel -j .rela -j .rel.* -j .rela.* -j .rel* -j .rela* \
+ -j .reloc \
+ -O binary $^ $@
else
%.elf: LDFLAGS += -pie -n -z notext
%.elf: %.o $(FLATLIBS) $(SRCDIR)/riscv/flat.lds $(cstart.o) %.aux.o
diff --git a/riscv/cstart.S b/riscv/cstart.S
index c935467..10b5da5 100644
--- a/riscv/cstart.S
+++ b/riscv/cstart.S
@@ -42,6 +42,9 @@
9997:
.endm
+#ifdef CONFIG_EFI
+#include "efi/crt0-efi-riscv64.S"
+#else
.section .init
/*
@@ -109,6 +112,7 @@
call exit
j halt
+#endif /* !CONFIG_EFI */
.text
.balign 4
diff --git a/riscv/efi/crt0-efi-riscv64.S b/riscv/efi/crt0-efi-riscv64.S
new file mode 100644
index 0000000..4ed82b1
--- /dev/null
+++ b/riscv/efi/crt0-efi-riscv64.S
@@ -0,0 +1,205 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause */
+/*
+ * Copright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
+ * Copright (C) 2018 Alexander Graf <agraf@suse.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice and this list of conditions, without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License as published by the Free Software Foundation;
+ * either version 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef EFI_SUBSYSTEM
+#define EFI_SUBSYSTEM 10
+#endif
+
+ .section .text.head
+
+ /*
+ * Magic "MZ" signature for PE/COFF
+ */
+ .globl ImageBase
+ImageBase:
+ .ascii "MZ"
+ .skip 58 // 'MZ' + pad + offset == 64
+ .4byte pe_header - ImageBase // Offset to the PE header.
+pe_header:
+ .ascii "PE"
+ .2byte 0
+coff_header:
+ .2byte 0x5064 // riscv64
+ .2byte 4 // nr_sections
+ .4byte 0 // TimeDateStamp
+ .4byte 0 // PointerToSymbolTable
+ .4byte 0 // NumberOfSymbols
+ .2byte section_table - optional_header // SizeOfOptionalHeader
+ .2byte 0x206 // Characteristics.
+ // IMAGE_FILE_DEBUG_STRIPPED |
+ // IMAGE_FILE_EXECUTABLE_IMAGE |
+ // IMAGE_FILE_LINE_NUMS_STRIPPED
+optional_header:
+ .2byte 0x20b // PE32+ format
+ .byte 0x02 // MajorLinkerVersion
+ .byte 0x14 // MinorLinkerVersion
+ .4byte _text_size - ImageBase // SizeOfCode
+ .4byte _alldata_size - ImageBase // SizeOfInitializedData
+ .4byte 0 // SizeOfUninitializedData
+ .4byte _start - ImageBase // AddressOfEntryPoint
+ .4byte _text - ImageBase // BaseOfCode
+
+extra_header_fields:
+ .8byte 0 // ImageBase
+ .4byte 0x1000 // SectionAlignment
+ .4byte 0x1000 // FileAlignment
+ .2byte 0 // MajorOperatingSystemVersion
+ .2byte 0 // MinorOperatingSystemVersion
+ .2byte 0 // MajorImageVersion
+ .2byte 0 // MinorImageVersion
+ .2byte 0 // MajorSubsystemVersion
+ .2byte 0 // MinorSubsystemVersion
+ .4byte 0 // Win32VersionValue
+
+ .4byte _image_end - ImageBase // SizeOfImage
+
+ // Everything before the kernel image is considered part of the header
+ .4byte _text - ImageBase // SizeOfHeaders
+ .4byte 0 // CheckSum
+ .2byte EFI_SUBSYSTEM // Subsystem
+ .2byte 0 // DllCharacteristics
+ .8byte 0 // SizeOfStackReserve
+ .8byte 0 // SizeOfStackCommit
+ .8byte 0 // SizeOfHeapReserve
+ .8byte 0 // SizeOfHeapCommit
+ .4byte 0 // LoaderFlags
+ .4byte 0x10 // NumberOfRvaAndSizes
+
+ .8byte 0 // ExportTable
+ .8byte 0 // ImportTable
+ .8byte 0 // ResourceTable
+ .8byte 0 // ExceptionTable
+ .8byte 0 // CertificationTable
+ .4byte _reloc - ImageBase // BaseRelocationTable (VirtualAddress)
+ .4byte _reloc_vsize - ImageBase // BaseRelocationTable (Size)
+ .8byte 0 // Debug
+ .8byte 0 // Architecture
+ .8byte 0 // Global Ptr
+ .8byte 0 // TLS Table
+ .8byte 0 // Load Config Table
+ .8byte 0 // Bound Import
+ .8byte 0 // IAT
+ .8byte 0 // Delay Import Descriptor
+ .8byte 0 // CLR Runtime Header
+ .8byte 0 // Reserved, must be zero
+
+ // Section table
+section_table:
+
+ .ascii ".text\0\0\0"
+ .4byte _text_vsize - ImageBase // VirtualSize
+ .4byte _text - ImageBase // VirtualAddress
+ .4byte _text_size - ImageBase // SizeOfRawData
+ .4byte _text - ImageBase // PointerToRawData
+ .4byte 0 // PointerToRelocations (0 for executables)
+ .4byte 0 // PointerToLineNumbers (0 for executables)
+ .2byte 0 // NumberOfRelocations (0 for executables)
+ .2byte 0 // NumberOfLineNumbers (0 for executables)
+ .4byte 0x60000020 // Characteristics (section flags)
+
+ /*
+ * The EFI application loader requires a relocation section
+ * because EFI applications must be relocatable. This is a
+ * dummy section as far as we are concerned.
+ */
+ .ascii ".reloc\0\0"
+ .4byte _reloc_vsize - ImageBase // VirtualSize
+ .4byte _reloc - ImageBase // VirtualAddress
+ .4byte _reloc_size - ImageBase // SizeOfRawData
+ .4byte _reloc - ImageBase // PointerToRawData
+ .4byte 0 // PointerToRelocations
+ .4byte 0 // PointerToLineNumbers
+ .2byte 0 // NumberOfRelocations
+ .2byte 0 // NumberOfLineNumbers
+ .4byte 0x42000040 // Characteristics (section flags)
+
+ .ascii ".data\0\0\0"
+ .4byte _data_vsize - ImageBase // VirtualSize
+ .4byte _data - ImageBase // VirtualAddress
+ .4byte _data_size - ImageBase // SizeOfRawData
+ .4byte _data - ImageBase // PointerToRawData
+ .4byte 0 // PointerToRelocations
+ .4byte 0 // PointerToLineNumbers
+ .2byte 0 // NumberOfRelocations
+ .2byte 0 // NumberOfLineNumbers
+ .4byte 0xC0000040 // Characteristics (section flags)
+
+ .ascii ".rodata\0"
+ .4byte _rodata_vsize - ImageBase // VirtualSize
+ .4byte _rodata - ImageBase // VirtualAddress
+ .4byte _rodata_size - ImageBase // SizeOfRawData
+ .4byte _rodata - ImageBase // PointerToRawData
+ .4byte 0 // PointerToRelocations
+ .4byte 0 // PointerToLineNumbers
+ .2byte 0 // NumberOfRelocations
+ .2byte 0 // NumberOfLineNumbers
+ .4byte 0x40000040 // Characteristics (section flags)
+
+ .text
+ .globl _start
+ .type _start,%function
+_start:
+ addi sp, sp, -24
+ sd a0, 0(sp)
+ sd a1, 8(sp)
+ sd ra, 16(sp)
+ lla a0, ImageBase
+ lla a1, _DYNAMIC
+ call _relocate
+ bne a0, zero, 0f
+ ld a1, 8(sp)
+ ld a0, 0(sp)
+
+ /* Switch to our own stack */
+ mv a2, sp
+ la sp, stacktop
+ mv fp, zero
+ push_fp zero
+ addi sp, sp, -16
+ sd a2, 0(sp)
+
+ call efi_main
+
+ /* Restore sp */
+ ld sp, 0(sp)
+
+ ld ra, 16(sp)
+0: addi sp, sp, 24
+ ret
+
+// hand-craft a dummy .reloc section so EFI knows it's a relocatable executable:
+
+ .data
+
+.balign 16384
+.space 16384
+stacktop:
+
+dummy: .4byte 0
+
+#define IMAGE_REL_ABSOLUTE 0
+ .section .reloc, "a"
+label1:
+ .4byte dummy-label1 // Page RVA
+ .4byte 12 // Block Size (2*4+2*2), must be aligned by 32 Bits
+ .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy
+ .2byte (IMAGE_REL_ABSOLUTE<<12) + 0 // reloc for dummy
+
+#if defined(__ELF__) && defined(__linux__)
+ .section .note.GNU-stack,"",%progbits
+#endif
diff --git a/riscv/efi/elf_riscv64_efi.lds b/riscv/efi/elf_riscv64_efi.lds
new file mode 100644
index 0000000..ac7055a
--- /dev/null
+++ b/riscv/efi/elf_riscv64_efi.lds
@@ -0,0 +1,142 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-2-Clause */
+
+OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv")
+OUTPUT_ARCH(riscv)
+ENTRY(_start)
+SECTIONS
+{
+ .text 0 : {
+ *(.text.head)
+ . = ALIGN(4096);
+ _text = .;
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t.*)
+ *(.plt)
+ . = ALIGN(16);
+ _evtext = .;
+ . = ALIGN(4096);
+ _etext = .;
+ } =0
+ _text_vsize = _evtext - _text;
+ _text_size = _etext - _text;
+ . = ALIGN(4096);
+ _reloc = .;
+ .reloc : {
+ *(.reloc)
+ _evreloc = .;
+ . = ALIGN(4096);
+ _ereloc = .;
+ } =0
+ _reloc_vsize = _evreloc - _reloc;
+ _reloc_size = _ereloc - _reloc;
+ . = ALIGN(4096);
+ _data = .;
+ .dynamic : { *(.dynamic) }
+ . = ALIGN(4096);
+ .data :
+ {
+ *(.sdata)
+ *(.data)
+ *(.data1)
+ *(.data.*)
+ *(.got.plt)
+ *(.got)
+
+ /*
+ * Note that these aren't the using the GNU "CONSTRUCTOR" output section
+ * command, so they don't start with a size. Because of p2align and the
+ * end/END definitions, and the fact that they're mergeable, they can also
+ * have NULLs which aren't guaranteed to be at the end.
+ */
+ . = ALIGN(16);
+ __init_array_start = .;
+ *(SORT(.init_array.*))
+ *(.init_array)
+ __init_array_end = .;
+ . = ALIGN(16);
+ __CTOR_LIST__ = .;
+ *(SORT(.ctors.*))
+ *(.ctors)
+ __CTOR_END__ = .;
+ . = ALIGN(16);
+ __DTOR_LIST__ = .;
+ *(SORT(.dtors.*))
+ *(.dtors)
+ __DTOR_END__ = .;
+ . = ALIGN(16);
+ __fini_array_start = .;
+ *(SORT(.fini_array.*))
+ *(.fini_array)
+ __fini_array_end = .;
+
+ /* the EFI loader doesn't seem to like a .bss section, so we stick
+ it all into .data: */
+ . = ALIGN(16);
+ _bss = .;
+ *(.sbss)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ . = ALIGN(16);
+ _bss_end = .;
+ _evdata = .;
+ . = ALIGN(4096);
+ _edata = .;
+ } =0
+ _data_vsize = _evdata - _data;
+ _data_size = _edata - _data;
+
+ . = ALIGN(4096);
+ _rodata = .;
+ .rela :
+ {
+ *(.rela.text*)
+ *(.rela.data*)
+ *(.rela.got)
+ *(.rela.dyn)
+ *(.rela.stab)
+ *(.rela.init_array*)
+ *(.rela.fini_array*)
+ *(.rela.ctors*)
+ *(.rela.dtors*)
+
+ }
+ . = ALIGN(4096);
+ .rela.plt : { *(.rela.plt) }
+ . = ALIGN(4096);
+ .rodata : {
+ *(.rodata*)
+ _evrodata = .;
+ . = ALIGN(4096);
+ _erodata = .;
+ } =0
+ _rodata_vsize = _evrodata - _rodata;
+ _rodata_size = _erodata - _rodata;
+ _image_end = .;
+ _alldata_size = _image_end - _reloc;
+
+ . = ALIGN(4096);
+ .dynsym : { *(.dynsym) }
+ . = ALIGN(4096);
+ .dynstr : { *(.dynstr) }
+ . = ALIGN(4096);
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ . = ALIGN(4096);
+ .hash : { *(.hash) }
+ . = ALIGN(4096);
+ .gnu.hash : { *(.gnu.hash) }
+ . = ALIGN(4096);
+ .eh_frame : { *(.eh_frame) }
+ . = ALIGN(4096);
+ .gcc_except_table : { *(.gcc_except_table*) }
+ /DISCARD/ :
+ {
+ *(.rela.reloc)
+ *(.note.GNU-stack)
+ }
+ .comment 0 : { *(.comment) }
+}
+
diff --git a/riscv/efi/reloc_riscv64.c b/riscv/efi/reloc_riscv64.c
new file mode 100644
index 0000000..8504ad5
--- /dev/null
+++ b/riscv/efi/reloc_riscv64.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/* reloc_riscv.c - position independent ELF shared object relocator
+ Copyright (C) 2018 Alexander Graf <agraf@suse.de>
+ Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
+ Copyright (C) 1999 Hewlett-Packard Co.
+ Contributed by David Mosberger <davidm@hpl.hp.com>.
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+ * Neither the name of Hewlett-Packard Co. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+*/
+
+#include <efi.h>
+
+#include <elf.h>
+
+#define Elf_Dyn Elf64_Dyn
+#define Elf_Rela Elf64_Rela
+#define ELF_R_TYPE ELF64_R_TYPE
+
+efi_status_t _relocate(long ldbase, Elf64_Dyn *dyn, efi_handle_t handle,
+ efi_system_table_t *sys_tab)
+{
+ long relsz = 0, relent = 0;
+ Elf_Rela *rel = NULL;
+ unsigned long *addr;
+ int i;
+
+ for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
+ switch (dyn[i].d_tag) {
+ case DT_RELA:
+ rel = (Elf_Rela *)((unsigned long)dyn[i].d_un.d_ptr + ldbase);
+ break;
+ case DT_RELASZ:
+ relsz = dyn[i].d_un.d_val;
+ break;
+ case DT_RELAENT:
+ relent = dyn[i].d_un.d_val;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!rel && relent == 0)
+ return EFI_SUCCESS;
+
+ if (!rel || relent == 0)
+ return EFI_LOAD_ERROR;
+
+ while (relsz > 0) {
+ /* apply the relocs */
+ switch (ELF_R_TYPE(rel->r_info)) {
+ case R_RISCV_RELATIVE:
+ addr = (unsigned long *)(ldbase + rel->r_offset);
+ *addr = ldbase + rel->r_addend;
+ break;
+ default:
+ break;
+ }
+ rel = (Elf_Rela *)((char *)rel + relent);
+ relsz -= relent;
+ }
+ return EFI_SUCCESS;
+}
diff --git a/riscv/efi/run b/riscv/efi/run
new file mode 100755
index 0000000..982b8b9
--- /dev/null
+++ b/riscv/efi/run
@@ -0,0 +1,106 @@
+#!/bin/bash
+
+if [ $# -eq 0 ]; then
+ echo "Usage $0 TEST_CASE [QEMU_ARGS]"
+ exit 2
+fi
+
+if [ ! -f config.mak ]; then
+ echo "run './configure --enable-efi && make' first. See ./configure -h"
+ exit 2
+fi
+source config.mak
+source scripts/arch-run.bash
+
+if [ -f RISCV_VIRT_CODE.fd ]; then
+ DEFAULT_UEFI=RISCV_VIRT_CODE.fd
+fi
+
+KERNEL_NAME=$1
+
+: "${EFI_SRC:=$TEST_DIR}"
+: "${EFI_UEFI:=$DEFAULT_UEFI}"
+: "${EFI_TEST:=efi-tests}"
+: "${EFI_CASE:=$(basename $KERNEL_NAME .efi)}"
+: "${EFI_TESTNAME:=$TESTNAME}"
+: "${EFI_TESTNAME:=$EFI_CASE}"
+: "${EFI_CASE_DIR:="$EFI_TEST/$EFI_TESTNAME"}"
+: "${EFI_VAR_GUID:=97ef3e03-7329-4a6a-b9ba-6c1fdcc5f823}"
+
+if [ ! -f "$EFI_UEFI" ]; then
+ echo "UEFI firmware not found."
+ echo "Please specify the path with the env variable EFI_UEFI"
+ exit 2
+fi
+
+if [ "$EFI_USE_ACPI" = "y" ]; then
+ echo "ACPI not available"
+ exit 2
+fi
+
+# Remove the TEST_CASE from $@
+shift 1
+
+# Fish out the arguments for the test, they should be the next string
+# after the "-append" option
+qemu_args=()
+cmd_args=()
+while (( "$#" )); do
+ if [ "$1" = "-append" ]; then
+ cmd_args=$2
+ shift 2
+ else
+ qemu_args+=("$1")
+ shift 1
+ fi
+done
+
+if [ "$EFI_CASE" = "_NO_FILE_4Uhere_" ]; then
+ EFI_CASE_DIR="$EFI_TEST/dummy"
+ mkdir -p "$EFI_CASE_DIR"
+ $TEST_DIR/run \
+ $EFI_CASE \
+ -machine pflash0=pflash0 \
+ -blockdev node-name=pflash0,driver=file,read-only=on,filename="$EFI_UEFI" \
+ -drive file.dir="$EFI_CASE_DIR/",file.driver=vvfat,file.rw=on,format=raw,if=virtio \
+ "${qemu_args[@]}"
+ exit
+fi
+
+uefi_shell_run()
+{
+ mkdir -p "$EFI_CASE_DIR"
+ cp "$EFI_SRC/$EFI_CASE.efi" "$EFI_CASE_DIR/"
+ echo "@echo -off" > "$EFI_CASE_DIR/startup.nsh"
+ if [ "$EFI_USE_ACPI" != "y" ]; then
+ qemu_args+=(-machine acpi=off)
+ FDT_BASENAME="dtb"
+ UEFI_SHELL_RUN=y $TEST_DIR/run \
+ -machine pflash0=pflash0 \
+ -blockdev node-name=pflash0,driver=file,read-only=on,filename="$EFI_UEFI" \
+ -machine dumpdtb="$EFI_CASE_DIR/$FDT_BASENAME" \
+ "${qemu_args[@]}"
+ echo "setvar fdtfile -guid $EFI_VAR_GUID -rt =L\"$FDT_BASENAME\"" >> "$EFI_CASE_DIR/startup.nsh"
+ fi
+ echo "$EFI_CASE.efi" "${cmd_args[@]}" >> "$EFI_CASE_DIR/startup.nsh"
+
+ UEFI_SHELL_RUN=y $TEST_DIR/run \
+ -machine pflash0=pflash0 \
+ -blockdev node-name=pflash0,driver=file,read-only=on,filename="$EFI_UEFI" \
+ -drive file.dir="$EFI_CASE_DIR/",file.driver=vvfat,file.rw=on,format=raw,if=virtio \
+ "${qemu_args[@]}"
+}
+
+if [ "$EFI_DIRECT" = "y" ]; then
+ if [ "$EFI_USE_ACPI" != "y" ]; then
+ qemu_args+=(-machine acpi=off)
+ fi
+ $TEST_DIR/run \
+ $KERNEL_NAME \
+ -append "$(basename $KERNEL_NAME) ${cmd_args[@]}" \
+ -machine pflash0=pflash0 \
+ -blockdev node-name=pflash0,driver=file,read-only=on,filename="$EFI_UEFI" \
+ "${qemu_args[@]}"
+else
+ uefi_shell_run
+fi
diff --git a/riscv/flat.lds b/riscv/flat.lds
index d4853f8..1ca501e 100644
--- a/riscv/flat.lds
+++ b/riscv/flat.lds
@@ -30,6 +30,7 @@
SECTIONS
{
+ PROVIDE(ImageBase = .);
PROVIDE(_text = .);
.text : { *(.init) *(.text) *(.text.*) } :text
. = ALIGN(4K);
diff --git a/riscv/run b/riscv/run
index cbe5dd7..73f2bf5 100755
--- a/riscv/run
+++ b/riscv/run
@@ -33,7 +33,7 @@
command+=" $mach $acc $firmware -cpu $processor "
command="$(migration_cmd) $(timeout_cmd) $command"
-if [ "$EFI_RUN" = "y" ]; then
+if [ "$UEFI_SHELL_RUN" = "y" ]; then
ENVIRON_DEFAULT=n run_qemu_status $command "$@"
else
# We return the exit code via stdout, not via the QEMU return code
diff --git a/riscv/sbi.c b/riscv/sbi.c
index ffb07a2..762e971 100644
--- a/riscv/sbi.c
+++ b/riscv/sbi.c
@@ -14,28 +14,114 @@
puts("An environ must be provided where expected values are given.\n");
}
-int main(int argc, char **argv)
+static struct sbiret __base_sbi_ecall(int fid, unsigned long arg0)
+{
+ return sbi_ecall(SBI_EXT_BASE, fid, arg0, 0, 0, 0, 0, 0);
+}
+
+static bool env_or_skip(const char *env)
+{
+ if (!getenv(env)) {
+ report_skip("missing %s environment variable", env);
+ return false;
+ }
+
+ return true;
+}
+
+static void gen_report(struct sbiret *ret,
+ long expected_error, long expected_value)
+{
+ bool check_error = ret->error == expected_error;
+ bool check_value = ret->value == expected_value;
+
+ if (!check_error || !check_value)
+ report_info("expected (error: %ld, value: %ld), received: (error: %ld, value %ld)",
+ expected_error, expected_value, ret->error, ret->value);
+
+ report(check_error, "expected sbi.error");
+ report(check_value, "expected sbi.value");
+}
+
+static void check_base(void)
{
struct sbiret ret;
long expected;
+ report_prefix_push("base");
+
+ ret = __base_sbi_ecall(SBI_EXT_BASE_GET_SPEC_VERSION, 0);
+ if (ret.error || ret.value < 2) {
+ report_skip("SBI spec version 0.2 or higher required");
+ return;
+ }
+
+ report_prefix_push("spec_version");
+ if (env_or_skip("SPEC_VERSION")) {
+ expected = strtol(getenv("SPEC_VERSION"), NULL, 0);
+ gen_report(&ret, 0, expected);
+ }
+ report_prefix_pop();
+
+ report_prefix_push("impl_id");
+ if (env_or_skip("IMPL_ID")) {
+ expected = strtol(getenv("IMPL_ID"), NULL, 0);
+ ret = __base_sbi_ecall(SBI_EXT_BASE_GET_IMP_ID, 0);
+ gen_report(&ret, 0, expected);
+ }
+ report_prefix_pop();
+
+ report_prefix_push("impl_version");
+ if (env_or_skip("IMPL_VERSION")) {
+ expected = strtol(getenv("IMPL_VERSION"), NULL, 0);
+ ret = __base_sbi_ecall(SBI_EXT_BASE_GET_IMP_VERSION, 0);
+ gen_report(&ret, 0, expected);
+ }
+ report_prefix_pop();
+
+ report_prefix_push("probe_ext");
+ expected = getenv("PROBE_EXT") ? strtol(getenv("PROBE_EXT"), NULL, 0) : 1;
+ ret = __base_sbi_ecall(SBI_EXT_BASE_PROBE_EXT, SBI_EXT_BASE);
+ gen_report(&ret, 0, expected);
+ report_prefix_pop();
+
+ report_prefix_push("mvendorid");
+ if (env_or_skip("MVENDORID")) {
+ expected = strtol(getenv("MVENDORID"), NULL, 0);
+ ret = __base_sbi_ecall(SBI_EXT_BASE_GET_MVENDORID, 0);
+ gen_report(&ret, 0, expected);
+ }
+ report_prefix_pop();
+
+ report_prefix_push("marchid");
+ if (env_or_skip("MARCHID")) {
+ expected = strtol(getenv("MARCHID"), NULL, 0);
+ ret = __base_sbi_ecall(SBI_EXT_BASE_GET_MARCHID, 0);
+ gen_report(&ret, 0, expected);
+ }
+ report_prefix_pop();
+
+ report_prefix_push("mimpid");
+ if (env_or_skip("MIMPID")) {
+ expected = strtol(getenv("MIMPID"), NULL, 0);
+ ret = __base_sbi_ecall(SBI_EXT_BASE_GET_MIMPID, 0);
+ gen_report(&ret, 0, expected);
+ }
+ report_prefix_pop();
+
+ report_prefix_pop();
+}
+
+int main(int argc, char **argv)
+{
+
if (argc > 1 && !strcmp(argv[1], "-h")) {
help();
exit(0);
}
report_prefix_push("sbi");
+ check_base();
- if (!getenv("MVENDORID")) {
- report_skip("mvendorid: missing MVENDORID environment variable");
- goto done;
- }
- expected = strtol(getenv("MVENDORID"), NULL, 0);
-
- ret = sbi_ecall(SBI_EXT_BASE, SBI_EXT_BASE_GET_MVENDORID, 0, 0, 0, 0, 0, 0);
- report(!ret.error, "mvendorid: no error");
- report(ret.value == expected, "mvendorid");
-
-done:
return report_summary();
}