diff mbox series

[v15,8/9] target/loongarch: Adjust functions and structure to support user-mode

Message ID 20220609024209.2406188-9-gaosong@loongson.cn
State New
Headers show
Series Add LoongArch linux-user emulation support | expand

Commit Message

gaosong June 9, 2022, 2:42 a.m. UTC
Some functions and member of the structure are different with softmmu-mode
So we need adjust them to support user-mode.

Signed-off-by: Song Gao <gaosong@loongson.cn>
Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
---
 target/loongarch/cpu.c                        | 22 ++++++++++--
 target/loongarch/cpu.h                        |  6 ++++
 target/loongarch/helper.h                     |  5 +--
 target/loongarch/insn_trans/trans_extra.c.inc | 14 ++++++++
 .../insn_trans/trans_privileged.c.inc         | 36 +++++++++++++++++++
 target/loongarch/internals.h                  |  2 ++
 target/loongarch/op_helper.c                  | 12 +++++++
 7 files changed, 93 insertions(+), 4 deletions(-)

Comments

WANG Xuerui June 9, 2022, 10:18 a.m. UTC | #1
On 2022/6/9 10:42, Song Gao wrote:
> Some functions and member of the structure are different with softmmu-mode
> So we need adjust them to support user-mode.
>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> ---
>   target/loongarch/cpu.c                        | 22 ++++++++++--
>   target/loongarch/cpu.h                        |  6 ++++
>   target/loongarch/helper.h                     |  5 +--
>   target/loongarch/insn_trans/trans_extra.c.inc | 14 ++++++++
>   .../insn_trans/trans_privileged.c.inc         | 36 +++++++++++++++++++
>   target/loongarch/internals.h                  |  2 ++
>   target/loongarch/op_helper.c                  | 12 +++++++
>   7 files changed, 93 insertions(+), 4 deletions(-)
>
> diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
> index 4c8f96bc3a..472e258f68 100644
> --- a/target/loongarch/cpu.c
> +++ b/target/loongarch/cpu.c
> @@ -18,7 +18,6 @@
>   #include "fpu/softfloat-helpers.h"
>   #include "cpu-csr.h"
>   #include "sysemu/reset.h"
> -#include "hw/loader.h"
>   
>   const char * const regnames[32] = {
>       "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
> @@ -82,6 +81,7 @@ static void loongarch_cpu_set_pc(CPUState *cs, vaddr value)
>       env->pc = value;
>   }
>   
> +#ifndef CONFIG_USER_ONLY
>   #include "hw/loongarch/virt.h"
>   
>   void loongarch_cpu_set_irq(void *opaque, int irq, int level)
> @@ -292,6 +292,7 @@ static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
>       }
>       return false;
>   }
> +#endif
>   
>   #ifdef CONFIG_TCG
>   static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
> @@ -306,6 +307,9 @@ static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
>   
>   static bool loongarch_cpu_has_work(CPUState *cs)
>   {
> +#ifdef CONFIG_USER_ONLY
> +    return true;
> +#else
>       LoongArchCPU *cpu = LOONGARCH_CPU(cs);
>       CPULoongArchState *env = &cpu->env;
>       bool has_work = false;
> @@ -316,6 +320,7 @@ static bool loongarch_cpu_has_work(CPUState *cs)
>       }
>   
>       return has_work;
> +#endif
>   }
>   
>   static void loongarch_la464_initfn(Object *obj)
> @@ -464,7 +469,9 @@ static void loongarch_cpu_reset(DeviceState *dev)
>           env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0);
>       }
>   
> +#ifndef CONFIG_USER_ONLY
>       env->pc = 0x1c000000;
> +#endif
>   
>       restore_fp_status(env);
>       cs->exception_index = -1;
> @@ -495,6 +502,7 @@ static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
>       lacc->parent_realize(dev, errp);
>   }
>   
> +#ifndef CONFIG_USER_ONLY
>   static void loongarch_qemu_write(void *opaque, hwaddr addr,
>                                    uint64_t val, unsigned size)
>   {
> @@ -529,13 +537,16 @@ static const MemoryRegionOps loongarch_qemu_ops = {
>           .max_access_size = 8,
>       },
>   };
> +#endif
>   
>   static void loongarch_cpu_init(Object *obj)
>   {
>       LoongArchCPU *cpu = LOONGARCH_CPU(obj);
> -    CPULoongArchState *env = &cpu->env;
>   
> +#ifdef CONFIG_USER_ONLY
>       cpu_set_cpustate_pointers(cpu);
> +#else
> +    CPULoongArchState *env = &cpu->env;
>       qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
>       timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
>                     &loongarch_constant_timer_cb, cpu);
> @@ -545,6 +556,7 @@ static void loongarch_cpu_init(Object *obj)
>       memory_region_init_io(&env->iocsr_mem, OBJECT(cpu), &loongarch_qemu_ops,
>                             NULL, "iocsr_misc", 0x428);
>       memory_region_add_subregion(&env->system_iocsr, 0, &env->iocsr_mem);
> +#endif
>   }
>   
>   static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
> @@ -612,18 +624,22 @@ static struct TCGCPUOps loongarch_tcg_ops = {
>       .initialize = loongarch_translate_init,
>       .synchronize_from_tb = loongarch_cpu_synchronize_from_tb,
>   
> +#ifndef CONFIG_USER_ONLY
>       .tlb_fill = loongarch_cpu_tlb_fill,
>       .cpu_exec_interrupt = loongarch_cpu_exec_interrupt,
>       .do_interrupt = loongarch_cpu_do_interrupt,
>       .do_transaction_failed = loongarch_cpu_do_transaction_failed,
> +#endif
>   };
>   #endif /* CONFIG_TCG */
>   
> +#ifndef CONFIG_USER_ONLY
>   #include "hw/core/sysemu-cpu-ops.h"
>   
>   static const struct SysemuCPUOps loongarch_sysemu_ops = {
>       .get_phys_page_debug = loongarch_cpu_get_phys_page_debug,
>   };
> +#endif
>   
>   static void loongarch_cpu_class_init(ObjectClass *c, void *data)
>   {
> @@ -639,8 +655,10 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data)
>       cc->has_work = loongarch_cpu_has_work;
>       cc->dump_state = loongarch_cpu_dump_state;
>       cc->set_pc = loongarch_cpu_set_pc;
> +#ifndef CONFIG_USER_ONLY
>       dc->vmsd = &vmstate_loongarch_cpu;
>       cc->sysemu_ops = &loongarch_sysemu_ops;
> +#endif
>       cc->disas_set_info = loongarch_cpu_disas_set_info;
>       cc->gdb_read_register = loongarch_cpu_gdb_read_register;
>       cc->gdb_write_register = loongarch_cpu_gdb_write_register;
> diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
> index 71a5036c3c..19eed2f0c1 100644
> --- a/target/loongarch/cpu.h
> +++ b/target/loongarch/cpu.h
> @@ -303,6 +303,7 @@ typedef struct CPUArchState {
>       uint64_t CSR_DERA;
>       uint64_t CSR_DSAVE;
>   
> +#ifndef CONFIG_USER_ONLY
>       LoongArchTLB  tlb[LOONGARCH_TLB_MAX];
>   
>       AddressSpace address_space_iocsr;
> @@ -310,6 +311,7 @@ typedef struct CPUArchState {
>       MemoryRegion iocsr_mem;
>       bool load_elf;
>       uint64_t elf_address;
> +#endif
>   } CPULoongArchState;
>   
>   /**
> @@ -360,12 +362,16 @@ struct LoongArchCPUClass {
>   
>   static inline int cpu_mmu_index(CPULoongArchState *env, bool ifetch)
>   {
> +#ifdef CONFIG_USER_ONLY
> +    return MMU_USER_IDX;
> +#else
>       uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
>   
>       if (!pg) {
>           return MMU_DA_IDX;
>       }
>       return FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV);
> +#endif
>   }
>   
>   static inline void cpu_get_tb_cpu_state(CPULoongArchState *env,
> diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
> index 85c11a60d4..ee42707868 100644
> --- a/target/loongarch/helper.h
> +++ b/target/loongarch/helper.h
> @@ -93,8 +93,7 @@ DEF_HELPER_2(frint_d, i64, env, i64)
>   
>   DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32)
>   
> -DEF_HELPER_1(rdtime_d, i64, env)
> -
> +#ifndef CONFIG_USER_ONLY
>   /* CSRs helper */
>   DEF_HELPER_1(csrrd_pgd, i64, env)
>   DEF_HELPER_1(csrrd_tval, i64, env)
> @@ -128,3 +127,5 @@ DEF_HELPER_4(lddir, tl, env, tl, tl, i32)
>   DEF_HELPER_4(ldpte, void, env, tl, tl, i32)
>   DEF_HELPER_1(ertn, void, env)
>   DEF_HELPER_1(idle, void, env)
> +DEF_HELPER_1(rdtime_d, i64, env)
> +#endif
> diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc
> index ad713cd61e..f1980497ac 100644
> --- a/target/loongarch/insn_trans/trans_extra.c.inc
> +++ b/target/loongarch/insn_trans/trans_extra.c.inc
> @@ -33,6 +33,7 @@ static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a)
>       return true;
>   }
>   
> +#ifndef CONFIG_USER_ONLY
>   static bool gen_rdtime(DisasContext *ctx, arg_rr *a,
>                          bool word, bool high)
>   {
> @@ -50,20 +51,33 @@ static bool gen_rdtime(DisasContext *ctx, arg_rr *a,
>   
>       return true;
>   }
> +#endif
>   
>   static bool trans_rdtimel_w(DisasContext *ctx, arg_rdtimel_w *a)
>   {
> +#ifdef CONFIG_USER_ONLY
> +    return cpu_get_host_ticks();
> +#else
>       return gen_rdtime(ctx, a, 1, 0);
> +#endif
>   }
>   
>   static bool trans_rdtimeh_w(DisasContext *ctx, arg_rdtimeh_w *a)
>   {
> +#ifdef CONFIG_USER_ONLY
> +    return cpu_get_host_ticks();
> +#else
This can't be right, we need to return only the high part for rdtimeh.w 
but I didn't see any such processing. I see ">> 32" in the target/riscv 
code so we want something like this here too...
>       return gen_rdtime(ctx, a, 1, 1);
> +#endif
>   }
>   
>   static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a)
>   {
> +#ifdef CONFIG_USER_ONLY
> +    return cpu_get_host_ticks();
> +#else
>       return gen_rdtime(ctx, a, 0, 0);
> +#endif
>   }
>   
>   static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a)
> diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc
> index 53596c4f77..9c4dcbfcfb 100644
> --- a/target/loongarch/insn_trans/trans_privileged.c.inc
> +++ b/target/loongarch/insn_trans/trans_privileged.c.inc
> @@ -7,6 +7,41 @@
>   
>   #include "cpu-csr.h"
>   
> +#ifdef CONFIG_USER_ONLY
> +
> +#define GEN_FALSE_TRANS(name)   \
> +static bool trans_##name(DisasContext *ctx, arg_##name * a)  \
> +{   \
> +    return false;   \
> +}
> +
> +GEN_FALSE_TRANS(csrrd)
> +GEN_FALSE_TRANS(csrwr)
> +GEN_FALSE_TRANS(csrxchg)
> +GEN_FALSE_TRANS(iocsrrd_b)
> +GEN_FALSE_TRANS(iocsrrd_h)
> +GEN_FALSE_TRANS(iocsrrd_w)
> +GEN_FALSE_TRANS(iocsrrd_d)
> +GEN_FALSE_TRANS(iocsrwr_b)
> +GEN_FALSE_TRANS(iocsrwr_h)
> +GEN_FALSE_TRANS(iocsrwr_w)
> +GEN_FALSE_TRANS(iocsrwr_d)
> +GEN_FALSE_TRANS(tlbsrch)
> +GEN_FALSE_TRANS(tlbrd)
> +GEN_FALSE_TRANS(tlbwr)
> +GEN_FALSE_TRANS(tlbfill)
> +GEN_FALSE_TRANS(tlbclr)
> +GEN_FALSE_TRANS(tlbflush)
> +GEN_FALSE_TRANS(invtlb)
> +GEN_FALSE_TRANS(cacop)
> +GEN_FALSE_TRANS(ldpte)
> +GEN_FALSE_TRANS(lddir)
> +GEN_FALSE_TRANS(ertn)
> +GEN_FALSE_TRANS(dbcl)
> +GEN_FALSE_TRANS(idle)
> +
> +#else
> +
>   typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env);
>   typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src);
>   
> @@ -464,3 +499,4 @@ static bool trans_idle(DisasContext *ctx, arg_idle *a)
>       ctx->base.is_jmp = DISAS_NORETURN;
>       return true;
>   }
> +#endif
> diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
> index 9d50fbdd81..ebca7a1a25 100644
> --- a/target/loongarch/internals.h
> +++ b/target/loongarch/internals.h
> @@ -33,6 +33,7 @@ const char *loongarch_exception_name(int32_t exception);
>   
>   void restore_fp_status(CPULoongArchState *env);
>   
> +#ifndef CONFIG_USER_ONLY
>   extern const VMStateDescription vmstate_loongarch_cpu;
>   
>   void loongarch_cpu_set_irq(void *opaque, int irq, int level);
> @@ -48,6 +49,7 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>                               bool probe, uintptr_t retaddr);
>   
>   hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
> +#endif
>   
>   int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n);
>   int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n);
> diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c
> index d87049851f..49fbd1343c 100644
> --- a/target/loongarch/op_helper.c
> +++ b/target/loongarch/op_helper.c
> @@ -49,14 +49,24 @@ target_ulong helper_bitswap(target_ulong v)
>   void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
>   {
>       if (rj > rk) {
> +#ifdef CONFIG_USER_ONLY
> +        cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
> +                              MMU_DATA_LOAD, true, GETPC());
> +#else
>           do_raise_exception(env, EXCCODE_ADEM, GETPC());
> +#endif
>       }
>   }
>   
>   void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
>   {
>       if (rj <= rk) {
> +#ifdef CONFIG_USER_ONLY
> +        cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
> +                              MMU_DATA_LOAD, true, GETPC());
> +#else
>           do_raise_exception(env, EXCCODE_ADEM, GETPC());
> +#endif
>       }
>   }
>   
> @@ -84,6 +94,7 @@ target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj)
>       return rj > 21 ? 0 : env->cpucfg[rj];
>   }
>   
> +#ifndef CONFIG_USER_ONLY
>   uint64_t helper_rdtime_d(CPULoongArchState *env)
>   {
>       uint64_t plv;
> @@ -131,3 +142,4 @@ void helper_idle(CPULoongArchState *env)
>       cs->halted = 1;
>       do_raise_exception(env, EXCP_HLT, 0);
>   }
> +#endif

