1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * LoongArch emulation helpers for CSRs 4 * 5 * Copyright (c) 2021 Loongson Technology Corporation Limited 6 */ 7 8 #include "qemu/osdep.h" 9 #include "qemu/log.h" 10 #include "qemu/main-loop.h" 11 #include "cpu.h" 12 #include "internals.h" 13 #include "qemu/host-utils.h" 14 #include "exec/helper-proto.h" 15 #include "exec/cputlb.h" 16 #include "exec/cpu_ldst.h" 17 #include "hw/irq.h" 18 #include "cpu-csr.h" 19 20 target_ulong helper_csrwr_stlbps(CPULoongArchState *env, target_ulong val) 21 { 22 int64_t old_v = env->CSR_STLBPS; 23 24 /* 25 * The real hardware only supports the min tlb_ps is 12 26 * tlb_ps=0 may cause undefined-behavior. 27 */ 28 uint8_t tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); 29 if (!check_ps(env, tlb_ps)) { 30 qemu_log_mask(LOG_GUEST_ERROR, 31 "Attempted set ps %d\n", tlb_ps); 32 } 33 return old_v; 34 } 35 36 target_ulong helper_csrrd_pgd(CPULoongArchState *env) 37 { 38 int64_t v; 39 40 if (env->CSR_TLBRERA & 0x1) { 41 v = env->CSR_TLBRBADV; 42 } else { 43 v = env->CSR_BADV; 44 } 45 46 if ((v >> 63) & 0x1) { 47 v = env->CSR_PGDH; 48 } else { 49 v = env->CSR_PGDL; 50 } 51 52 return v; 53 } 54 55 target_ulong helper_csrrd_cpuid(CPULoongArchState *env) 56 { 57 LoongArchCPU *lac = env_archcpu(env); 58 59 env->CSR_CPUID = CPU(lac)->cpu_index; 60 61 return env->CSR_CPUID; 62 } 63 64 target_ulong helper_csrrd_tval(CPULoongArchState *env) 65 { 66 LoongArchCPU *cpu = env_archcpu(env); 67 68 return cpu_loongarch_get_constant_timer_ticks(cpu); 69 } 70 71 target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val) 72 { 73 int64_t old_v = env->CSR_ESTAT; 74 75 /* Only IS[1:0] can be written */ 76 env->CSR_ESTAT = deposit64(env->CSR_ESTAT, 0, 2, val); 77 78 return old_v; 79 } 80 81 target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val) 82 { 83 int64_t old_v = env->CSR_ASID; 84 85 /* Only ASID filed of CSR_ASID can be written */ 86 env->CSR_ASID = deposit64(env->CSR_ASID, 0, 10, val); 87 if (old_v != env->CSR_ASID) { 88 tlb_flush(env_cpu(env)); 89 } 90 return old_v; 91 } 92 93 target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val) 94 { 95 LoongArchCPU *cpu = env_archcpu(env); 96 int64_t old_v = env->CSR_TCFG; 97 98 cpu_loongarch_store_constant_timer_config(cpu, val); 99 100 return old_v; 101 } 102 103 target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val) 104 { 105 LoongArchCPU *cpu = env_archcpu(env); 106 int64_t old_v = 0; 107 108 if (val & 0x1) { 109 bql_lock(); 110 loongarch_cpu_set_irq(cpu, IRQ_TIMER, 0); 111 bql_unlock(); 112 } 113 return old_v; 114 } 115 116 target_ulong helper_csrwr_pwcl(CPULoongArchState *env, target_ulong val) 117 { 118 int shift, ptbase; 119 int64_t old_v = env->CSR_PWCL; 120 121 /* 122 * The real hardware only supports 64bit PTE width now, 128bit or others 123 * treated as illegal. 124 */ 125 shift = FIELD_EX64(val, CSR_PWCL, PTEWIDTH); 126 ptbase = FIELD_EX64(val, CSR_PWCL, PTBASE); 127 if (shift) { 128 qemu_log_mask(LOG_GUEST_ERROR, 129 "Attempted set pte width with %d bit\n", 64 << shift); 130 val = FIELD_DP64(val, CSR_PWCL, PTEWIDTH, 0); 131 } 132 if (!check_ps(env, ptbase)) { 133 qemu_log_mask(LOG_GUEST_ERROR, 134 "Attrmpted set ptbase 2^%d\n", ptbase); 135 } 136 env->CSR_PWCL =val; 137 return old_v; 138 } 139