[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [RFC PATCH v4 2/4] Adding basic custom/vendor CSR handling mechanism
From: |
Alistair Francis |
Subject: |
Re: [RFC PATCH v4 2/4] Adding basic custom/vendor CSR handling mechanism |
Date: |
Fri, 13 Aug 2021 15:20:36 +1000 |
On Fri, Aug 6, 2021 at 3:58 AM Ruinland Chuan-Tzu Tsai
<ruinland@andestech.com> wrote:
>
> From: Ruinalnd ChuanTzu Tsai <ruinland@andestech.com>
>
> For now we add a custom CSR handling mechanism to handle non-standard CSR read
> or write.
>
> The write_stub() and read_zero() are provided for quick placeholder usage if
> such CSRs' behavior are expected to fail-over in its user code.
>
> Signed-off-by: Dylan Jhong <dylan@andestech.com>
> ---
> target/riscv/cpu.c | 23 ++++++++++
> target/riscv/cpu.h | 31 ++++++++++++-
> target/riscv/cpu_bits.h | 4 ++
> target/riscv/csr.c | 83 ++++++++++++++++++++++++++++------
> target/riscv/custom_cpu_bits.h | 8 ++++
> 5 files changed, 134 insertions(+), 15 deletions(-)
> create mode 100644 target/riscv/custom_cpu_bits.h
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 7401325..3a638b5 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -144,6 +144,29 @@ static void set_resetvec(CPURISCVState *env,
> target_ulong resetvec)
> #endif
> }
>
> +#if defined(CONFIG_RISCV_CUSTOM)
> +static void setup_custom_csr(CPURISCVState *env,
> + riscv_custom_csr_operations csr_map_struct[]
> + ) {
Can you run `checkpatch.pl` on each patch? That will catch issues like this.
> +
> + env->custom_csr_map = g_hash_table_new_full(g_direct_hash, \
> + g_direct_equal, \
> + NULL, NULL);
> +
> +
> + int i;
> + for (i = 0; i < MAX_CUSTOM_CSR_NUM; i++) {
> + if (csr_map_struct[i].csrno != 0) {
> + g_hash_table_insert(env->custom_csr_map,
> + GINT_TO_POINTER(csr_map_struct[i].csrno),
> + &csr_map_struct[i].csr_opset);
> + } else {
> + break;
> + }
> + }
> +}
> +#endif
> +
> static void riscv_any_cpu_init(Object *obj)
> {
> CPURISCVState *env = &RISCV_CPU(obj)->env;
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 0edb282..52df9bb 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -239,6 +239,16 @@ struct CPURISCVState {
>
> /* Fields from here on are preserved across CPU reset. */
> QEMUTimer *timer; /* Internal timer */
> +
> + /*
> + * The reason why we have an opset map for custom CSRs and a seperated
> + * storage map is that we might have heterogeneous architecture, in which
> + * different harts have different custom CSRs.
> + * Custom CSR opset map
> + */
> + GHashTable *custom_csr_map;
> + /* Custom CSR val holder */
> + void *custom_csr_val;
> };
>
> OBJECT_DECLARE_TYPE(RISCVCPU, RISCVCPUClass,
> @@ -485,17 +495,36 @@ typedef struct {
> riscv_csr_op_fn op;
> } riscv_csr_operations;
>
> +typedef struct {
> + int csrno;
> + riscv_csr_operations csr_opset;
> + } riscv_custom_csr_operations;
> +
> +/*
> + * The reason why we have an abstraction here is that : We could have CSR
> + * number M on hart A is an alias of CSR number N on hart B. So we make a
> + * CSR number to value address map.
> + */
> +typedef struct {
> + int csrno;
> + target_ulong val;
> + } riscv_custom_csr_vals;
This should be a seperate patch.
> +
> /* CSR function table constants */
> enum {
> - CSR_TABLE_SIZE = 0x1000
> + CSR_TABLE_SIZE = 0x1000,
> + MAX_CUSTOM_CSR_NUM = 100
> };
>
> /* CSR function table */
> +extern int andes_custom_csr_size;
> +extern riscv_custom_csr_operations
> andes_custom_csr_table[MAX_CUSTOM_CSR_NUM];
This should be a seperate patch
> extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
>
> void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
> void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops);
>
> +
> void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);
>
> #endif /* RISCV_CPU_H */
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index caf4599..de77242 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -593,3 +593,7 @@
> #define MIE_SSIE (1 << IRQ_S_SOFT)
> #define MIE_USIE (1 << IRQ_U_SOFT)
> #endif
> +
> +#if defined(CONFIG_RISCV_CUSTOM)
> +#include "custom_cpu_bits.h"
> +#endif
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index fd2e636..1c4dc94 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -137,7 +137,8 @@ static int ctr32(CPURISCVState *env, int csrno)
> return ctr(env, csrno);
> }
>
> -#if !defined(CONFIG_USER_ONLY)
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic ignored "-Wunused-function"
Don't do this. It it is unused then just remove it.
> static int any(CPURISCVState *env, int csrno)
> {
> return 0;
> @@ -152,6 +153,25 @@ static int any32(CPURISCVState *env, int csrno)
> return any(env, csrno);
>
> }
> +#pragma GCC diagnostic pop
> +
> +/* Machine Information Registers */
> +static int read_zero(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> + return *val = 0;
> +}
> +
> +/*
> + * XXX: This is just a write stub for developing custom CSR handler,
> + * if the behavior of writting such CSR is not presentable in QEMU and
> doesn't
> + * affect the functionality, just stub it.
> + */
> +static int write_stub(CPURISCVState *env, int csrno, target_ulong val)
> +{
> + return 0;
> +}
> +
> +#if !defined(CONFIG_USER_ONLY)
>
> static int smode(CPURISCVState *env, int csrno)
> {
> @@ -435,11 +455,6 @@ static const char valid_vm_1_10_64[16] = {
> [VM_1_10_SV57] = 1
> };
>
> -/* Machine Information Registers */
> -static int read_zero(CPURISCVState *env, int csrno, target_ulong *val)
> -{
> - return *val = 0;
> -}
>
> static int read_mhartid(CPURISCVState *env, int csrno, target_ulong *val)
> {
> @@ -1264,6 +1279,18 @@ static int write_pmpaddr(CPURISCVState *env, int
> csrno, target_ulong val)
>
> #endif
>
> +
> +#if defined(CONFIG_RISCV_CUSTOM)
> +/* Custom CSR related routines and data structures */
> +
> +static gpointer is_custom_csr(CPURISCVState *env, int csrno)
> +{
> + gpointer ret;
> + ret = g_hash_table_lookup(env->custom_csr_map, GINT_TO_POINTER(csrno));
> + return ret;
> +}
> +#endif
> +
> /*
> * riscv_csrrw - read and/or update control and status register
> *
> @@ -1273,12 +1300,19 @@ static int write_pmpaddr(CPURISCVState *env, int
> csrno, target_ulong val)
> * csrrc <-> riscv_csrrw(env, csrno, ret_value, 0, value);
> */
>
> +
> +
> int riscv_csrrw(CPURISCVState *env, int csrno, target_ulong *ret_value,
> target_ulong new_value, target_ulong write_mask)
> {
> int ret;
> target_ulong old_value;
> RISCVCPU *cpu = env_archcpu(env);
> + #if !defined(CONFIG_RISCV_CUSTOM)
> + riscv_csr_operations *csrop = &csr_ops[csrno];
> + #else
> + riscv_csr_operations *csrop;
Why declare this at all?
> + #endif
>
> /* check privileges and return -1 if check fails */
> #if !defined(CONFIG_USER_ONLY)
> @@ -1300,6 +1334,7 @@ int riscv_csrrw(CPURISCVState *env, int csrno,
> target_ulong *ret_value,
> (!env->debugger && (effective_priv < get_field(csrno, 0x300)))) {
> return -RISCV_EXCP_ILLEGAL_INST;
> }
> +
> #endif
>
> /* ensure the CSR extension is enabled. */
> @@ -1307,27 +1342,43 @@ int riscv_csrrw(CPURISCVState *env, int csrno,
> target_ulong *ret_value,
> return -RISCV_EXCP_ILLEGAL_INST;
> }
>
> + /* try handle_custom_csr */
> +
> + #if defined(CONFIG_RISCV_CUSTOM)
> + if (unlikely(env->custom_csr_map != NULL)) {
> + riscv_csr_operations *custom_csr_opset = (riscv_csr_operations *)
> + is_custom_csr(env, csrno);
> + if (NULL != custom_csr_opset) {
> + csrop = custom_csr_opset;
> + } else {
> + csrop = &csr_ops[csrno];
> + }
> + } else {
> + csrop = &csr_ops[csrno];
> + }
Cool! This looks like it's going in the right direction.
Alistair
> + #endif
> +
> /* check predicate */
> - if (!csr_ops[csrno].predicate) {
> + if (!csrop->predicate) {
> return -RISCV_EXCP_ILLEGAL_INST;
> }
> - ret = csr_ops[csrno].predicate(env, csrno);
> + ret = csrop->predicate(env, csrno);
> if (ret < 0) {
> return ret;
> }
>
> /* execute combined read/write operation if it exists */
> - if (csr_ops[csrno].op) {
> - return csr_ops[csrno].op(env, csrno, ret_value, new_value,
> write_mask);
> + if (csrop->op) {
> + return csrop->op(env, csrno, ret_value, new_value, write_mask);
> }
>
> /* if no accessor exists then return failure */
> - if (!csr_ops[csrno].read) {
> + if (!csrop->read) {
> return -RISCV_EXCP_ILLEGAL_INST;
> }
>
> /* read old value */
> - ret = csr_ops[csrno].read(env, csrno, &old_value);
> + ret = csrop->read(env, csrno, &old_value);
> if (ret < 0) {
> return ret;
> }
> @@ -1335,8 +1386,8 @@ int riscv_csrrw(CPURISCVState *env, int csrno,
> target_ulong *ret_value,
> /* write value if writable and write mask set, otherwise drop writes */
> if (write_mask) {
> new_value = (old_value & ~write_mask) | (new_value & write_mask);
> - if (csr_ops[csrno].write) {
> - ret = csr_ops[csrno].write(env, csrno, new_value);
> + if (csrop->write) {
> + ret = csrop->write(env, csrno, new_value);
> if (ret < 0) {
> return ret;
> }
> @@ -1369,6 +1420,10 @@ int riscv_csrrw_debug(CPURISCVState *env, int csrno,
> target_ulong *ret_value,
> return ret;
> }
>
> +#if defined(CONFIG_RISCV_CUSTOM)
> +/* Include the custom CSR table here. */
> +#endif
> +
> /* Control and Status Register function table */
> riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> /* User Floating-Point CSRs */
> diff --git a/target/riscv/custom_cpu_bits.h b/target/riscv/custom_cpu_bits.h
> new file mode 100644
> index 0000000..5df31f8
> --- /dev/null
> +++ b/target/riscv/custom_cpu_bits.h
> @@ -0,0 +1,8 @@
> +/*
> + * RISC-V cpu bits for custom CSR logic.
> + *
> + * Copyright (c) 2021 Andes Technology Corp.
> + * SPDX-License-Identifier: GPL-2.0+
> + */
> +
> +/* This file is intentionally left blank at this commit. */
> --
> 2.32.0
>
>
Re: [RFC PATCH v4 0/4] Add basic support for custom CSR, Alistair Francis, 2021/08/13