mirror of https://github.com/xemu-project/xemu.git
pull-loongarch-20231103
-----BEGIN PGP SIGNATURE----- iLMEAAEKAB0WIQS4/x2g0v3LLaCcbCxAov/yOSY+3wUCZUSQIgAKCRBAov/yOSY+ 31aIBADj5FzdUxyFB813SouAiEiyMdI4bN98AunomAk3Kt8PF1XPoP8kPzcjxcMI kCW4eoHb12MVs9OclkqFY3VyaxtSD3YSG/h8W9YxaDyU+L/q89RS+J4r6CAZ8ylg J4uxs3Lv8nwPEvRb4zITAt8JQllLey1100j/uu4fU0Rx7vUcMA== =9RMx -----END PGP SIGNATURE----- Merge tag 'pull-loongarch-20231103' of https://gitlab.com/gaosong/qemu into staging pull-loongarch-20231103 # -----BEGIN PGP SIGNATURE----- # # iLMEAAEKAB0WIQS4/x2g0v3LLaCcbCxAov/yOSY+3wUCZUSQIgAKCRBAov/yOSY+ # 31aIBADj5FzdUxyFB813SouAiEiyMdI4bN98AunomAk3Kt8PF1XPoP8kPzcjxcMI # kCW4eoHb12MVs9OclkqFY3VyaxtSD3YSG/h8W9YxaDyU+L/q89RS+J4r6CAZ8ylg # J4uxs3Lv8nwPEvRb4zITAt8JQllLey1100j/uu4fU0Rx7vUcMA== # =9RMx # -----END PGP SIGNATURE----- # gpg: Signature made Fri 03 Nov 2023 14:16:02 HKT # gpg: using RSA key B8FF1DA0D2FDCB2DA09C6C2C40A2FFF239263EDF # gpg: Good signature from "Song Gao <m17746591750@163.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: B8FF 1DA0 D2FD CB2D A09C 6C2C 40A2 FFF2 3926 3EDF * tag 'pull-loongarch-20231103' of https://gitlab.com/gaosong/qemu: linux-user/loongarch64: Add LASX sigcontext save/restore linux-user/loongarch64: Add LSX sigcontext save/restore linux-user/loongarch64: Use abi_{ulong,uint} types linux-user/loongarch64: setup_sigframe() set 'end' context size 0 linux-user/loongarch64: Fix setup_extcontext alloc wrong fpu_context size linux-user/loongarch64: Use traps to track LSX/LASX usage target/loongarch: Support 4K page size target/loongarch: Implement query-cpu-model-expansion target/loongarch: Allow user enable/disable LSX/LASX features target/loongarch: Add cpu model 'max' Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
9477a89c14
|
@ -72,6 +72,19 @@ void cpu_loop(CPULoongArchState *env)
|
|||
case EXCCODE_BCE:
|
||||
force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Begin with LSX and LASX disabled, then enable on the first trap.
|
||||
* In this way we can tell if the unit is in use. This is used to
|
||||
* choose the layout of any signal frame.
|
||||
*/
|
||||
case EXCCODE_SXD:
|
||||
env->CSR_EUEN |= R_CSR_EUEN_SXE_MASK;
|
||||
break;
|
||||
case EXCCODE_ASXD:
|
||||
env->CSR_EUEN |= R_CSR_EUEN_ASXE_MASK;
|
||||
break;
|
||||
|
||||
case EXCP_ATOMIC:
|
||||
cpu_exec_step_atomic(cs);
|
||||
break;
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
#define SC_USED_FP (1 << 0)
|
||||
|
||||
struct target_sigcontext {
|
||||
uint64_t sc_pc;
|
||||
uint64_t sc_regs[32];
|
||||
uint32_t sc_flags;
|
||||
uint64_t sc_extcontext[0] QEMU_ALIGNED(16);
|
||||
abi_ulong sc_pc;
|
||||
abi_ulong sc_regs[32];
|
||||
abi_uint sc_flags;
|
||||
abi_ulong sc_extcontext[0] QEMU_ALIGNED(16);
|
||||
};
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(struct target_sigcontext) != sizeof_sigcontext);
|
||||
|
@ -33,19 +33,35 @@ QEMU_BUILD_BUG_ON(offsetof(struct target_sigcontext, sc_regs)
|
|||
#define FPU_CTX_MAGIC 0x46505501
|
||||
#define FPU_CTX_ALIGN 8
|
||||
struct target_fpu_context {
|
||||
uint64_t regs[32];
|
||||
uint64_t fcc;
|
||||
uint32_t fcsr;
|
||||
abi_ulong regs[32];
|
||||
abi_ulong fcc;
|
||||
abi_uint fcsr;
|
||||
} QEMU_ALIGNED(FPU_CTX_ALIGN);
|
||||
|
||||
QEMU_BUILD_BUG_ON(offsetof(struct target_fpu_context, regs)
|
||||
!= offsetof_fpucontext_fr);
|
||||
|
||||
#define LSX_CTX_MAGIC 0x53580001
|
||||
#define LSX_CTX_ALIGN 16
|
||||
struct target_lsx_context {
|
||||
abi_ulong regs[2 * 32];
|
||||
abi_ulong fcc;
|
||||
abi_uint fcsr;
|
||||
} QEMU_ALIGNED(LSX_CTX_ALIGN);
|
||||
|
||||
#define LASX_CTX_MAGIC 0x41535801
|
||||
#define LASX_CTX_ALIGN 32
|
||||
struct target_lasx_context {
|
||||
abi_ulong regs[4 * 32];
|
||||
abi_ulong fcc;
|
||||
abi_uint fcsr;
|
||||
} QEMU_ALIGNED(LASX_CTX_ALIGN);
|
||||
|
||||
#define CONTEXT_INFO_ALIGN 16
|
||||
struct target_sctx_info {
|
||||
uint32_t magic;
|
||||
uint32_t size;
|
||||
uint64_t padding;
|
||||
abi_uint magic;
|
||||
abi_uint size;
|
||||
abi_ulong padding;
|
||||
} QEMU_ALIGNED(CONTEXT_INFO_ALIGN);
|
||||
|
||||
QEMU_BUILD_BUG_ON(sizeof(struct target_sctx_info) != sizeof_sctx_info);
|
||||
|
@ -81,9 +97,11 @@ struct ctx_layout {
|
|||
};
|
||||
|
||||
struct extctx_layout {
|
||||
unsigned int size;
|
||||
unsigned long size;
|
||||
unsigned int flags;
|
||||
struct ctx_layout fpu;
|
||||
struct ctx_layout lsx;
|
||||
struct ctx_layout lasx;
|
||||
struct ctx_layout end;
|
||||
};
|
||||
|
||||
|
@ -105,7 +123,8 @@ static abi_ptr extframe_alloc(struct extctx_layout *extctx,
|
|||
return sp;
|
||||
}
|
||||
|
||||
static abi_ptr setup_extcontext(struct extctx_layout *extctx, abi_ptr sp)
|
||||
static abi_ptr setup_extcontext(CPULoongArchState *env,
|
||||
struct extctx_layout *extctx, abi_ptr sp)
|
||||
{
|
||||
memset(extctx, 0, sizeof(struct extctx_layout));
|
||||
|
||||
|
@ -114,8 +133,17 @@ static abi_ptr setup_extcontext(struct extctx_layout *extctx, abi_ptr sp)
|
|||
|
||||
/* For qemu, there is no lazy fp context switch, so fp always present. */
|
||||
extctx->flags = SC_USED_FP;
|
||||
sp = extframe_alloc(extctx, &extctx->fpu,
|
||||
sizeof(struct target_rt_sigframe), FPU_CTX_ALIGN, sp);
|
||||
|
||||
if (FIELD_EX64(env->CSR_EUEN, CSR_EUEN, ASXE)) {
|
||||
sp = extframe_alloc(extctx, &extctx->lasx,
|
||||
sizeof(struct target_lasx_context), LASX_CTX_ALIGN, sp);
|
||||
} else if (FIELD_EX64(env->CSR_EUEN, CSR_EUEN, SXE)) {
|
||||
sp = extframe_alloc(extctx, &extctx->lsx,
|
||||
sizeof(struct target_lsx_context), LSX_CTX_ALIGN, sp);
|
||||
} else {
|
||||
sp = extframe_alloc(extctx, &extctx->fpu,
|
||||
sizeof(struct target_fpu_context), FPU_CTX_ALIGN, sp);
|
||||
}
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
@ -125,7 +153,6 @@ static void setup_sigframe(CPULoongArchState *env,
|
|||
struct extctx_layout *extctx)
|
||||
{
|
||||
struct target_sctx_info *info;
|
||||
struct target_fpu_context *fpu_ctx;
|
||||
int i;
|
||||
|
||||
__put_user(extctx->flags, &sc->sc_flags);
|
||||
|
@ -136,25 +163,63 @@ static void setup_sigframe(CPULoongArchState *env,
|
|||
}
|
||||
|
||||
/*
|
||||
* Set fpu context
|
||||
* Set extension context
|
||||
*/
|
||||
info = extctx->fpu.haddr;
|
||||
__put_user(FPU_CTX_MAGIC, &info->magic);
|
||||
__put_user(extctx->fpu.size, &info->size);
|
||||
|
||||
fpu_ctx = (struct target_fpu_context *)(info + 1);
|
||||
for (i = 0; i < 32; ++i) {
|
||||
__put_user(env->fpr[i].vreg.D(0), &fpu_ctx->regs[i]);
|
||||
if (FIELD_EX64(env->CSR_EUEN, CSR_EUEN, ASXE)) {
|
||||
struct target_lasx_context *lasx_ctx;
|
||||
info = extctx->lasx.haddr;
|
||||
|
||||
__put_user(LASX_CTX_MAGIC, &info->magic);
|
||||
__put_user(extctx->lasx.size, &info->size);
|
||||
|
||||
lasx_ctx = (struct target_lasx_context *)(info + 1);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
__put_user(env->fpr[i].vreg.UD(0), &lasx_ctx->regs[4 * i]);
|
||||
__put_user(env->fpr[i].vreg.UD(1), &lasx_ctx->regs[4 * i + 1]);
|
||||
__put_user(env->fpr[i].vreg.UD(2), &lasx_ctx->regs[4 * i + 2]);
|
||||
__put_user(env->fpr[i].vreg.UD(3), &lasx_ctx->regs[4 * i + 3]);
|
||||
}
|
||||
__put_user(read_fcc(env), &lasx_ctx->fcc);
|
||||
__put_user(env->fcsr0, &lasx_ctx->fcsr);
|
||||
} else if (FIELD_EX64(env->CSR_EUEN, CSR_EUEN, SXE)) {
|
||||
struct target_lsx_context *lsx_ctx;
|
||||
info = extctx->lsx.haddr;
|
||||
|
||||
__put_user(LSX_CTX_MAGIC, &info->magic);
|
||||
__put_user(extctx->lsx.size, &info->size);
|
||||
|
||||
lsx_ctx = (struct target_lsx_context *)(info + 1);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
__put_user(env->fpr[i].vreg.UD(0), &lsx_ctx->regs[2 * i]);
|
||||
__put_user(env->fpr[i].vreg.UD(1), &lsx_ctx->regs[2 * i + 1]);
|
||||
}
|
||||
__put_user(read_fcc(env), &lsx_ctx->fcc);
|
||||
__put_user(env->fcsr0, &lsx_ctx->fcsr);
|
||||
} else {
|
||||
struct target_fpu_context *fpu_ctx;
|
||||
info = extctx->fpu.haddr;
|
||||
|
||||
__put_user(FPU_CTX_MAGIC, &info->magic);
|
||||
__put_user(extctx->fpu.size, &info->size);
|
||||
|
||||
fpu_ctx = (struct target_fpu_context *)(info + 1);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
__put_user(env->fpr[i].vreg.UD(0), &fpu_ctx->regs[i]);
|
||||
}
|
||||
__put_user(read_fcc(env), &fpu_ctx->fcc);
|
||||
__put_user(env->fcsr0, &fpu_ctx->fcsr);
|
||||
}
|
||||
__put_user(read_fcc(env), &fpu_ctx->fcc);
|
||||
__put_user(env->fcsr0, &fpu_ctx->fcsr);
|
||||
|
||||
/*
|
||||
* Set end context
|
||||
*/
|
||||
info = extctx->end.haddr;
|
||||
__put_user(0, &info->magic);
|
||||
__put_user(extctx->end.size, &info->size);
|
||||
__put_user(0, &info->size);
|
||||
}
|
||||
|
||||
static bool parse_extcontext(struct extctx_layout *extctx, abi_ptr frame)
|
||||
|
@ -162,7 +227,7 @@ static bool parse_extcontext(struct extctx_layout *extctx, abi_ptr frame)
|
|||
memset(extctx, 0, sizeof(*extctx));
|
||||
|
||||
while (1) {
|
||||
uint32_t magic, size;
|
||||
abi_uint magic, size;
|
||||
|
||||
if (get_user_u32(magic, frame) || get_user_u32(size, frame + 4)) {
|
||||
return false;
|
||||
|
@ -184,6 +249,24 @@ static bool parse_extcontext(struct extctx_layout *extctx, abi_ptr frame)
|
|||
extctx->fpu.size = size;
|
||||
extctx->size += size;
|
||||
break;
|
||||
case LSX_CTX_MAGIC:
|
||||
if (size < (sizeof(struct target_sctx_info) +
|
||||
sizeof(struct target_lsx_context))) {
|
||||
return false;
|
||||
}
|
||||
extctx->lsx.gaddr = frame;
|
||||
extctx->lsx.size = size;
|
||||
extctx->size += size;
|
||||
break;
|
||||
case LASX_CTX_MAGIC:
|
||||
if (size < (sizeof(struct target_sctx_info) +
|
||||
sizeof(struct target_lasx_context))) {
|
||||
return false;
|
||||
}
|
||||
extctx->lasx.gaddr = frame;
|
||||
extctx->lasx.size = size;
|
||||
extctx->size += size;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -197,19 +280,45 @@ static void restore_sigframe(CPULoongArchState *env,
|
|||
struct extctx_layout *extctx)
|
||||
{
|
||||
int i;
|
||||
abi_ulong fcc;
|
||||
|
||||
__get_user(env->pc, &sc->sc_pc);
|
||||
for (i = 1; i < 32; ++i) {
|
||||
__get_user(env->gpr[i], &sc->sc_regs[i]);
|
||||
}
|
||||
|
||||
if (extctx->fpu.haddr) {
|
||||
struct target_fpu_context *fpu_ctx =
|
||||
extctx->fpu.haddr + sizeof(struct target_sctx_info);
|
||||
uint64_t fcc;
|
||||
if (extctx->lasx.haddr) {
|
||||
struct target_lasx_context *lasx_ctx =
|
||||
extctx->lasx.haddr + sizeof(struct target_sctx_info);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
__get_user(env->fpr[i].vreg.D(0), &fpu_ctx->regs[i]);
|
||||
__get_user(env->fpr[i].vreg.UD(0), &lasx_ctx->regs[4 * i]);
|
||||
__get_user(env->fpr[i].vreg.UD(1), &lasx_ctx->regs[4 * i + 1]);
|
||||
__get_user(env->fpr[i].vreg.UD(2), &lasx_ctx->regs[4 * i + 2]);
|
||||
__get_user(env->fpr[i].vreg.UD(3), &lasx_ctx->regs[4 * i + 3]);
|
||||
}
|
||||
__get_user(fcc, &lasx_ctx->fcc);
|
||||
write_fcc(env, fcc);
|
||||
__get_user(env->fcsr0, &lasx_ctx->fcsr);
|
||||
restore_fp_status(env);
|
||||
} else if (extctx->lsx.haddr) {
|
||||
struct target_lsx_context *lsx_ctx =
|
||||
extctx->lsx.haddr + sizeof(struct target_sctx_info);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
__get_user(env->fpr[i].vreg.UD(0), &lsx_ctx->regs[2 * i]);
|
||||
__get_user(env->fpr[i].vreg.UD(1), &lsx_ctx->regs[2 * i + 1]);
|
||||
}
|
||||
__get_user(fcc, &lsx_ctx->fcc);
|
||||
write_fcc(env, fcc);
|
||||
__get_user(env->fcsr0, &lsx_ctx->fcsr);
|
||||
restore_fp_status(env);
|
||||
} else if (extctx->fpu.haddr) {
|
||||
struct target_fpu_context *fpu_ctx =
|
||||
extctx->fpu.haddr + sizeof(struct target_sctx_info);
|
||||
|
||||
for (i = 0; i < 32; ++i) {
|
||||
__get_user(env->fpr[i].vreg.UD(0), &fpu_ctx->regs[i]);
|
||||
}
|
||||
__get_user(fcc, &fpu_ctx->fcc);
|
||||
write_fcc(env, fcc);
|
||||
|
@ -229,7 +338,7 @@ static abi_ptr get_sigframe(struct target_sigaction *ka,
|
|||
|
||||
sp = target_sigsp(get_sp_from_cpustate(env), ka);
|
||||
sp = ROUND_DOWN(sp, 16);
|
||||
sp = setup_extcontext(extctx, sp);
|
||||
sp = setup_extcontext(env, extctx, sp);
|
||||
sp -= sizeof(struct target_rt_sigframe);
|
||||
|
||||
assert(QEMU_IS_ALIGNED(sp, 16));
|
||||
|
@ -255,8 +364,17 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
|
|||
force_sigsegv(sig);
|
||||
return;
|
||||
}
|
||||
extctx.fpu.haddr = (void *)frame + (extctx.fpu.gaddr - frame_addr);
|
||||
extctx.end.haddr = (void *)frame + (extctx.end.gaddr - frame_addr);
|
||||
|
||||
if (FIELD_EX64(env->CSR_EUEN, CSR_EUEN, ASXE)) {
|
||||
extctx.lasx.haddr = (void *)frame + (extctx.lasx.gaddr - frame_addr);
|
||||
extctx.end.haddr = (void *)frame + (extctx.end.gaddr - frame_addr);
|
||||
} else if (FIELD_EX64(env->CSR_EUEN, CSR_EUEN, SXE)) {
|
||||
extctx.lsx.haddr = (void *)frame + (extctx.lsx.gaddr - frame_addr);
|
||||
extctx.end.haddr = (void *)frame + (extctx.end.gaddr - frame_addr);
|
||||
} else {
|
||||
extctx.fpu.haddr = (void *)frame + (extctx.fpu.gaddr - frame_addr);
|
||||
extctx.end.haddr = (void *)frame + (extctx.end.gaddr - frame_addr);
|
||||
}
|
||||
|
||||
tswap_siginfo(&frame->rs_info, info);
|
||||
|
||||
|
@ -299,7 +417,12 @@ long do_rt_sigreturn(CPULoongArchState *env)
|
|||
if (!frame) {
|
||||
goto badframe;
|
||||
}
|
||||
if (extctx.fpu.gaddr) {
|
||||
|
||||
if (extctx.lasx.gaddr) {
|
||||
extctx.lasx.haddr = (void *)frame + (extctx.lasx.gaddr - frame_addr);
|
||||
} else if (extctx.lsx.gaddr) {
|
||||
extctx.lsx.haddr = (void *)frame + (extctx.lsx.gaddr - frame_addr);
|
||||
} else if (extctx.fpu.gaddr) {
|
||||
extctx.fpu.haddr = (void *)frame + (extctx.fpu.gaddr - frame_addr);
|
||||
}
|
||||
|
||||
|
|
|
@ -230,7 +230,8 @@
|
|||
'data': { 'model': 'CpuModelInfo' },
|
||||
'if': { 'any': [ 'TARGET_S390X',
|
||||
'TARGET_I386',
|
||||
'TARGET_ARM' ] } }
|
||||
'TARGET_ARM',
|
||||
'TARGET_LOONGARCH64' ] } }
|
||||
|
||||
##
|
||||
# @query-cpu-model-expansion:
|
||||
|
@ -275,7 +276,8 @@
|
|||
'returns': 'CpuModelExpansionInfo',
|
||||
'if': { 'any': [ 'TARGET_S390X',
|
||||
'TARGET_I386',
|
||||
'TARGET_ARM' ] } }
|
||||
'TARGET_ARM',
|
||||
'TARGET_LOONGARCH64' ] } }
|
||||
|
||||
##
|
||||
# @CpuDefinitionInfo:
|
||||
|
|
|
@ -12,6 +12,6 @@
|
|||
#define TARGET_PHYS_ADDR_SPACE_BITS 48
|
||||
#define TARGET_VIRT_ADDR_SPACE_BITS 48
|
||||
|
||||
#define TARGET_PAGE_BITS 14
|
||||
#define TARGET_PAGE_BITS 12
|
||||
|
||||
#endif
|
||||
|
|
|
@ -443,6 +443,7 @@ static void loongarch_la464_initfn(Object *obj)
|
|||
env->cpucfg[20] = data;
|
||||
|
||||
env->CSR_ASID = FIELD_DP64(0, CSR_ASID, ASIDBITS, 0xa);
|
||||
loongarch_cpu_post_init(obj);
|
||||
}
|
||||
|
||||
static void loongarch_la132_initfn(Object *obj)
|
||||
|
@ -474,6 +475,12 @@ static void loongarch_la132_initfn(Object *obj)
|
|||
env->cpucfg[1] = data;
|
||||
}
|
||||
|
||||
static void loongarch_max_initfn(Object *obj)
|
||||
{
|
||||
/* '-cpu max' for TCG: we use cpu la464. */
|
||||
loongarch_la464_initfn(obj);
|
||||
}
|
||||
|
||||
static void loongarch_cpu_list_entry(gpointer data, gpointer user_data)
|
||||
{
|
||||
const char *typename = object_class_get_name(OBJECT_CLASS(data));
|
||||
|
@ -616,6 +623,72 @@ static const MemoryRegionOps loongarch_qemu_ops = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static bool loongarch_get_lsx(Object *obj, Error **errp)
|
||||
{
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
|
||||
bool ret;
|
||||
|
||||
if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
|
||||
ret = true;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void loongarch_set_lsx(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
|
||||
|
||||
if (value) {
|
||||
cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LSX, 1);
|
||||
} else {
|
||||
cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LSX, 0);
|
||||
cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LASX, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static bool loongarch_get_lasx(Object *obj, Error **errp)
|
||||
{
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
|
||||
bool ret;
|
||||
|
||||
if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) {
|
||||
ret = true;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void loongarch_set_lasx(Object *obj, bool value, Error **errp)
|
||||
{
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
|
||||
|
||||
if (value) {
|
||||
if (!FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
|
||||
cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LSX, 1);
|
||||
}
|
||||
cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LASX, 1);
|
||||
} else {
|
||||
cpu->env.cpucfg[2] = FIELD_DP32(cpu->env.cpucfg[2], CPUCFG2, LASX, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void loongarch_cpu_post_init(Object *obj)
|
||||
{
|
||||
LoongArchCPU *cpu = LOONGARCH_CPU(obj);
|
||||
|
||||
if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LSX)) {
|
||||
object_property_add_bool(obj, "lsx", loongarch_get_lsx,
|
||||
loongarch_set_lsx);
|
||||
}
|
||||
if (FIELD_EX32(cpu->env.cpucfg[2], CPUCFG2, LASX)) {
|
||||
object_property_add_bool(obj, "lasx", loongarch_get_lasx,
|
||||
loongarch_set_lasx);
|
||||
}
|
||||
}
|
||||
|
||||
static void loongarch_cpu_init(Object *obj)
|
||||
{
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
@ -829,6 +902,7 @@ static const TypeInfo loongarch_cpu_type_infos[] = {
|
|||
},
|
||||
DEFINE_LOONGARCH_CPU_TYPE(64, "la464", loongarch_la464_initfn),
|
||||
DEFINE_LOONGARCH_CPU_TYPE(32, "la132", loongarch_la132_initfn),
|
||||
DEFINE_LOONGARCH_CPU_TYPE(64, "max", loongarch_max_initfn),
|
||||
};
|
||||
|
||||
DEFINE_TYPES(loongarch_cpu_type_infos)
|
||||
|
|
|
@ -486,4 +486,6 @@ void loongarch_cpu_list(void);
|
|||
#define LOONGARCH_CPU_TYPE_NAME(model) model LOONGARCH_CPU_TYPE_SUFFIX
|
||||
#define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU
|
||||
|
||||
void loongarch_cpu_post_init(Object *obj);
|
||||
|
||||
#endif /* LOONGARCH_CPU_H */
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
* Copyright (c) 2022-2023 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
|
||||
static bool check_vec(DisasContext *ctx, uint32_t oprsz)
|
||||
{
|
||||
if ((oprsz == 16) && ((ctx->base.tb->flags & HW_FLAGS_EUEN_SXE) == 0)) {
|
||||
|
@ -21,15 +19,6 @@ static bool check_vec(DisasContext *ctx, uint32_t oprsz)
|
|||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static bool check_vec(DisasContext *ctx, uint32_t oprsz)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static bool gen_vvvv_ptr_vl(DisasContext *ctx, arg_vvvv *a, uint32_t oprsz,
|
||||
gen_helper_gvec_4_ptr *fn)
|
||||
{
|
||||
|
|
|
@ -7,8 +7,13 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-commands-machine-target.h"
|
||||
#include "cpu.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qom/qom-qobject.h"
|
||||
|
||||
static void loongarch_cpu_add_definition(gpointer data, gpointer user_data)
|
||||
{
|
||||
|
@ -35,3 +40,62 @@ CpuDefinitionInfoList *qmp_query_cpu_definitions(Error **errp)
|
|||
|
||||
return cpu_list;
|
||||
}
|
||||
|
||||
static const char *cpu_model_advertised_features[] = {
|
||||
"lsx", "lasx", NULL
|
||||
};
|
||||
|
||||
CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
|
||||
CpuModelInfo *model,
|
||||
Error **errp)
|
||||
{
|
||||
CpuModelExpansionInfo *expansion_info;
|
||||
QDict *qdict_out;
|
||||
ObjectClass *oc;
|
||||
Object *obj;
|
||||
const char *name;
|
||||
int i;
|
||||
|
||||
if (type != CPU_MODEL_EXPANSION_TYPE_STATIC) {
|
||||
error_setg(errp, "The requested expansion type is not supported");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
oc = cpu_class_by_name(TYPE_LOONGARCH_CPU, model->name);
|
||||
if (!oc) {
|
||||
error_setg(errp, "The CPU type '%s' is not a recognized LoongArch CPU type",
|
||||
model->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
obj = object_new(object_class_get_name(oc));
|
||||
|
||||
expansion_info = g_new0(CpuModelExpansionInfo, 1);
|
||||
expansion_info->model = g_malloc0(sizeof(*expansion_info->model));
|
||||
expansion_info->model->name = g_strdup(model->name);
|
||||
|
||||
qdict_out = qdict_new();
|
||||
|
||||
i = 0;
|
||||
while ((name = cpu_model_advertised_features[i++]) != NULL) {
|
||||
ObjectProperty *prop = object_property_find(obj, name);
|
||||
if (prop) {
|
||||
QObject *value;
|
||||
|
||||
assert(prop->get);
|
||||
value = object_property_get_qobject(obj, name, &error_abort);
|
||||
|
||||
qdict_put_obj(qdict_out, name, value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!qdict_size(qdict_out)) {
|
||||
qobject_unref(qdict_out);
|
||||
} else {
|
||||
expansion_info->model->props = QOBJECT(qdict_out);
|
||||
}
|
||||
|
||||
object_unref(obj);
|
||||
|
||||
return expansion_info;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,9 @@ static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical,
|
|||
tlb_rplv = 0;
|
||||
}
|
||||
|
||||
/* Remove sw bit between bit12 -- bit PS*/
|
||||
tlb_ppn = tlb_ppn & ~(((0x1UL << (tlb_ps - 12)) -1));
|
||||
|
||||
/* Check access rights */
|
||||
if (!tlb_v) {
|
||||
return TLBRET_INVALID;
|
||||
|
@ -82,10 +85,6 @@ static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical,
|
|||
return TLBRET_DIRTY;
|
||||
}
|
||||
|
||||
/*
|
||||
* tlb_entry contains ppn[47:12] while 16KiB ppn is [47:15]
|
||||
* need adjust.
|
||||
*/
|
||||
*physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) |
|
||||
(address & MAKE_64BIT_MASK(0, tlb_ps));
|
||||
*prot = PAGE_READ;
|
||||
|
@ -774,7 +773,7 @@ void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
|
|||
/* Move Global bit */
|
||||
tmp0 = ((tmp0 & (1 << LOONGARCH_HGLOBAL_SHIFT)) >>
|
||||
LOONGARCH_HGLOBAL_SHIFT) << R_TLBENTRY_G_SHIFT |
|
||||
(tmp0 & (~(1 << R_TLBENTRY_G_SHIFT)));
|
||||
(tmp0 & (~(1 << LOONGARCH_HGLOBAL_SHIFT)));
|
||||
ps = ptbase + ptwidth - 1;
|
||||
if (odd) {
|
||||
tmp0 += MAKE_64BIT_MASK(ps, 1);
|
||||
|
|
Loading…
Reference in New Issue