Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RISC-V SBI debug console extension support #121

Closed
wants to merge 8 commits into from
1 change: 1 addition & 0 deletions arch/riscv/configs/defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_DW=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SERIAL_SH_SCI=y
CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_VIRTIO=y
Expand Down
1 change: 1 addition & 0 deletions arch/riscv/configs/rv32_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ CONFIG_INPUT_MOUSEDEV=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_SERIAL_EARLYCON_RISCV_SBI=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_VIRTIO=y
Expand Down
7 changes: 6 additions & 1 deletion arch/riscv/include/asm/kvm_vcpu_sbi.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

#define KVM_SBI_IMPID 3

#define KVM_SBI_VERSION_MAJOR 1
#define KVM_SBI_VERSION_MAJOR 2
#define KVM_SBI_VERSION_MINOR 0

enum kvm_riscv_sbi_ext_status {
Expand All @@ -35,6 +35,9 @@ struct kvm_vcpu_sbi_return {
struct kvm_vcpu_sbi_extension {
unsigned long extid_start;
unsigned long extid_end;

bool default_unavail;

/**
* SBI extension handler. It can be defined for a given extension or group of
* extension. But it should always return linux error codes rather than SBI
Expand All @@ -59,6 +62,7 @@ int kvm_riscv_vcpu_get_reg_sbi_ext(struct kvm_vcpu *vcpu,
const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(
struct kvm_vcpu *vcpu, unsigned long extid);
int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run);
void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu);

#ifdef CONFIG_RISCV_SBI_V01
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01;
Expand All @@ -69,6 +73,7 @@ extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_ipi;
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_rfence;
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst;
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_hsm;
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn;
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental;
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor;

Expand Down
12 changes: 12 additions & 0 deletions arch/riscv/include/asm/sbi.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ enum sbi_ext_id {
SBI_EXT_HSM = 0x48534D,
SBI_EXT_SRST = 0x53525354,
SBI_EXT_PMU = 0x504D55,
SBI_EXT_DBCN = 0x4442434E,

/* Experimentals extensions must lie within this range */
SBI_EXT_EXPERIMENTAL_START = 0x08000000,
Expand Down Expand Up @@ -236,6 +237,12 @@ enum sbi_pmu_ctr_type {
/* Flags defined for counter stop function */
#define SBI_PMU_STOP_FLAG_RESET (1 << 0)

enum sbi_ext_dbcn_fid {
SBI_EXT_DBCN_CONSOLE_WRITE = 0,
SBI_EXT_DBCN_CONSOLE_READ = 1,
SBI_EXT_DBCN_CONSOLE_WRITE_BYTE = 2,
};

#define SBI_SPEC_VERSION_DEFAULT 0x1
#define SBI_SPEC_VERSION_MAJOR_SHIFT 24
#define SBI_SPEC_VERSION_MAJOR_MASK 0x7f
Expand Down Expand Up @@ -264,8 +271,13 @@ struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
unsigned long arg3, unsigned long arg4,
unsigned long arg5);

#ifdef CONFIG_RISCV_SBI_V01
void sbi_console_putchar(int ch);
int sbi_console_getchar(void);
#else
static inline void sbi_console_putchar(int ch) { }
static inline int sbi_console_getchar(void) { return -1; }
#endif
long sbi_get_mvendorid(void);
long sbi_get_marchid(void);
long sbi_get_mimpid(void);
Expand Down
1 change: 1 addition & 0 deletions arch/riscv/include/uapi/asm/kvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ enum KVM_RISCV_SBI_EXT_ID {
KVM_RISCV_SBI_EXT_PMU,
KVM_RISCV_SBI_EXT_EXPERIMENTAL,
KVM_RISCV_SBI_EXT_VENDOR,
KVM_RISCV_SBI_EXT_DBCN,
KVM_RISCV_SBI_EXT_MAX,
};

Expand Down
6 changes: 6 additions & 0 deletions arch/riscv/kvm/vcpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,12 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
if (rc)
return rc;

/*
* Setup SBI extensions
* NOTE: This must be the last thing to be initialized.
*/
kvm_riscv_vcpu_sbi_init(vcpu);

/* Reset VCPU */
kvm_riscv_reset_vcpu(vcpu);

Expand Down
49 changes: 30 additions & 19 deletions arch/riscv/kvm/vcpu_sbi.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = {
.ext_idx = KVM_RISCV_SBI_EXT_PMU,
.ext_ptr = &vcpu_sbi_ext_pmu,
},
{
.ext_idx = KVM_RISCV_SBI_EXT_DBCN,
.ext_ptr = &vcpu_sbi_ext_dbcn,
},
{
.ext_idx = KVM_RISCV_SBI_EXT_EXPERIMENTAL,
.ext_ptr = &vcpu_sbi_ext_experimental,
Expand Down Expand Up @@ -155,14 +159,8 @@ static int riscv_vcpu_set_sbi_ext_single(struct kvm_vcpu *vcpu,
if (!sext)
return -ENOENT;

/*
* We can't set the extension status to available here, since it may
* have a probe() function which needs to confirm availability first,
* but it may be too early to call that here. We can set the status to
* unavailable, though.
*/
if (!reg_val)
scontext->ext_status[sext->ext_idx] =
scontext->ext_status[sext->ext_idx] = (reg_val) ?
KVM_RISCV_SBI_EXT_AVAILABLE :
KVM_RISCV_SBI_EXT_UNAVAILABLE;

return 0;
Expand Down Expand Up @@ -337,18 +335,8 @@ const struct kvm_vcpu_sbi_extension *kvm_vcpu_sbi_find_ext(
scontext->ext_status[entry->ext_idx] ==
KVM_RISCV_SBI_EXT_AVAILABLE)
return ext;
if (scontext->ext_status[entry->ext_idx] ==
KVM_RISCV_SBI_EXT_UNAVAILABLE)
return NULL;
if (ext->probe && !ext->probe(vcpu)) {
scontext->ext_status[entry->ext_idx] =
KVM_RISCV_SBI_EXT_UNAVAILABLE;
return NULL;
}

scontext->ext_status[entry->ext_idx] =
KVM_RISCV_SBI_EXT_AVAILABLE;
return ext;
return NULL;
}
}

Expand Down Expand Up @@ -419,3 +407,26 @@ int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run)

return ret;
}

void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu)
{
struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
const struct kvm_riscv_sbi_extension_entry *entry;
const struct kvm_vcpu_sbi_extension *ext;
int i;

for (i = 0; i < ARRAY_SIZE(sbi_ext); i++) {
entry = &sbi_ext[i];
ext = entry->ext_ptr;

if (ext->probe && !ext->probe(vcpu)) {
scontext->ext_status[entry->ext_idx] =
KVM_RISCV_SBI_EXT_UNAVAILABLE;
continue;
}

scontext->ext_status[entry->ext_idx] = ext->default_unavail ?
KVM_RISCV_SBI_EXT_UNAVAILABLE :
KVM_RISCV_SBI_EXT_AVAILABLE;
}
}
32 changes: 32 additions & 0 deletions arch/riscv/kvm/vcpu_sbi_replace.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,35 @@ const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_srst = {
.extid_end = SBI_EXT_SRST,
.handler = kvm_sbi_ext_srst_handler,
};