The other parts seem to be good.

With the rdtime[lh].w bug fixed:

Reviewed-by: WANG Xuerui <git@xen0n.name>
Richard Henderson June 9, 2022, 6:42 p.m. UTC | #2
On 6/8/22 19:42, Song Gao wrote:
> diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
> index 85c11a60d4..ee42707868 100644
> --- a/target/loongarch/helper.h
> +++ b/target/loongarch/helper.h
> @@ -93,8 +93,7 @@ DEF_HELPER_2(frint_d, i64, env, i64)
>   
>   DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32)
>   
> -DEF_HELPER_1(rdtime_d, i64, env)
> -
> +#ifndef CONFIG_USER_ONLY
>   /* CSRs helper */
>   DEF_HELPER_1(csrrd_pgd, i64, env)
>   DEF_HELPER_1(csrrd_tval, i64, env)
> @@ -128,3 +127,5 @@ DEF_HELPER_4(lddir, tl, env, tl, tl, i32)
>   DEF_HELPER_4(ldpte, void, env, tl, tl, i32)
>   DEF_HELPER_1(ertn, void, env)
>   DEF_HELPER_1(idle, void, env)
> +DEF_HELPER_1(rdtime_d, i64, env)
> +#endif

This is wrong.

>   static bool trans_rdtimel_w(DisasContext *ctx, arg_rdtimel_w *a)
>   {
> +#ifdef CONFIG_USER_ONLY
> +    return cpu_get_host_ticks();

This is very wrong.  You're calling cpu_get_host_ticks at translation time.
There are no changes required during translation.

You should in fact be calling cpu_get_host_ticks in helper_rdtime_d.

>   void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
>   {
>       if (rj > rk) {
> +#ifdef CONFIG_USER_ONLY
> +        cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
> +                              MMU_DATA_LOAD, true, GETPC());
> +#else
>           do_raise_exception(env, EXCCODE_ADEM, GETPC());
> +#endif

This change is wrong.  First, the kernel's do_ade raises SIGBUS.  Second, GETPC() is a 
host address, not a guest address.  Third, this highlights the fact that the existing 
system code is wrong, and should be setting badvaddr.

You need to
(1) set badvaddr here, and then
(2) handle EXCCODE_ADEM in linux-user/loongarch/cpu_loop.c to 
force_fix_fault(TARGET_SIGBUS, TARGET_BUS_ADRERR, env->badvaddr).

>   void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
>   {
>       if (rj <= rk) {
> +#ifdef CONFIG_USER_ONLY
> +        cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
> +                              MMU_DATA_LOAD, true, GETPC());
> +#else
>           do_raise_exception(env, EXCCODE_ADEM, GETPC());
> +#endif
>       }
>   }

Likewise.


r~
gaosong June 10, 2022, 6:53 a.m. UTC | #3
Hi Richard,

On 2022/6/10 上午2:42, Richard Henderson wrote:
>>   void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, 
>> target_ulong rk)
>>   {
>>       if (rj > rk) {
>> +#ifdef CONFIG_USER_ONLY
>> +        cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
>> +                              MMU_DATA_LOAD, true, GETPC());
>> +#else
>>           do_raise_exception(env, EXCCODE_ADEM, GETPC());
>> +#endif
>
> This change is wrong.  First, the kernel's do_ade raises SIGBUS. 
> Second, GETPC() is a host address, not a guest address.  Third, this 
> highlights the fact that the existing system code is wrong, and should 
> be setting badvaddr.
>
> You need to
> (1) set badvaddr here, and then
> (2) handle EXCCODE_ADEM in linux-user/loongarch/cpu_loop.c to 
> force_fix_fault(TARGET_SIGBUS, TARGET_BUS_ADRERR, env->badvaddr). 

badvaddr is env->pc or base->pc_next?   and we just raise exception on 
use-mode,

like this

   void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, 
target_ulong rk)
   {
       if (rj > rk) {

          env->badvaddr = env->pc;

#ifdef CONFIG_USER_ONLY
           do_raise_exception(env, EXCCODE_ADEM, GETPC());
#endif

       }

}

