@@ -12,6 +12,17 @@
/* clang-format off */
+#define SBI_SUCCESS 0
+#define SBI_ERR_FAILED -1
+#define SBI_ERR_NOT_SUPPORTED -2
+#define SBI_ERR_INVALID_PARAM -3
+#define SBI_ERR_DENIED -4
+#define SBI_ERR_INVALID_ADDRESS -5
+#define SBI_ERR_ALREADY_AVAILABLE -6
+#define SBI_ERR_ALREADY_STARTED -7
+#define SBI_ERR_ALREADY_STOPPED -8
+#define SBI_ERR_NO_SHMEM -9
+
/* SBI Extension IDs */
#define SBI_EXT_0_1_SET_TIMER 0x0
#define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1
@@ -27,6 +38,7 @@
#define SBI_EXT_IPI 0x735049
#define SBI_EXT_RFENCE 0x52464E43
#define SBI_EXT_HSM 0x48534D
+#define SBI_EXT_DBCN 0x4442434E
/* SBI function IDs for BASE extension */
#define SBI_EXT_BASE_GET_SPEC_VERSION 0x0
@@ -57,6 +69,11 @@
#define SBI_EXT_HSM_HART_STOP 0x1
#define SBI_EXT_HSM_HART_GET_STATUS 0x2
+/* SBI function IDs for DBCN extension */
+#define SBI_EXT_DBCN_CONSOLE_WRITE 0x0
+#define SBI_EXT_DBCN_CONSOLE_READ 0x1
+#define SBI_EXT_DBCN_CONSOLE_WRITE_BYTE 0x2
+
#define SBI_HSM_HART_STATUS_STARTED 0x0
#define SBI_HSM_HART_STATUS_STOPPED 0x1
#define SBI_HSM_HART_STATUS_START_PENDING 0x2
@@ -409,6 +409,12 @@ static KVMCPUConfig kvm_v_vlenb = {
KVM_REG_RISCV_VECTOR_CSR_REG(vlenb)
};
+static KVMCPUConfig kvm_sbi_dbcn = {
+ .name = "sbi_dbcn",
+ .kvm_reg_id = KVM_REG_RISCV | KVM_REG_SIZE_U64 |
+ KVM_REG_RISCV_SBI_EXT | KVM_RISCV_SBI_EXT_DBCN
+};
+
static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs)
{
CPURISCVState *env = &cpu->env;
@@ -1037,6 +1043,20 @@ static int uint64_cmp(const void *a, const void *b)
return 0;
}
+static void kvm_riscv_check_sbi_dbcn_support(RISCVCPU *cpu,
+ KVMScratchCPU *kvmcpu,
+ struct kvm_reg_list *reglist)
+{
+ struct kvm_reg_list *reg_search;
+
+ reg_search = bsearch(&kvm_sbi_dbcn.kvm_reg_id, reglist->reg, reglist->n,
+ sizeof(uint64_t), uint64_cmp);
+
+ if (reg_search) {
+ kvm_sbi_dbcn.supported = true;
+ }
+}
+
static void kvm_riscv_read_vlenb(RISCVCPU *cpu, KVMScratchCPU *kvmcpu,
struct kvm_reg_list *reglist)
{
@@ -1142,6 +1162,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
if (riscv_has_ext(&cpu->env, RVV)) {
kvm_riscv_read_vlenb(cpu, kvmcpu, reglist);
}
+
+ kvm_riscv_check_sbi_dbcn_support(cpu, kvmcpu, reglist);
}
static void riscv_init_kvm_registers(Object *cpu_obj)
@@ -1316,6 +1338,17 @@ static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs)
return ret;
}
+static int kvm_vcpu_enable_sbi_dbcn(RISCVCPU *cpu, CPUState *cs)
+{
+ target_ulong reg = 1;
+
+ if (!kvm_sbi_dbcn.supported) {
+ return 0;
+ }
+
+ return kvm_set_one_reg(cs, kvm_sbi_dbcn.kvm_reg_id, ®);
+}
+
int kvm_arch_init_vcpu(CPUState *cs)
{
int ret = 0;
@@ -1333,6 +1366,8 @@ int kvm_arch_init_vcpu(CPUState *cs)
kvm_riscv_update_cpu_misa_ext(cpu, cs);
kvm_riscv_update_cpu_cfg_isa_ext(cpu, cs);
+ ret = kvm_vcpu_enable_sbi_dbcn(cpu, cs);
+
return ret;
}
@@ -1390,6 +1425,79 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cs)
return true;
}
+static void kvm_riscv_handle_sbi_dbcn(CPUState *cs, struct kvm_run *run)
+{
+ g_autofree uint8_t *buf = NULL;
+ RISCVCPU *cpu = RISCV_CPU(cs);
+ target_ulong num_bytes;
+ uint64_t addr;
+ unsigned char ch;
+ int ret;
+
+ switch (run->riscv_sbi.function_id) {
+ case SBI_EXT_DBCN_CONSOLE_READ:
+ case SBI_EXT_DBCN_CONSOLE_WRITE:
+ num_bytes = run->riscv_sbi.args[0];
+
+ if (num_bytes == 0) {
+ run->riscv_sbi.ret[0] = SBI_SUCCESS;
+ run->riscv_sbi.ret[1] = 0;
+ break;
+ }
+
+ addr = run->riscv_sbi.args[1];
+
+ /*
+ * Handle the case where a 32 bit CPU is running in a
+ * 64 bit addressing env.
+ */
+ if (riscv_cpu_mxl(&cpu->env) == MXL_RV32) {
+ addr |= (uint64_t)run->riscv_sbi.args[2] << 32;
+ }
+
+ buf = g_malloc0(num_bytes);
+
+ if (run->riscv_sbi.function_id == SBI_EXT_DBCN_CONSOLE_READ) {
+ ret = qemu_chr_fe_read_all(serial_hd(0)->be, buf, num_bytes);
+ if (ret < 0) {
+ error_report("SBI_EXT_DBCN_CONSOLE_READ: error when "
+ "reading chardev");
+ exit(1);
+ }
+
+ cpu_physical_memory_write(addr, buf, ret);
+ } else {
+ cpu_physical_memory_read(addr, buf, num_bytes);
+
+ ret = qemu_chr_fe_write_all(serial_hd(0)->be, buf, num_bytes);
+ if (ret < 0) {
+ error_report("SBI_EXT_DBCN_CONSOLE_WRITE: error when "
+ "writing chardev");
+ exit(1);
+ }
+ }
+
+ run->riscv_sbi.ret[0] = SBI_SUCCESS;
+ run->riscv_sbi.ret[1] = ret;
+ break;
+ case SBI_EXT_DBCN_CONSOLE_WRITE_BYTE:
+ ch = run->riscv_sbi.args[0];
+ ret = qemu_chr_fe_write(serial_hd(0)->be, &ch, sizeof(ch));
+
+ if (ret < 0) {
+ error_report("SBI_EXT_DBCN_CONSOLE_WRITE_BYTE: error when "
+ "writing chardev");
+ exit(1);
+ }
+
+ run->riscv_sbi.ret[0] = SBI_SUCCESS;
+ run->riscv_sbi.ret[1] = 0;
+ break;
+ default:
+ run->riscv_sbi.ret[0] = SBI_ERR_NOT_SUPPORTED;
+ }
+}
+
static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run)
{
int ret = 0;
@@ -1408,6 +1516,9 @@ static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run)
}
ret = 0;
break;
+ case SBI_EXT_DBCN:
+ kvm_riscv_handle_sbi_dbcn(cs, run);
+ break;
default:
qemu_log_mask(LOG_UNIMP,
"%s: un-handled SBI EXIT, specific reasons is %lu\n",