static int kvm_sbi_ext_dbcn_handler(struct kvm_vcpu *vcpu,
struct kvm_run *run,
struct kvm_vcpu_sbi_return *retdata)
{
struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
unsigned long funcid = cp->a6;

switch (funcid) {
case SBI_EXT_DBCN_CONSOLE_WRITE:
case SBI_EXT_DBCN_CONSOLE_READ:
case SBI_EXT_DBCN_CONSOLE_WRITE_BYTE:
/*
* The SBI debug console functions are unconditionally
* forwarded to the userspace.
*/
kvm_riscv_vcpu_sbi_forward(vcpu, run);
retdata->uexit = true;
break;
default:
retdata->err_val = SBI_ERR_NOT_SUPPORTED;
}

return 0;
}

const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_dbcn = {
.extid_start = SBI_EXT_DBCN,
.extid_end = SBI_EXT_DBCN,
.default_unavail = true,
.handler = kvm_sbi_ext_dbcn_handler,
};
2 changes: 1 addition & 1 deletion drivers/tty/hvc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ config HVC_DCC_SERIALIZE_SMP

config HVC_RISCV_SBI
bool "RISC-V SBI console support"
depends on RISCV_SBI_V01
depends on RISCV_SBI
select HVC_DRIVER
help
This enables support for console output via RISC-V SBI calls, which
Expand Down
76 changes: 69 additions & 7 deletions drivers/tty/hvc/hvc_riscv_sbi.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,83 @@ static int hvc_sbi_tty_get(uint32_t vtermno, char *buf, int count)
return i;
}

