1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * LoongArch emulation helpers for QEMU. 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 "qemu/host-utils.h" 13 #include "exec/helper-proto.h" 14 #include "exec/exec-all.h" 15 #include "exec/cpu_ldst.h" 16 #include "internals.h" 17 #include "qemu/crc32c.h" 18 #include <zlib.h> 19 #include "cpu-csr.h" 20 21 /* Exceptions helpers */ 22 void helper_raise_exception(CPULoongArchState *env, uint32_t exception) 23 { 24 do_raise_exception(env, exception, GETPC()); 25 } 26 27 target_ulong helper_bitrev_w(target_ulong rj) 28 { 29 return (int32_t)revbit32(rj); 30 } 31 32 target_ulong helper_bitrev_d(target_ulong rj) 33 { 34 return revbit64(rj); 35 } 36 37 target_ulong helper_bitswap(target_ulong v) 38 { 39 v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) | 40 ((v & (target_ulong)0x5555555555555555ULL) << 1); 41 v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) | 42 ((v & (target_ulong)0x3333333333333333ULL) << 2); 43 v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) | 44 ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4); 45 return v; 46 } 47 48 /* loongarch assert op */ 49 void helper_asrtle_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) 50 { 51 if (rj > rk) { 52 do_raise_exception(env, EXCCODE_ADEM, GETPC()); 53 } 54 } 55 56 void helper_asrtgt_d(CPULoongArchState *env, target_ulong rj, target_ulong rk) 57 { 58 if (rj <= rk) { 59 do_raise_exception(env, EXCCODE_ADEM, GETPC()); 60 } 61 } 62 63 target_ulong helper_crc32(target_ulong val, target_ulong m, uint64_t sz) 64 { 65 uint8_t buf[8]; 66 target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); 67 68 m &= mask; 69 stq_le_p(buf, m); 70 return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff); 71 } 72 73 target_ulong helper_crc32c(target_ulong val, target_ulong m, uint64_t sz) 74 { 75 uint8_t buf[8]; 76 target_ulong mask = ((sz * 8) == 64) ? -1ULL : ((1ULL << (sz * 8)) - 1); 77 m &= mask; 78 stq_le_p(buf, m); 79 return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff); 80 } 81 82 target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj) 83 { 84 return rj > 21 ? 0 : env->cpucfg[rj]; 85 } 86 87 uint64_t helper_rdtime_d(CPULoongArchState *env) 88 { 89 uint64_t plv; 90 LoongArchCPU *cpu = env_archcpu(env); 91 92 plv = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV); 93 if (extract64(env->CSR_MISC, R_CSR_MISC_DRDTL_SHIFT + plv, 1)) { 94 do_raise_exception(env, EXCCODE_IPE, GETPC()); 95 } 96 97 return cpu_loongarch_get_constant_timer_counter(cpu); 98 } 99 100 void helper_ertn(CPULoongArchState *env) 101 { 102 uint64_t csr_pplv, csr_pie; 103 if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) { 104 csr_pplv = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV); 105 csr_pie = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE); 106 107 env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0); 108 env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 0); 109 env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 1); 110 env->pc = env->CSR_TLBRERA; 111 qemu_log_mask(CPU_LOG_INT, "%s: TLBRERA " TARGET_FMT_lx "\n", 112 __func__, env->CSR_TLBRERA); 113 } else { 114 csr_pplv = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PPLV); 115 csr_pie = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PIE); 116 117 env->pc = env->CSR_ERA; 118 qemu_log_mask(CPU_LOG_INT, "%s: ERA " TARGET_FMT_lx "\n", 119 __func__, env->CSR_ERA); 120 } 121 env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, csr_pplv); 122 env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, csr_pie); 123 124 env->lladdr = 1; 125 } 126 127 void helper_idle(CPULoongArchState *env) 128 { 129 CPUState *cs = env_cpu(env); 130 131 cs->halted = 1; 132 do_raise_exception(env, EXCP_HLT, 0); 133 } 134