cpu_loop.c

         case EXCCODE_ADEM:
             force_sig_fault(TARGET_SIGBUS, TARGET_BUS_ADRERR, 
env->badvaddr);
             break;

Thanks.
Song Gao
Richard Henderson June 10, 2022, 10:45 p.m. UTC | #4
On 6/9/22 23:53, gaosong wrote:
> Hi Richard,
> 
> On 2022/6/10 上午2:42, Richard Henderson wrote:
>>>   void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
>>>   {
>>>       if (rj > rk) {
>>> +#ifdef CONFIG_USER_ONLY
>>> +        cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
>>> +                              MMU_DATA_LOAD, true, GETPC());
>>> +#else
>>>           do_raise_exception(env, EXCCODE_ADEM, GETPC());
>>> +#endif
>>
>> This change is wrong.  First, the kernel's do_ade raises SIGBUS. Second, GETPC() is a 
>> host address, not a guest address.  Third, this highlights the fact that the existing 
>> system code is wrong, and should be setting badvaddr.
>>
>> You need to
>> (1) set badvaddr here, and then
>> (2) handle EXCCODE_ADEM in linux-user/loongarch/cpu_loop.c to 
>> force_fix_fault(TARGET_SIGBUS, TARGET_BUS_ADRERR, env->badvaddr). 
> 
> badvaddr is env->pc or base->pc_next?

I don't know.  The documentation for the ASRT{LE,GD}.D instructions is incomplete.

However, from the kernel code,

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/loongarch/kernel/traps.c#n360

I can see that the kernel expects *some* value to be set there.  Given that this is the 
same trap used by the bound check memory accesses, I presume that badvaddr is related to 
the memory access not the PC.  So I would expect badvaddr to be RJ.

But that is a guess.  Please check with your hardware engineers.


r~
gaosong June 11, 2022, 3:10 a.m. UTC | #5
On 2022/6/11 上午6:45, Richard Henderson wrote:
> On 6/9/22 23:53, gaosong wrote:
>> Hi Richard,
>>
>> On 2022/6/10 上午2:42, Richard Henderson wrote:
>>>>   void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, 
>>>> target_ulong rk)
>>>>   {
>>>>       if (rj > rk) {
>>>> +#ifdef CONFIG_USER_ONLY
>>>> +        cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
>>>> +                              MMU_DATA_LOAD, true, GETPC());
>>>> +#else
>>>>           do_raise_exception(env, EXCCODE_ADEM, GETPC());
>>>> +#endif
>>>
>>> This change is wrong.  First, the kernel's do_ade raises SIGBUS. 
>>> Second, GETPC() is a host address, not a guest address.  Third, this 
>>> highlights the fact that the existing system code is wrong, and 
>>> should be setting badvaddr.
>>>
>>> You need to
>>> (1) set badvaddr here, and then
>>> (2) handle EXCCODE_ADEM in linux-user/loongarch/cpu_loop.c to 
>>> force_fix_fault(TARGET_SIGBUS, TARGET_BUS_ADRERR, env->badvaddr). 
>>
>> badvaddr is env->pc or base->pc_next?
>
> I don't know.  The documentation for the ASRT{LE,GD}.D instructions is 
> incomplete.
>
> However, from the kernel code,
>
> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/loongarch/kernel/traps.c#n360 
>
>
> I can see that the kernel expects *some* value to be set there.  Given 
> that this is the same trap used by the bound check memory accesses, I 
> presume that badvaddr is related to the memory access not the PC.  So 
> I would expect badvaddr to be RJ.
>
> But that is a guess.  Please check with your hardware engineers.

Thanks you,


I had tested asrtgt.d on hardware.  the log is :

the gdb log

(gdb) info registers
                   zero               ra tp               sp
R0   0000000000000000 000000fff7e7c774 000000fff7ffef20 000000ffffff6940
                     a0               a1 a2               a3
R4   0000000000000001 000000ffffff6a88 000000ffffff6a98 000000fff7fbc4b0
                     a4               a5 a6               a7
R8   0000000000000000 000000fff7fe6f70 000000ffffff6a80 0000000000000080
                     t0               t1 t2               t3
R12  0000000000000000 0000000000000000 0000000000000000 000000fff7fbeeb8
                     t4               t5 t6               t7
R16  000000fff7fbdd40 000000fff7fbdd40 7f7f7f7f7f7f7f7f 0000000000000000
                     t8                x fp               s0
R20  ffffff0000000000 0000000000000000 000000ffffff6960 0000000000000000
                     s1               s2 s3               s4
R24  0000000120000658 000000aaaabd9c60 0000000000000000 000000aaaabe9b50
                     s5               s6 s7               s8
R28  000000aaaabd9c60 0000000000000000 0000000000000000 000000aaaabcfa08
pc             0x120000638         0x120000638 <main+32>
badvaddr       0xfff7e935c8        0xfff7e935c8 <__cxa_atexit>
(gdb) stepi

Program received signal SIGSYS, Bad system call.
0x0000000120000638 in main () at asrtle.c:8
8        asm volatile("asrtgt.d  %0,%1\n\t"
(gdb) info registers
                   zero               ra tp               sp
R0   0000000000000000 000000fff7e7c774 000000fff7ffef20 000000ffffff6940
                     a0               a1 a2               a3
R4   0000000000000001 000000ffffff6a88 000000ffffff6a98 000000fff7fbc4b0
                     a4               a5 a6               a7
R8   0000000000000000 000000fff7fe6f70 000000ffffff6a80 0000000000000080
                     t0               t1 t2               t3
R12  0000000000000000 0000000000000000 0000000000000000 000000fff7fbeeb8
                     t4               t5 t6               t7
R16  000000fff7fbdd40 000000fff7fbdd40 7f7f7f7f7f7f7f7f 0000000000000000
                     t8                x fp               s0
R20  ffffff0000000000 0000000000000000 000000ffffff6960 0000000000000000
                     s1               s2 s3               s4
R24  0000000120000658 000000aaaabd9c60 0000000000000000 000000aaaabe9b50
                     s5               s6 s7               s8
R28  000000aaaabd9c60 0000000000000000 0000000000000000 000000aaaabcfa08
pc             0x120000638         0x120000638 <main+32>
badvaddr       0x120000638         0x120000638 <main+32>
(gdb) disas
Dump of assembler code for function main:
    0x0000000120000618 <+0>:    addi.d    $r3,$r3,-32(0xfe0)
    0x000000012000061c <+4>:    st.d    $r22,$r3,24(0x18)
    0x0000000120000620 <+8>:    addi.d    $r22,$r3,32(0x20)
    0x0000000120000624 <+12>:    addi.w    $r12,$r0,23(0x17)
    0x0000000120000628 <+16>:    st.d    $r12,$r22,-24(0xfe8)
    0x000000012000062c <+20>:    st.d    $r0,$r22,-32(0xfe0)
    0x0000000120000630 <+24>:    ld.d    $r12,$r22,-32(0xfe0)
    0x0000000120000634 <+28>:    ld.d    $r13,$r22,-32(0xfe0)
=> 0x0000000120000638 <+32>:    asrtgt.d    $r12,$r12
    0x000000012000063c <+36>:    st.d    $r12,$r22,-24(0xfe8)
    0x0000000120000640 <+40>:    move    $r12,$r0
    0x0000000120000644 <+44>:    move    $r4,$r12
    0x0000000120000648 <+48>:    ld.d    $r22,$r3,24(0x18)
    0x000000012000064c <+52>:    addi.d    $r3,$r3,32(0x20)
    0x0000000120000650 <+56>:    jirl    $r0,$r1,0
End of assembler dump.

dmesg :

[151125.931122] pid:32782 [a.out] Caught reserved exception 10 - should 
not happen


So

badvaddr is the PC,

exitsting system code is BCE, (10)

And I think the change like this:

void helper_asrtle_d(CPULoongArchState *env,  target_ulong rj, 
target_ulong  rk)

{

      if (rj > rk) {

         env->badvaddr = env->pc;

         do_raise_exception(env, EXCCODE_BCE,  env->badvaddr);

      }

}

cpu_loop.c

case EXCCODE_BCE:

     force_sig_fault(TARGET_SIGSYS,  TARGET_SI_KERNEL, env->badvaddr)


Thanks.
Song Gao
Richard Henderson June 11, 2022, 4:06 p.m. UTC | #6
On 6/10/22 20:10, gaosong wrote:
> pc             0x120000638         0x120000638 <main+32>
> badvaddr       0x120000638         0x120000638 <main+32>
...
> So badvaddr is the PC,

Yes.

> void helper_asrtle_d(CPULoongArchState *env,  target_ulong rj, target_ulong  rk)
> {
>       if (rj > rk) {
>          env->badvaddr = env->pc;
>          do_raise_exception(env, EXCCODE_BCE,  env->badvaddr);
>       }
> }

Well, not quite.  The value of env->pc is not current; it is too expensive to update all 
of the time.  We need to recover that value by using TCG unwinding, e.g.:

     if (rj > rk) {
         cpu_restore_state(env_cpu(env), GETPC(), true);
         env->badvaddr = env->pc;

However,

         do_raise_exception(env, EXCCODE_ADEM, GETPC());

expects to do it's own cpu_restore_state via cpu_loop_exit_restore(), and we should not do 
that twice.

Therefore, since the value of badvaddr is something that we can more easily recover later 
than earlier, we should move the setting of badvaddr for ADEM to loongarch_cpu_do_interrupt():

     case EXCCODE_ADEM:

         env->badvaddr = env->pc;
         cause = cs->exception_index;
         break;

It is probably worthwhile to check how many other exceptions should be having the same effect.


r~
gaosong June 13, 2022, 3:50 a.m. UTC | #7
On 2022/6/12 上午12:06, Richard Henderson wrote:
>> void helper_asrtle_d(CPULoongArchState *env,  target_ulong rj, 
>> target_ulong  rk)
>> {
>>       if (rj > rk) {
>>          env->badvaddr = env->pc;
>>          do_raise_exception(env, EXCCODE_BCE, env->badvaddr);
>>       }
>> }
>
> Well, not quite.  The value of env->pc is not current; it is too 
> expensive to update all of the time.  We need to recover that value by 
> using TCG unwinding, e.g.:
>
>     if (rj > rk) {
>         cpu_restore_state(env_cpu(env), GETPC(), true);
>         env->badvaddr = env->pc;
>
> However,
>
>         do_raise_exception(env, EXCCODE_ADEM, GETPC());
>
> expects to do it's own cpu_restore_state via cpu_loop_exit_restore(), 
> and we should not do that twice.
>
> Therefore, since the value of badvaddr is something that we can more 
> easily recover later than earlier, we should move the setting of 
> badvaddr for ADEM to loongarch_cpu_do_interrupt():
>
>     case EXCCODE_ADEM:
>
>         env->badvaddr = env->pc;
>         cause = cs->exception_index;
>         break;
>
> It is probably worthwhile to check how many other exceptions should be 
> having the same effect.
>
Thank you for your advice.
like this:

  void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, 
target_ulong rk)
  {
+    CPUState *cs = env_cpu(env);
+
      if (rj > rk) {
-        env->badaddr = env->pc;
-        do_raise_exception(env, EXCCODE_BCE, env->badaddr);
+        cpu_restore_state(cs, GETPC(), true);
+        cs->exception_index = EXCCODE_BCE;
+        cpu_loop_exit(cs);
      }
  }

cpu.c


      case EXCCODE_ADEM:
+    case EXCCODE_BCE:
      case EXCCODE_SYS:
      case EXCCODE_BRK:
+    case EXCCODE_INE:
+    case EXCCODE_IPE:
+    case EXCCODE_FPE:
+        env->badvaddr = env->pc;
+        QEMU_FALLTHROUGH;
      case EXCCODE_PIL:
      case EXCCODE_PIS:
      case EXCCODE_PME:
      case EXCCODE_PNR:
      case EXCCODE_PNX:
      case EXCCODE_PPI:
-    case EXCCODE_INE:
-    case EXCCODE_IPE:
-    case EXCCODE_FPE:
          cause = cs->exception_index;
          break;

Thanks
Song Gao
Richard Henderson June 13, 2022, 4:05 p.m. UTC | #8
On 6/12/22 20:50, gaosong wrote:
> Thank you for your advice.
> like this:
> 
>   void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
>   {
> +    CPUState *cs = env_cpu(env);
> +
>       if (rj > rk) {
> -        env->badaddr = env->pc;
> -        do_raise_exception(env, EXCCODE_BCE, env->badaddr);
> +        cpu_restore_state(cs, GETPC(), true);
> +        cs->exception_index = EXCCODE_BCE;
> +        cpu_loop_exit(cs);
>       }
>   }

This is not required -- better to continue using do_raise_exception.

> 
> cpu.c
> 
> 
>       case EXCCODE_ADEM:
> +    case EXCCODE_BCE:
>       case EXCCODE_SYS:
>       case EXCCODE_BRK:
> +    case EXCCODE_INE:
> +    case EXCCODE_IPE:
> +    case EXCCODE_FPE:
> +        env->badvaddr = env->pc;
> +        QEMU_FALLTHROUGH;
>       case EXCCODE_PIL:
>       case EXCCODE_PIS:
>       case EXCCODE_PME:
>       case EXCCODE_PNR:
>       case EXCCODE_PNX:
>       case EXCCODE_PPI:
> -    case EXCCODE_INE:
> -    case EXCCODE_IPE:
> -    case EXCCODE_FPE:
>           cause = cs->exception_index;
>           break;

But this looks correct, and sufficient to solve the problem.


r~
diff mbox series

Patch

diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 4c8f96bc3a..472e258f68 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -18,7 +18,6 @@ 
 #include "fpu/softfloat-helpers.h"
 #include "cpu-csr.h"
 #include "sysemu/reset.h"
-#include "hw/loader.h"
 
 const char * const regnames[32] = {
     "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
@@ -82,6 +81,7 @@  static void loongarch_cpu_set_pc(CPUState *cs, vaddr value)
     env->pc = value;
 }
 
+#ifndef CONFIG_USER_ONLY
 #include "hw/loongarch/virt.h"
 
 void loongarch_cpu_set_irq(void *opaque, int irq, int level)
@@ -292,6 +292,7 @@  static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
     }
     return false;
 }
+#endif
 
 #ifdef CONFIG_TCG
 static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
@@ -306,6 +307,9 @@  static void loongarch_cpu_synchronize_from_tb(CPUState *cs,
 
 static bool loongarch_cpu_has_work(CPUState *cs)
 {
+#ifdef CONFIG_USER_ONLY
+    return true;
+#else
     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
     CPULoongArchState *env = &cpu->env;
     bool has_work = false;
@@ -316,6 +320,7 @@  static bool loongarch_cpu_has_work(CPUState *cs)
     }
 
     return has_work;
+#endif
 }
 
 static void loongarch_la464_initfn(Object *obj)
@@ -464,7 +469,9 @@  static void loongarch_cpu_reset(DeviceState *dev)
         env->CSR_DMW[n] = FIELD_DP64(env->CSR_DMW[n], CSR_DMW, PLV3, 0);
     }
 