static const struct hv_ops hvc_sbi_ops = {
static const struct hv_ops hvc_sbi_v01_ops = {
.get_chars = hvc_sbi_tty_get,
.put_chars = hvc_sbi_tty_put,
};

static int __init hvc_sbi_init(void)
static int hvc_sbi_dbcn_tty_put(uint32_t vtermno, const char *buf, int count)
{
return PTR_ERR_OR_ZERO(hvc_alloc(0, 0, &hvc_sbi_ops, 16));
phys_addr_t pa;
struct sbiret ret;

if (is_vmalloc_addr(buf))
pa = page_to_phys(vmalloc_to_page(buf)) + offset_in_page(buf);
else
pa = __pa(buf);

if (IS_ENABLED(CONFIG_32BIT))
ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE,
count, lower_32_bits(pa), upper_32_bits(pa),
0, 0, 0);
else
ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE,
count, pa, 0, 0, 0, 0);
if (ret.error)
return 0;

return count;
}
device_initcall(hvc_sbi_init);

static int __init hvc_sbi_console_init(void)
static int hvc_sbi_dbcn_tty_get(uint32_t vtermno, char *buf, int count)
{
hvc_instantiate(0, 0, &hvc_sbi_ops);
phys_addr_t pa;
struct sbiret ret;

if (is_vmalloc_addr(buf))
pa = page_to_phys(vmalloc_to_page(buf)) + offset_in_page(buf);
else
pa = __pa(buf);

if (IS_ENABLED(CONFIG_32BIT))
ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_READ,
count, lower_32_bits(pa), upper_32_bits(pa),
0, 0, 0);
else
ret = sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_READ,
count, pa, 0, 0, 0, 0);
if (ret.error)
return 0;

return ret.value;
}

static const struct hv_ops hvc_sbi_dbcn_ops = {
.put_chars = hvc_sbi_dbcn_tty_put,
.get_chars = hvc_sbi_dbcn_tty_get,
};

static int __init hvc_sbi_init(void)
{
int err;

if ((sbi_spec_version >= sbi_mk_version(2, 0)) &&
(sbi_probe_extension(SBI_EXT_DBCN) > 0)) {
err = PTR_ERR_OR_ZERO(hvc_alloc(0, 0, &hvc_sbi_dbcn_ops, 16));
if (err)
return err;
hvc_instantiate(0, 0, &hvc_sbi_dbcn_ops);
} else {
if (IS_ENABLED(CONFIG_RISCV_SBI_V01)) {
err = PTR_ERR_OR_ZERO(hvc_alloc(0, 0, &hvc_sbi_v01_ops, 16));
if (err)
return err;
hvc_instantiate(0, 0, &hvc_sbi_v01_ops);
} else {
return -ENODEV;
}
}

return 0;
}
console_initcall(hvc_sbi_console_init);
device_initcall(hvc_sbi_init);
2 changes: 1 addition & 1 deletion drivers/tty/serial/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ config SERIAL_EARLYCON_SEMIHOST

config SERIAL_EARLYCON_RISCV_SBI
bool "Early console using RISC-V SBI"
depends on RISCV_SBI_V01
depends on RISCV_SBI
select SERIAL_CORE
select SERIAL_CORE_CONSOLE
select SERIAL_EARLYCON
Expand Down
32 changes: 28 additions & 4 deletions drivers/tty/serial/earlycon-riscv-sbi.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,41 @@ static void sbi_putc(struct uart_port *port, unsigned char c)
sbi_console_putchar(c);
}

static void sbi_console_write(struct console *con,
const char *s, unsigned n)
static void sbi_0_1_console_write(struct console *con,
const char *s, unsigned int n)
{
struct earlycon_device *dev = con->data;
uart_console_write(&dev->port, s, n, sbi_putc);
}

static void sbi_dbcn_console_write(struct console *con,
const char *s, unsigned int n)
{
phys_addr_t pa = __pa(s);

if (IS_ENABLED(CONFIG_32BIT))
sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE,
n, lower_32_bits(pa), upper_32_bits(pa), 0, 0, 0);
else
sbi_ecall(SBI_EXT_DBCN, SBI_EXT_DBCN_CONSOLE_WRITE,
n, pa, 0, 0, 0, 0);
}

static int __init early_sbi_setup(struct earlycon_device *device,
const char *opt)
{
device->con->write = sbi_console_write;
return 0;
int ret = 0;

if ((sbi_spec_version >= sbi_mk_version(2, 0)) &&
(sbi_probe_extension(SBI_EXT_DBCN) > 0)) {
device->con->write = sbi_dbcn_console_write;
} else {
if (IS_ENABLED(CONFIG_RISCV_SBI_V01))
device->con->write = sbi_0_1_console_write;
else
ret = -ENODEV;
}

return ret;
}
EARLYCON_DECLARE(sbi, early_sbi_setup);
Loading