Merge branch 'riscv/sbi' into 'master'
riscv: Add support for SBI tests
See merge request kvm-unit-tests/kvm-unit-tests!67
diff --git a/lib/cpumask.h b/lib/cpumask.h
index be19192..e1e92aa 100644
--- a/lib/cpumask.h
+++ b/lib/cpumask.h
@@ -6,8 +6,9 @@
*/
#ifndef _CPUMASK_H_
#define _CPUMASK_H_
-#include <asm/setup.h>
#include <bitops.h>
+#include <limits.h>
+#include <asm/setup.h>
#define CPUMASK_NR_LONGS ((NR_CPUS + BITS_PER_LONG - 1) / BITS_PER_LONG)
@@ -49,46 +50,34 @@
static inline void cpumask_setall(cpumask_t *mask)
{
- int i;
- for (i = 0; i < nr_cpus; i += BITS_PER_LONG)
- cpumask_bits(mask)[BIT_WORD(i)] = ~0UL;
- i -= BITS_PER_LONG;
- if ((nr_cpus - i) < BITS_PER_LONG)
- cpumask_bits(mask)[BIT_WORD(i)] = BIT_MASK(nr_cpus - i) - 1;
+ memset(mask, 0xff, sizeof(*mask));
}
static inline void cpumask_clear(cpumask_t *mask)
{
- int i;
- for (i = 0; i < nr_cpus; i += BITS_PER_LONG)
- cpumask_bits(mask)[BIT_WORD(i)] = 0UL;
+ memset(mask, 0, sizeof(*mask));
}
static inline bool cpumask_empty(const cpumask_t *mask)
{
- int i;
- for (i = 0; i < nr_cpus; i += BITS_PER_LONG) {
- if (i < NR_CPUS) { /* silence crazy compiler warning */
- if (cpumask_bits(mask)[BIT_WORD(i)] != 0UL)
- return false;
- }
- }
- return true;
+ unsigned long lastmask = BIT_MASK(nr_cpus) - 1;
+
+ for (int i = 0; i < BIT_WORD(nr_cpus); ++i)
+ if (cpumask_bits(mask)[i])
+ return false;
+
+ return !lastmask || !(cpumask_bits(mask)[BIT_WORD(nr_cpus)] & lastmask);
}
static inline bool cpumask_full(const cpumask_t *mask)
{
- int i;
- for (i = 0; i < nr_cpus; i += BITS_PER_LONG) {
- if (cpumask_bits(mask)[BIT_WORD(i)] != ~0UL) {
- if ((nr_cpus - i) >= BITS_PER_LONG)
- return false;
- if (cpumask_bits(mask)[BIT_WORD(i)]
- != BIT_MASK(nr_cpus - i) - 1)
- return false;
- }
- }
- return true;
+ unsigned long lastmask = BIT_MASK(nr_cpus) - 1;
+
+ for (int i = 0; i < BIT_WORD(nr_cpus); ++i)
+ if (cpumask_bits(mask)[i] != ULONG_MAX)
+ return false;
+
+ return !lastmask || (cpumask_bits(mask)[BIT_WORD(nr_cpus)] & lastmask) == lastmask;
}
static inline int cpumask_weight(const cpumask_t *mask)
diff --git a/lib/on-cpus.c b/lib/on-cpus.c
index aed70f7..8921493 100644
--- a/lib/on-cpus.c
+++ b/lib/on-cpus.c
@@ -124,6 +124,43 @@
smp_send_event();
}
+void on_cpumask_async(const cpumask_t *mask, void (*func)(void *data), void *data)
+{
+ int cpu, me = smp_processor_id();
+
+ for_each_cpu(cpu, mask) {
+ if (cpu == me)
+ continue;
+ on_cpu_async(cpu, func, data);
+ }
+ if (cpumask_test_cpu(me, mask))
+ func(data);
+}
+
+void on_cpumask(const cpumask_t *mask, void (*func)(void *data), void *data)
+{
+ int cpu, me = smp_processor_id();
+
+ for_each_cpu(cpu, mask) {
+ if (cpu == me)
+ continue;
+ on_cpu_async(cpu, func, data);
+ }
+ if (cpumask_test_cpu(me, mask))
+ func(data);
+
+ for_each_cpu(cpu, mask) {
+ if (cpu == me)
+ continue;
+ cpumask_set_cpu(me, &on_cpu_info[cpu].waiters);
+ deadlock_check(me, cpu);
+ }
+ while (cpumask_weight(&cpu_idle_mask) < nr_cpus - 1)
+ smp_wait_for_event();
+ for_each_cpu(cpu, mask)
+ cpumask_clear_cpu(me, &on_cpu_info[cpu].waiters);
+}
+
void on_cpu(int cpu, void (*func)(void *data), void *data)
{
on_cpu_async(cpu, func, data);
@@ -132,23 +169,5 @@
void on_cpus(void (*func)(void *data), void *data)
{
- int cpu, me = smp_processor_id();
-
- for_each_present_cpu(cpu) {
- if (cpu == me)
- continue;
- on_cpu_async(cpu, func, data);
- }
- func(data);
-
- for_each_present_cpu(cpu) {
- if (cpu == me)
- continue;
- cpumask_set_cpu(me, &on_cpu_info[cpu].waiters);
- deadlock_check(me, cpu);
- }
- while (cpumask_weight(&cpu_idle_mask) < nr_cpus - 1)
- smp_wait_for_event();
- for_each_present_cpu(cpu)
- cpumask_clear_cpu(me, &on_cpu_info[cpu].waiters);
+ on_cpumask(&cpu_present_mask, func, data);
}
diff --git a/lib/on-cpus.h b/lib/on-cpus.h
index 41103b0..4bc6236 100644
--- a/lib/on-cpus.h
+++ b/lib/on-cpus.h
@@ -2,6 +2,7 @@
#ifndef _ON_CPUS_H_
#define _ON_CPUS_H_
#include <stdbool.h>
+#include <cpumask.h>
extern bool cpu0_calls_idle;
@@ -10,5 +11,7 @@
void on_cpu_async(int cpu, void (*func)(void *data), void *data);
void on_cpu(int cpu, void (*func)(void *data), void *data);
void on_cpus(void (*func)(void *data), void *data);
+void on_cpumask_async(const cpumask_t *mask, void (*func)(void *data), void *data);
+void on_cpumask(const cpumask_t *mask, void (*func)(void *data), void *data);
#endif /* _ON_CPUS_H_ */
diff --git a/lib/riscv/asm/csr.h b/lib/riscv/asm/csr.h
index 24b333e..16f5ddd 100644
--- a/lib/riscv/asm/csr.h
+++ b/lib/riscv/asm/csr.h
@@ -51,7 +51,8 @@
#define IRQ_S_GEXT 12
#define IRQ_PMU_OVF 13
-#define IE_TIE (_AC(0x1, UL) << IRQ_S_TIMER)
+#define IE_SSIE (_AC(1, UL) << IRQ_S_SOFT)
+#define IE_TIE (_AC(1, UL) << IRQ_S_TIMER)
#define IP_TIP IE_TIE
diff --git a/lib/riscv/asm/processor.h b/lib/riscv/asm/processor.h
index 4c9ad96..4063255 100644
--- a/lib/riscv/asm/processor.h
+++ b/lib/riscv/asm/processor.h
@@ -32,10 +32,26 @@
csr_clear(CSR_SSTATUS, SR_SIE);
}
+static inline void local_ipi_enable(void)
+{
+ csr_set(CSR_SIE, IE_SSIE);
+}
+
+static inline void local_ipi_disable(void)
+{
+ csr_clear(CSR_SIE, IE_SSIE);
+}
+
+static inline void ipi_ack(void)
+{
+ csr_clear(CSR_SIP, IE_SSIE);
+}
+
void install_exception_handler(unsigned long cause, void (*handler)(struct pt_regs *));
void install_irq_handler(unsigned long cause, void (*handler)(struct pt_regs *));
void do_handle_exception(struct pt_regs *regs);
void thread_info_init(void);
+void local_hart_init(void);
void show_regs(struct pt_regs *regs);
diff --git a/lib/riscv/asm/sbi.h b/lib/riscv/asm/sbi.h
index 47e9102..e032444 100644
--- a/lib/riscv/asm/sbi.h
+++ b/lib/riscv/asm/sbi.h
@@ -13,10 +13,12 @@
#define SBI_ERR_ALREADY_STOPPED -8
#ifndef __ASSEMBLY__
+#include <cpumask.h>
enum sbi_ext_id {
SBI_EXT_BASE = 0x10,
SBI_EXT_TIME = 0x54494d45,
+ SBI_EXT_IPI = 0x735049,
SBI_EXT_HSM = 0x48534d,
SBI_EXT_SRST = 0x53525354,
SBI_EXT_DBCN = 0x4442434E,
@@ -43,6 +45,10 @@
SBI_EXT_TIME_SET_TIMER = 0,
};
+enum sbi_ext_ipi_fid {
+ SBI_EXT_IPI_SEND_IPI = 0,
+};
+
enum sbi_ext_dbcn_fid {
SBI_EXT_DBCN_CONSOLE_WRITE = 0,
SBI_EXT_DBCN_CONSOLE_READ,
@@ -61,6 +67,10 @@
void sbi_shutdown(void);
struct sbiret sbi_hart_start(unsigned long hartid, unsigned long entry, unsigned long sp);
+struct sbiret sbi_send_ipi(unsigned long hart_mask, unsigned long hart_mask_base);
+struct sbiret sbi_send_ipi_cpu(int cpu);
+struct sbiret sbi_send_ipi_cpumask(const cpumask_t *mask);
+struct sbiret sbi_set_timer(unsigned long stime_value);
long sbi_probe(int ext);
#endif /* !__ASSEMBLY__ */
diff --git a/lib/riscv/asm/timer.h b/lib/riscv/asm/timer.h
index b3514d3..d206a29 100644
--- a/lib/riscv/asm/timer.h
+++ b/lib/riscv/asm/timer.h
@@ -5,6 +5,8 @@
#include <asm/csr.h>
extern void timer_get_frequency(void);
+extern void timer_start(unsigned long duration_us);
+extern void timer_stop(void);
static inline uint64_t timer_get_cycles(void)
{
diff --git a/lib/riscv/processor.c b/lib/riscv/processor.c
index 0dffadc..b055acc 100644
--- a/lib/riscv/processor.c
+++ b/lib/riscv/processor.c
@@ -3,10 +3,12 @@
* Copyright (C) 2023, Ventana Micro Systems Inc., Andrew Jones <ajones@ventanamicro.com>
*/
#include <libcflat.h>
+#include <limits.h>
#include <asm/csr.h>
#include <asm/isa.h>
#include <asm/processor.h>
#include <asm/setup.h>
+#include <asm/smp.h>
extern unsigned long ImageBase;
@@ -82,3 +84,12 @@
isa_init(&cpus[cpu]);
csr_write(CSR_SSCRATCH, &cpus[cpu]);
}
+
+void local_hart_init(void)
+{
+ if (cpu_has_extension(smp_processor_id(), ISA_SSTC)) {
+ csr_write(CSR_STIMECMP, ULONG_MAX);
+ if (__riscv_xlen == 32)
+ csr_write(CSR_STIMECMPH, ULONG_MAX);
+ }
+}
diff --git a/lib/riscv/sbi.c b/lib/riscv/sbi.c
index 3d4236e..ecc63ac 100644
--- a/lib/riscv/sbi.c
+++ b/lib/riscv/sbi.c
@@ -1,6 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <libcflat.h>
+#include <cpumask.h>
+#include <limits.h>
#include <asm/sbi.h>
+#include <asm/setup.h>
struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
unsigned long arg1, unsigned long arg2,
@@ -39,6 +42,56 @@
return sbi_ecall(SBI_EXT_HSM, SBI_EXT_HSM_HART_START, hartid, entry, sp, 0, 0, 0);
}
+struct sbiret sbi_send_ipi(unsigned long hart_mask, unsigned long hart_mask_base)
+{
+ return sbi_ecall(SBI_EXT_IPI, SBI_EXT_IPI_SEND_IPI, hart_mask, hart_mask_base, 0, 0, 0, 0);
+}
+
+struct sbiret sbi_send_ipi_cpu(int cpu)
+{
+ return sbi_send_ipi(1UL, cpus[cpu].hartid);
+}
+
+struct sbiret sbi_send_ipi_cpumask(const cpumask_t *mask)
+{
+ struct sbiret ret;
+ cpumask_t tmp;
+
+ if (cpumask_full(mask))
+ return sbi_send_ipi(0, -1UL);
+
+ cpumask_copy(&tmp, mask);
+
+ while (!cpumask_empty(&tmp)) {
+ unsigned long base = ULONG_MAX;
+ unsigned long mask = 0;
+ int cpu;
+
+ for_each_cpu(cpu, &tmp) {
+ if (base > cpus[cpu].hartid)
+ base = cpus[cpu].hartid;
+ }
+
+ for_each_cpu(cpu, &tmp) {
+ if (cpus[cpu].hartid < base + BITS_PER_LONG) {
+ mask |= 1UL << (cpus[cpu].hartid - base);
+ cpumask_clear_cpu(cpu, &tmp);
+ }
+ }
+
+ ret = sbi_send_ipi(mask, base);
+ if (ret.error)
+ break;
+ }
+
+ return ret;
+}
+
+struct sbiret sbi_set_timer(unsigned long stime_value)
+{
+ return sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0, 0, 0, 0, 0);
+}
+
long sbi_probe(int ext)
{
struct sbiret ret;
diff --git a/lib/riscv/setup.c b/lib/riscv/setup.c
index 9a16f00..495db04 100644
--- a/lib/riscv/setup.c
+++ b/lib/riscv/setup.c
@@ -210,6 +210,7 @@
cpu_init();
timer_get_frequency();
thread_info_init();
+ local_hart_init();
io_init();
ret = dt_get_bootargs(&bootargs);
@@ -276,6 +277,7 @@
cpu_init();
timer_get_frequency();
thread_info_init();
+ local_hart_init();
io_init();
initrd_setup();
diff --git a/lib/riscv/smp.c b/lib/riscv/smp.c
index 4d373e0..eb7061a 100644
--- a/lib/riscv/smp.c
+++ b/lib/riscv/smp.c
@@ -27,6 +27,7 @@
__mmu_enable(data->satp);
thread_info_init();
+ local_hart_init();
info = current_thread_info();
set_cpu_online(info->cpu, true);
smp_send_event();
diff --git a/lib/riscv/timer.c b/lib/riscv/timer.c
index d78d254..18063b7 100644
--- a/lib/riscv/timer.c
+++ b/lib/riscv/timer.c
@@ -4,7 +4,13 @@
*/
#include <libcflat.h>
#include <devicetree.h>
+#include <limits.h>
+#include <asm/csr.h>
+#include <asm/delay.h>
+#include <asm/isa.h>
+#include <asm/sbi.h>
#include <asm/setup.h>
+#include <asm/smp.h>
#include <asm/timer.h>
void timer_get_frequency(void)
@@ -26,3 +32,41 @@
data = (u32 *)prop->data;
timebase_frequency = fdt32_to_cpu(*data);
}
+
+void timer_start(unsigned long duration_us)
+{
+ uint64_t next = timer_get_cycles() + usec_to_cycles((uint64_t)duration_us);
+
+ if (cpu_has_extension(smp_processor_id(), ISA_SSTC)) {
+ csr_write(CSR_STIMECMP, (unsigned long)next);
+ if (__riscv_xlen == 32)
+ csr_write(CSR_STIMECMPH, (unsigned long)(next >> 32));
+ } else if (sbi_probe(SBI_EXT_TIME)) {
+ struct sbiret ret = sbi_set_timer(next);
+ assert(ret.error == SBI_SUCCESS);
+ assert(!(next >> 32));
+ } else {
+ assert_msg(false, "No timer to start!");
+ }
+}
+
+void timer_stop(void)
+{
+ if (cpu_has_extension(smp_processor_id(), ISA_SSTC)) {
+ /*
+ * Subtract one from ULONG_MAX to workaround QEMU using that
+ * exact number to decide *not* to update the timer. IOW, if
+ * we used ULONG_MAX, then we wouldn't stop the timer at all,
+ * but one less is still a big number ("infinity") and it gets
+ * QEMU to do what we want.
+ */
+ csr_write(CSR_STIMECMP, ULONG_MAX - 1);
+ if (__riscv_xlen == 32)
+ csr_write(CSR_STIMECMPH, ULONG_MAX - 1);
+ } else if (sbi_probe(SBI_EXT_TIME)) {
+ struct sbiret ret = sbi_set_timer(ULONG_MAX);
+ assert(ret.error == SBI_SUCCESS);
+ } else {
+ assert_msg(false, "No timer to stop!");
+ }
+}
diff --git a/riscv/sbi.c b/riscv/sbi.c
index 36ddfd4..093c20a 100644
--- a/riscv/sbi.c
+++ b/riscv/sbi.c
@@ -15,7 +15,6 @@
#include <asm/csr.h>
#include <asm/delay.h>
#include <asm/io.h>
-#include <asm/isa.h>
#include <asm/mmu.h>
#include <asm/processor.h>
#include <asm/sbi.h>
@@ -30,19 +29,21 @@
puts("An environ must be provided where expected values are given.\n");
}
-static struct sbiret __base_sbi_ecall(int fid, unsigned long arg0)
+static struct sbiret sbi_base(int fid, unsigned long arg0)
{
return sbi_ecall(SBI_EXT_BASE, fid, arg0, 0, 0, 0, 0, 0);
}
-static struct sbiret __time_sbi_ecall(unsigned long stime_value)
+static struct sbiret sbi_dbcn_write(unsigned long num_bytes, unsigned long base_addr_lo,
+ unsigned long base_addr_hi)
{
- return sbi_ecall(SBI_EXT_TIME, SBI_EXT_TIME_SET_TIMER, stime_value, 0, 0, 0, 0, 0);
+ return sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE,
+ num_bytes, base_addr_lo, base_addr_hi, 0, 0, 0);
}
-static struct sbiret __dbcn_sbi_ecall(int fid, unsigned long arg0, unsigned long arg1, unsigned long arg2)
+static struct sbiret sbi_dbcn_write_byte(uint8_t byte)
{
- return sbi_ecall(SBI_EXT_DBCN, fid, arg0, arg1, arg2, 0, 0, 0);
+ return sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE_BYTE, byte, 0, 0, 0, 0, 0);
}
static void split_phys_addr(phys_addr_t paddr, unsigned long *hi, unsigned long *lo)
@@ -103,7 +104,7 @@
report_prefix_push("base");
- ret = __base_sbi_ecall(SBI_EXT_BASE_GET_SPEC_VERSION, 0);
+ ret = sbi_base(SBI_EXT_BASE_GET_SPEC_VERSION, 0);
if (ret.error || ret.value < 2) {
report_skip("SBI spec version 0.2 or higher required");
return;
@@ -119,7 +120,7 @@
report_prefix_push("impl_id");
if (env_or_skip("SBI_IMPL_ID")) {
expected = (long)strtoul(getenv("SBI_IMPL_ID"), NULL, 0);
- ret = __base_sbi_ecall(SBI_EXT_BASE_GET_IMP_ID, 0);
+ ret = sbi_base(SBI_EXT_BASE_GET_IMP_ID, 0);
gen_report(&ret, 0, expected);
}
report_prefix_pop();
@@ -127,17 +128,17 @@
report_prefix_push("impl_version");
if (env_or_skip("SBI_IMPL_VERSION")) {
expected = (long)strtoul(getenv("SBI_IMPL_VERSION"), NULL, 0);
- ret = __base_sbi_ecall(SBI_EXT_BASE_GET_IMP_VERSION, 0);
+ ret = sbi_base(SBI_EXT_BASE_GET_IMP_VERSION, 0);
gen_report(&ret, 0, expected);
}
report_prefix_pop();
report_prefix_push("probe_ext");
expected = getenv("SBI_PROBE_EXT") ? (long)strtoul(getenv("SBI_PROBE_EXT"), NULL, 0) : 1;
- ret = __base_sbi_ecall(SBI_EXT_BASE_PROBE_EXT, SBI_EXT_BASE);
+ ret = sbi_base(SBI_EXT_BASE_PROBE_EXT, SBI_EXT_BASE);
gen_report(&ret, 0, expected);
report_prefix_push("unavailable");
- ret = __base_sbi_ecall(SBI_EXT_BASE_PROBE_EXT, 0xb000000);
+ ret = sbi_base(SBI_EXT_BASE_PROBE_EXT, 0xb000000);
gen_report(&ret, 0, 0);
report_prefix_pop();
report_prefix_pop();
@@ -146,7 +147,7 @@
if (env_or_skip("MVENDORID")) {
expected = (long)strtoul(getenv("MVENDORID"), NULL, 0);
assert(__riscv_xlen == 32 || !(expected >> 32));
- ret = __base_sbi_ecall(SBI_EXT_BASE_GET_MVENDORID, 0);
+ ret = sbi_base(SBI_EXT_BASE_GET_MVENDORID, 0);
gen_report(&ret, 0, expected);
}
report_prefix_pop();
@@ -154,7 +155,7 @@
report_prefix_push("marchid");
if (env_or_skip("MARCHID")) {
expected = (long)strtoul(getenv("MARCHID"), NULL, 0);
- ret = __base_sbi_ecall(SBI_EXT_BASE_GET_MARCHID, 0);
+ ret = sbi_base(SBI_EXT_BASE_GET_MARCHID, 0);
gen_report(&ret, 0, expected);
}
report_prefix_pop();
@@ -162,7 +163,7 @@
report_prefix_push("mimpid");
if (env_or_skip("MIMPID")) {
expected = (long)strtoul(getenv("MIMPID"), NULL, 0);
- ret = __base_sbi_ecall(SBI_EXT_BASE_GET_MIMPID, 0);
+ ret = sbi_base(SBI_EXT_BASE_GET_MIMPID, 0);
gen_report(&ret, 0, expected);
}
report_prefix_pop();
@@ -198,7 +199,7 @@
if (timer_info.mask_timer_irq)
timer_irq_disable();
else
- __time_sbi_ecall(ULONG_MAX);
+ sbi_set_timer(ULONG_MAX);
if (!timer_irq_pending())
timer_info.timer_irq_cleared = true;
@@ -217,7 +218,7 @@
timer_info = (struct timer_info){ .mask_timer_irq = mask_timer_irq };
begin = timer_get_cycles();
- ret = __time_sbi_ecall(begin + d);
+ ret = sbi_set_timer(begin + d);
report(!ret.error, "set timer%s", mask_test_str);
if (ret.error)
@@ -258,11 +259,6 @@
install_irq_handler(IRQ_S_TIMER, timer_irq_handler);
local_irq_enable();
- if (cpu_has_extension(smp_processor_id(), ISA_SSTC)) {
- csr_write(CSR_STIMECMP, ULONG_MAX);
- if (__riscv_xlen == 32)
- csr_write(CSR_STIMECMPH, ULONG_MAX);
- }
timer_irq_enable();
timer_check_set_timer(false);
@@ -273,10 +269,10 @@
report_skip("timer irq enable bit is not writable, skipping mask irq test");
timer_irq_disable();
- __time_sbi_ecall(0);
+ sbi_set_timer(0);
pending = timer_irq_pending();
report(pending, "timer immediately pending by setting timer to 0");
- __time_sbi_ecall(ULONG_MAX);
+ sbi_set_timer(ULONG_MAX);
if (pending)
report(!timer_irq_pending(), "pending timer cleared while masked");
else
@@ -302,7 +298,7 @@
split_phys_addr(paddr, &base_addr_hi, &base_addr_lo);
do {
- ret = __dbcn_sbi_ecall(SBI_EXT_DBCN_CONSOLE_WRITE, num_bytes, base_addr_lo, base_addr_hi);
+ ret = sbi_dbcn_write(num_bytes, base_addr_lo, base_addr_hi);
num_bytes -= ret.value;
paddr += ret.value;
split_phys_addr(paddr, &base_addr_hi, &base_addr_lo);
@@ -335,7 +331,7 @@
/*
* Only the write functionality is tested here. There's no easy way to
- * non-interactively test the read functionality.
+ * non-interactively test SBI_EXT_DBCN_CONSOLE_READ.
*/
static void check_dbcn(void)
{
@@ -349,8 +345,7 @@
report_prefix_push("dbcn");
- ret = __base_sbi_ecall(SBI_EXT_BASE_PROBE_EXT, SBI_EXT_DBCN);
- if (!ret.value) {
+ if (!sbi_probe(SBI_EXT_DBCN)) {
report_skip("DBCN extension unavailable");
report_prefix_pop();
return;
@@ -403,7 +398,7 @@
if (do_invalid_addr) {
split_phys_addr(paddr, &base_addr_hi, &base_addr_lo);
- ret = __dbcn_sbi_ecall(SBI_EXT_DBCN_CONSOLE_WRITE, 1, base_addr_lo, base_addr_hi);
+ ret = sbi_dbcn_write(1, base_addr_lo, base_addr_hi);
report(ret.error == SBI_ERR_INVALID_PARAM, "address (error=%ld)", ret.error);
}
report_prefix_pop();
@@ -411,12 +406,19 @@
report_prefix_pop();
report_prefix_push("write_byte");
- puts("DBCN_WRITE TEST CHAR: ");
- ret = __dbcn_sbi_ecall(SBI_EXT_DBCN_CONSOLE_WRITE_BYTE, (u8)DBCN_WRITE_BYTE_TEST_BYTE, 0, 0);
+ puts("DBCN_WRITE_BYTE TEST BYTE: ");
+ ret = sbi_dbcn_write_byte(DBCN_WRITE_BYTE_TEST_BYTE);
puts("\n");
report(ret.error == SBI_SUCCESS, "write success (error=%ld)", ret.error);
report(ret.value == 0, "expected ret.value (%ld)", ret.value);
+ puts("DBCN_WRITE_BYTE TEST WORD: "); /* still expect 'a' in the output */
+ ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE_BYTE, 0x64636261, 0, 0, 0, 0, 0);
+ puts("\n");
+ report(ret.error == SBI_SUCCESS, "write success (error=%ld)", ret.error);
+ report(ret.value == 0, "expected ret.value (%ld)", ret.value);
+
+ report_prefix_pop();
report_prefix_pop();
}