+#ifndef CONFIG_USER_ONLY
     env->pc = 0x1c000000;
+#endif
 
     restore_fp_status(env);
     cs->exception_index = -1;
@@ -495,6 +502,7 @@  static void loongarch_cpu_realizefn(DeviceState *dev, Error **errp)
     lacc->parent_realize(dev, errp);
 }
 
+#ifndef CONFIG_USER_ONLY
 static void loongarch_qemu_write(void *opaque, hwaddr addr,
                                  uint64_t val, unsigned size)
 {
@@ -529,13 +537,16 @@  static const MemoryRegionOps loongarch_qemu_ops = {
         .max_access_size = 8,
     },
 };
+#endif
 
 static void loongarch_cpu_init(Object *obj)
 {
     LoongArchCPU *cpu = LOONGARCH_CPU(obj);
-    CPULoongArchState *env = &cpu->env;
 
+#ifdef CONFIG_USER_ONLY
     cpu_set_cpustate_pointers(cpu);
+#else
+    CPULoongArchState *env = &cpu->env;
     qdev_init_gpio_in(DEVICE(cpu), loongarch_cpu_set_irq, N_IRQS);
     timer_init_ns(&cpu->timer, QEMU_CLOCK_VIRTUAL,
                   &loongarch_constant_timer_cb, cpu);
@@ -545,6 +556,7 @@  static void loongarch_cpu_init(Object *obj)
     memory_region_init_io(&env->iocsr_mem, OBJECT(cpu), &loongarch_qemu_ops,
                           NULL, "iocsr_misc", 0x428);
     memory_region_add_subregion(&env->system_iocsr, 0, &env->iocsr_mem);
+#endif
 }
 
 static ObjectClass *loongarch_cpu_class_by_name(const char *cpu_model)
