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 "accel/tcg/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 } else { 33 /* Only update PS field, reserved bit keeps zero */ 34 env->CSR_STLBPS = FIELD_DP64(old_v, CSR_STLBPS, PS, tlb_ps); 35 } 36 37 return old_v; 38 } 39 40 target_ulong helper_csrrd_pgd(CPULoongArchState *env) 41 { 42 int64_t v; 43 44 if (env->CSR_TLBRERA & 0x1) { 45 v = env->CSR_TLBRBADV; 46 } else { 47 v = env->CSR_BADV; 48 } 49 50 if ((v >> 63) & 0x1) { 51 v = env->CSR_PGDH; 52 } else { 53 v = env->CSR_PGDL; 54 } 55 56 return v; 57 } 58 59 target_ulong helper_csrrd_cpuid(CPULoongArchState *env) 60 { 61 LoongArchCPU *lac = env_archcpu(env); 62 63 env->CSR_CPUID = CPU(lac)->cpu_index; 64 65 return env->CSR_CPUID; 66 } 67 68 target_ulong helper_csrrd_tval(CPULoongArchState *env) 69 { 70 LoongArchCPU *cpu = env_archcpu(env); 71 72 return cpu_loongarch_get_constant_timer_ticks(cpu); 73 } 74 75 target_ulong helper_csrwr_estat(CPULoongArchState *env, target_ulong val) 76 { 77 int64_t old_v = env->CSR_ESTAT; 78 79 /* Only IS[1:0] can be written */ 80 env->CSR_ESTAT = deposit64(env->CSR_ESTAT, 0, 2, val); 81 82 return old_v; 83 } 84 85 target_ulong helper_csrwr_asid(CPULoongArchState *env, target_ulong val) 86 { 87 int64_t old_v = env->CSR_ASID; 88 89 /* Only ASID filed of CSR_ASID can be written */ 90 env->CSR_ASID = deposit64(env->CSR_ASID, 0, 10, val); 91 if (old_v != env->CSR_ASID) { 92 tlb_flush(env_cpu(env)); 93 } 94 return old_v; 95 } 96 97 target_ulong helper_csrwr_tcfg(CPULoongArchState *env, target_ulong val) 98 { 99 LoongArchCPU *cpu = env_archcpu(env); 100 int64_t old_v = env->CSR_TCFG; 101 102 cpu_loongarch_store_constant_timer_config(cpu, val); 103 104 return old_v; 105 } 106 107 target_ulong helper_csrwr_ticlr(CPULoongArchState *env, target_ulong val) 108 { 109 LoongArchCPU *cpu = env_archcpu(env); 110 int64_t old_v = 0; 111 112 if (val & 0x1) { 113 bql_lock(); 114 loongarch_cpu_set_irq(cpu, IRQ_TIMER, 0); 115 bql_unlock(); 116 } 117 return old_v; 118 } 119 120 target_ulong helper_csrwr_pwcl(CPULoongArchState *env, target_ulong val) 121 { 122 uint8_t shift, ptbase; 123 int64_t old_v = env->CSR_PWCL; 124 125 /* 126 * The real hardware only supports 64bit PTE width now, 128bit or others 127 * treated as illegal. 128 */ 129 shift = FIELD_EX64(val, CSR_PWCL, PTEWIDTH); 130 ptbase = FIELD_EX64(val, CSR_PWCL, PTBASE); 131 if (shift) { 132 qemu_log_mask(LOG_GUEST_ERROR, 133 "Attempted set pte width with %d bit\n", 64 << shift); 134 val = FIELD_DP64(val, CSR_PWCL, PTEWIDTH, 0); 135 } 136 if (!check_ps(env, ptbase)) { 137 qemu_log_mask(LOG_GUEST_ERROR, 138 "Attempted set ptbase 2^%d\n", ptbase); 139 } 140 env->CSR_PWCL = val; 141 return old_v; 142 } 143