@@ -612,18 +624,22 @@  static struct TCGCPUOps loongarch_tcg_ops = {
     .initialize = loongarch_translate_init,
     .synchronize_from_tb = loongarch_cpu_synchronize_from_tb,
 
+#ifndef CONFIG_USER_ONLY
     .tlb_fill = loongarch_cpu_tlb_fill,
     .cpu_exec_interrupt = loongarch_cpu_exec_interrupt,
     .do_interrupt = loongarch_cpu_do_interrupt,
     .do_transaction_failed = loongarch_cpu_do_transaction_failed,
+#endif
 };
 #endif /* CONFIG_TCG */
 
+#ifndef CONFIG_USER_ONLY
 #include "hw/core/sysemu-cpu-ops.h"
 
 static const struct SysemuCPUOps loongarch_sysemu_ops = {
     .get_phys_page_debug = loongarch_cpu_get_phys_page_debug,
 };
+#endif
 
 static void loongarch_cpu_class_init(ObjectClass *c, void *data)
 {
@@ -639,8 +655,10 @@  static void loongarch_cpu_class_init(ObjectClass *c, void *data)
     cc->has_work = loongarch_cpu_has_work;
     cc->dump_state = loongarch_cpu_dump_state;
     cc->set_pc = loongarch_cpu_set_pc;
+#ifndef CONFIG_USER_ONLY
     dc->vmsd = &vmstate_loongarch_cpu;
     cc->sysemu_ops = &loongarch_sysemu_ops;
+#endif
     cc->disas_set_info = loongarch_cpu_disas_set_info;
     cc->gdb_read_register = loongarch_cpu_gdb_read_register;
     cc->gdb_write_register = loongarch_cpu_gdb_write_register;
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 71a5036c3c..19eed2f0c1 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -303,6 +303,7 @@  typedef struct CPUArchState {
     uint64_t CSR_DERA;
     uint64_t CSR_DSAVE;
 
+#ifndef CONFIG_USER_ONLY
     LoongArchTLB  tlb[LOONGARCH_TLB_MAX];
 
     AddressSpace address_space_iocsr;
@@ -310,6 +311,7 @@  typedef struct CPUArchState {
     MemoryRegion iocsr_mem;
     bool load_elf;
     uint64_t elf_address;
+#endif
 } CPULoongArchState;
 
 /**
@@ -360,12 +362,16 @@  struct LoongArchCPUClass {
 
 static inline int cpu_mmu_index(CPULoongArchState *env, bool ifetch)
 {
+#ifdef CONFIG_USER_ONLY
+    return MMU_USER_IDX;
+#else
     uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
 
     if (!pg) {
         return MMU_DA_IDX;
     }
     return FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV);
+#endif
 }
 
 static inline void cpu_get_tb_cpu_state(CPULoongArchState *env,
diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h
index 85c11a60d4..ee42707868 100644
--- a/target/loongarch/helper.h
+++ b/target/loongarch/helper.h
@@ -93,8 +93,7 @@  DEF_HELPER_2(frint_d, i64, env, i64)
 
 DEF_HELPER_FLAGS_2(set_rounding_mode, TCG_CALL_NO_RWG, void, env, i32)
 
-DEF_HELPER_1(rdtime_d, i64, env)
-
+#ifndef CONFIG_USER_ONLY
 /* CSRs helper */
 DEF_HELPER_1(csrrd_pgd, i64, env)
 DEF_HELPER_1(csrrd_tval, i64, env)
@@ -128,3 +127,5 @@  DEF_HELPER_4(lddir, tl, env, tl, tl, i32)
 DEF_HELPER_4(ldpte, void, env, tl, tl, i32)
 DEF_HELPER_1(ertn, void, env)
 DEF_HELPER_1(idle, void, env)
+DEF_HELPER_1(rdtime_d, i64, env)
+#endif
diff --git a/target/loongarch/insn_trans/trans_extra.c.inc b/target/loongarch/insn_trans/trans_extra.c.inc
index ad713cd61e..f1980497ac 100644
--- a/target/loongarch/insn_trans/trans_extra.c.inc
+++ b/target/loongarch/insn_trans/trans_extra.c.inc
@@ -33,6 +33,7 @@  static bool trans_asrtgt_d(DisasContext *ctx, arg_asrtgt_d * a)
     return true;
 }
 
+#ifndef CONFIG_USER_ONLY
 static bool gen_rdtime(DisasContext *ctx, arg_rr *a,
                        bool word, bool high)
 {
@@ -50,20 +51,33 @@  static bool gen_rdtime(DisasContext *ctx, arg_rr *a,
 
     return true;
 }
+#endif
 
 static bool trans_rdtimel_w(DisasContext *ctx, arg_rdtimel_w *a)
 {
+#ifdef CONFIG_USER_ONLY
+    return cpu_get_host_ticks();
+#else
     return gen_rdtime(ctx, a, 1, 0);
+#endif
 }
 
 static bool trans_rdtimeh_w(DisasContext *ctx, arg_rdtimeh_w *a)
 {
+#ifdef CONFIG_USER_ONLY
+    return cpu_get_host_ticks();
+#else
     return gen_rdtime(ctx, a, 1, 1);
+#endif
 }
 
 static bool trans_rdtime_d(DisasContext *ctx, arg_rdtime_d *a)
 {
+#ifdef CONFIG_USER_ONLY
+    return cpu_get_host_ticks();
+#else
     return gen_rdtime(ctx, a, 0, 0);
+#endif
 }
 
 static bool trans_cpucfg(DisasContext *ctx, arg_cpucfg *a)
diff --git a/target/loongarch/insn_trans/trans_privileged.c.inc b/target/loongarch/insn_trans/trans_privileged.c.inc
index 53596c4f77..9c4dcbfcfb 100644
--- a/target/loongarch/insn_trans/trans_privileged.c.inc
+++ b/target/loongarch/insn_trans/trans_privileged.c.inc
@@ -7,6 +7,41 @@ 
 
 #include "cpu-csr.h"
 
+#ifdef CONFIG_USER_ONLY
+
+#define GEN_FALSE_TRANS(name)   \
+static bool trans_##name(DisasContext *ctx, arg_##name * a)  \
+{   \
+    return false;   \
+}
+
+GEN_FALSE_TRANS(csrrd)
+GEN_FALSE_TRANS(csrwr)
+GEN_FALSE_TRANS(csrxchg)
+GEN_FALSE_TRANS(iocsrrd_b)
+GEN_FALSE_TRANS(iocsrrd_h)
+GEN_FALSE_TRANS(iocsrrd_w)
+GEN_FALSE_TRANS(iocsrrd_d)
+GEN_FALSE_TRANS(iocsrwr_b)
+GEN_FALSE_TRANS(iocsrwr_h)
+GEN_FALSE_TRANS(iocsrwr_w)
+GEN_FALSE_TRANS(iocsrwr_d)
+GEN_FALSE_TRANS(tlbsrch)
+GEN_FALSE_TRANS(tlbrd)
+GEN_FALSE_TRANS(tlbwr)
+GEN_FALSE_TRANS(tlbfill)
+GEN_FALSE_TRANS(tlbclr)
+GEN_FALSE_TRANS(tlbflush)
+GEN_FALSE_TRANS(invtlb)
+GEN_FALSE_TRANS(cacop)
+GEN_FALSE_TRANS(ldpte)
+GEN_FALSE_TRANS(lddir)
+GEN_FALSE_TRANS(ertn)
+GEN_FALSE_TRANS(dbcl)
+GEN_FALSE_TRANS(idle)
+
+#else
+
 typedef void (*GenCSRRead)(TCGv dest, TCGv_ptr env);
 typedef void (*GenCSRWrite)(TCGv dest, TCGv_ptr env, TCGv src);
 
@@ -464,3 +499,4 @@  static bool trans_idle(DisasContext *ctx, arg_idle *a)
     ctx->base.is_jmp = DISAS_NORETURN;
     return true;
 }
+#endif
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index 9d50fbdd81..ebca7a1a25 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -33,6 +33,7 @@  const char *loongarch_exception_name(int32_t exception);
 
 void restore_fp_status(CPULoongArchState *env);
 
+#ifndef CONFIG_USER_ONLY
 extern const VMStateDescription vmstate_loongarch_cpu;
 
 void loongarch_cpu_set_irq(void *opaque, int irq, int level);
@@ -48,6 +49,7 @@  bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                             bool probe, uintptr_t retaddr);
 
 hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
+#endif
 
 int loongarch_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n);
 int loongarch_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n);
diff --git a/target/loongarch/op_helper.c b/target/loongarch/op_helper.c
index d87049851f..49fbd1343c 100644
--- a/target/loongarch/op_helper.c
+++ b/target/loongarch/op_helper.c
@@ -49,14 +49,24 @@  target_ulong helper_bitswap(target_ulong v)
 void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
 {
     if (rj > rk) {
+#ifdef CONFIG_USER_ONLY
+        cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
+                              MMU_DATA_LOAD, true, GETPC());
+#else
         do_raise_exception(env, EXCCODE_ADEM, GETPC());
+#endif
     }
 }
 
 void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk)
 {
     if (rj <= rk) {
+#ifdef CONFIG_USER_ONLY
+        cpu_loop_exit_sigsegv(env_cpu(env), GETPC(),
+                              MMU_DATA_LOAD, true, GETPC());
+#else
         do_raise_exception(env, EXCCODE_ADEM, GETPC());
+#endif
     }
 }
 
@@ -84,6 +94,7 @@  target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj)
     return rj > 21 ? 0 : env->cpucfg[rj];
 }
 
+#ifndef CONFIG_USER_ONLY
 uint64_t helper_rdtime_d(CPULoongArchState *env)
 {
     uint64_t plv;
@@ -131,3 +142,4 @@  void helper_idle(CPULoongArchState *env)
     cs->halted = 1;
     do_raise_exception(env, EXCP_HLT, 0);
 }
+#endif