[PATCH 0/2] Fixes for broken commit 48afe6e4eabf, Windows fails to boot
Commit ("i386: split cpu accelerators from cpu.c, using AccelCPUClass") introduced two bugs that break cpu max and host in the refactoring, by running initializations in the wrong order. This small series of two patches is an attempt to correct the situation. Please provide your test results and feedback, thanks! Claudio Claudio Fontana (2): i386: reorder call to cpu_exec_realizefn in x86_cpu_realizefn i386: run accel_cpu_instance_init as instance_post_init target/i386/cpu.c | 66 +-- 1 file changed, 35 insertions(+), 31 deletions(-) -- 2.26.2
[PATCH 1/2] i386: reorder call to cpu_exec_realizefn in x86_cpu_realizefn
we need to expand features first, before we attempt to check them in the accel realizefn code called by cpu_exec_realizefn(). At the same time we need checks for code_urev and host_cpuid_required, and modifications to cpu->mwait to happen after the initial setting of them inside the accel realizefn code. Partial Fix. Fixes: 48afe6e4eabf ("i386: split cpu accelerators from cpu.c, using AccelCPUClass") Signed-off-by: Claudio Fontana --- target/i386/cpu.c | 56 +++ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 9e211ac2ce..6bcb7dbc2c 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6133,34 +6133,6 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) Error *local_err = NULL; static bool ht_warned; -/* Process Hyper-V enlightenments */ -x86_cpu_hyperv_realize(cpu); - -cpu_exec_realizefn(cs, &local_err); -if (local_err != NULL) { -error_propagate(errp, local_err); -return; -} - -if (xcc->host_cpuid_required && !accel_uses_host_cpuid()) { -g_autofree char *name = x86_cpu_class_get_model_name(xcc); -error_setg(&local_err, "CPU model '%s' requires KVM or HVF", name); -goto out; -} - -if (cpu->ucode_rev == 0) { -/* The default is the same as KVM's. */ -if (IS_AMD_CPU(env)) { -cpu->ucode_rev = 0x0165; -} else { -cpu->ucode_rev = 0x1ULL; -} -} - -/* mwait extended info: needed for Core compatibility */ -/* We always wake on interrupt even if host does not have the capability */ -cpu->mwait.ecx |= CPUID_MWAIT_EMX | CPUID_MWAIT_IBE; - if (cpu->apic_id == UNASSIGNED_APIC_ID) { error_setg(errp, "apic-id property was not initialized properly"); return; @@ -6190,6 +6162,34 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) & CPUID_EXT2_AMD_ALIASES); } +/* Process Hyper-V enlightenments */ +x86_cpu_hyperv_realize(cpu); + +cpu_exec_realizefn(cs, &local_err); +if (local_err != NULL) { +error_propagate(errp, local_err); +return; +} + +if (xcc->host_cpuid_required && !accel_uses_host_cpuid()) { +g_autofree char *name = x86_cpu_class_get_model_name(xcc); +error_setg(&local_err, "CPU model '%s' requires KVM or HVF", name); +goto out; +} + +if (cpu->ucode_rev == 0) { +/* The default is the same as KVM's. */ +if (IS_AMD_CPU(env)) { +cpu->ucode_rev = 0x0165; +} else { +cpu->ucode_rev = 0x1ULL; +} +} + +/* mwait extended info: needed for Core compatibility */ +/* We always wake on interrupt even if host does not have the capability */ +cpu->mwait.ecx |= CPUID_MWAIT_EMX | CPUID_MWAIT_IBE; + /* For 64bit systems think about the number of physical bits to present. * ideally this should be the same as the host; anything other than matching * the host can cause incorrect guest behaviour. -- 2.26.2
[PATCH 2/2] i386: run accel_cpu_instance_init as instance_post_init
This partially fixes host and max cpu initialization, by running the accel cpu initialization only after all instance init functions are called for all X86 cpu subclasses. Partial Fix. Fixes: 48afe6e4eabf ("i386: split cpu accelerators from cpu.c, using AccelCPUClass") Signed-off-by: Claudio Fontana --- target/i386/cpu.c | 10 +++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 6bcb7dbc2c..ae148fbd2f 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6422,6 +6422,11 @@ static void x86_cpu_register_feature_bit_props(X86CPUClass *xcc, x86_cpu_register_bit_prop(xcc, name, w, bitnr); } +static void x86_cpu_post_initfn(Object *obj) +{ +accel_cpu_instance_init(CPU(obj)); +} + static void x86_cpu_initfn(Object *obj) { X86CPU *cpu = X86_CPU(obj); @@ -6473,9 +6478,6 @@ static void x86_cpu_initfn(Object *obj) if (xcc->model) { x86_cpu_load_model(cpu, xcc->model); } - -/* if required, do accelerator-specific cpu initializations */ -accel_cpu_instance_init(CPU(obj)); } static int64_t x86_cpu_get_arch_id(CPUState *cs) @@ -6810,6 +6812,8 @@ static const TypeInfo x86_cpu_type_info = { .parent = TYPE_CPU, .instance_size = sizeof(X86CPU), .instance_init = x86_cpu_initfn, +.instance_post_init = x86_cpu_post_initfn, + .abstract = true, .class_size = sizeof(X86CPUClass), .class_init = x86_cpu_common_class_init, -- 2.26.2
Re: [Qemu-devel] [PATCH v3 2/2] tests: tcg: mips: Remove old directories after moving source files
On 1/7/19 12:22 PM, Alex Bennée wrote: > > Aleksandar Markovic writes: > >> From: Aleksandar Markovic >> >> Remove old directories after reorganization of MIPS TCG tests. >> >> Signed-off-by: Aleksandar Markovic >> --- >> tests/tcg/mips/mips32-dsp/Makefile| 136 - >> tests/tcg/mips/mips32-dspr2/Makefile | 71 --- >> tests/tcg/mips/mips64-dsp/Makefile| 306 >> -- >> tests/tcg/mips/mips64-dsp/head.S | 16 -- >> tests/tcg/mips/mips64-dsp/io.h| 22 --- >> tests/tcg/mips/mips64-dsp/mips_boot.lds | 31 --- >> tests/tcg/mips/mips64-dspr2/.directory| 2 - >> tests/tcg/mips/mips64-dspr2/Makefile | 116 --- >> tests/tcg/mips/mips64-dspr2/head.S| 16 -- >> tests/tcg/mips/mips64-dspr2/io.h | 22 --- >> tests/tcg/mips/mips64-dspr2/mips_boot.lds | 31 --- >> tests/tcg/mips/mipsr5900/Makefile | 32 > > Erm do we really want this? Ideally the Makefiles should be moved into > their new locations and tested with whatever the out of tree build > approach was before. Then my series can apply on top and translate them > into new style check-tcg tests builds. It seems Aleksandar missed your comment :(
Re: [Qemu-devel] [PATCH v4 0/3] tests: Reorganize MIPS TCG directories and files
Hi Aleksandar Rikalo, On 1/24/19 4:37 PM, Aleksandar Rikalo wrote: >> From: Aleksandar Markovic >> Sent: Thursday, January 24, 2019 4:19 PM >> To: qemu-devel@nongnu.org >> Cc: aurel...@aurel32.net; Aleksandar Markovic; Aleksandar Rikalo >> Subject: [PATCH v4 0/3] tests: Reorganize MIPS TCG directories and files >> >> From: Aleksandar Markovic >> >> Reorganize MIPS TCG directories and files. >> >> Directories for DSP tests in system mode are deleted. They >> introduce more complexity in test structure compared to the >> value they add. Still, these tests may be moved somewhere >> else, let's say in a new acceptance test that will boot >> "mips64r2" virtual machine. >> >> All remaining test will are user mode tests, which will >> simplify maintenance of mips tcg tests overall. >> >> The file movement is done using "git mv" command, so "git >> blame" will still display the original information, regardless >> of the new names and locations of involved files. Also, the >> command "git config diff.renames true" was used to keep the >> size of movement patches reasonable. >> >> v3->v4: >> - DSP ASE system mode tests given up >> - Makefiles provided for tests that remain >> >> v2->v3: >> - corrected missing "v2" that caused wrong message linking >> (the version is now "v3", of course) >> >> v1->v2: >> - used "git config diff.renames true" before sending >> - rebased to the latest code (included newly added r5900 tests) >> >> >> Aleksandar Markovic (3): >> tests: tcg: mips: Move source files to new locations >> tests: tcg: mips: Add two new Makefiles >> tests: tcg: mips: Remove old directories > > I too think that this will simplify the test dirs structure and > maintenance. I cannot wait to see these directories populated with > new tests for various MIPS ISAs and ASEs. > > For all patches in this series: > > Reviewed-by: Aleksandar Rikalo Apparently this series was a bit too enthusiastic and removed many tests (MIPS64 DSP r1 and r2 for example) which then got never reintroduced. What is your plan regarding the "new tests" you mentioned? Thanks, Phil.
[PATCH] target/mips: Fix DBALIGN DSP-R2 opcode 'byte position' field size
Per the "MIPS® DSP Module for MIPS64 Architecture" manual (rev 3.02), Figure 5.12 "SPECIAL3 Encoding of APPEND/DAPPEND Instruction Sub-class" the byte position field ('bp') is 2 bits, not 3. Cc: Jia Liu Fixes: 26690560240 ("target-mips: Add ASE DSP compare-pick instructions") Signed-off-by: Philippe Mathieu-Daudé --- target/mips/tcg/translate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index c03a8ae1fed..e68647ce14c 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -23016,8 +23016,8 @@ static void gen_mipsdsp_append(CPUMIPSState *env, DisasContext *ctx, } break; case OPC_DBALIGN: -sa &= 7; -if (sa != 0 && sa != 2 && sa != 4) { +sa &= 3; +if (sa != 0 && sa != 2) { tcg_gen_shli_tl(cpu_gpr[rt], cpu_gpr[rt], 8 * sa); tcg_gen_shri_tl(t0, t0, 8 * (8 - sa)); tcg_gen_or_tl(cpu_gpr[rt], cpu_gpr[rt], t0); -- 2.26.3
Re: [PATCH v11 08/46] target/mips: Add emulation of nanoMIPS 16-bit branch instructions
On Mon, Aug 20, 2018 at 8:17 PM Aleksandar Markovic wrote: > > From: Stefan Markovic > > Add emulation of nanoMIPS 16-bit branch instructions. > > Reviewed-by: Richard Henderson > Signed-off-by: Yongbok Kim > Signed-off-by: Aleksandar Markovic > Signed-off-by: Stefan Markovic > --- > target/mips/translate.c | 158 > > 1 file changed, 158 insertions(+) > > diff --git a/target/mips/translate.c b/target/mips/translate.c > index 261680e..b0bbf4c 100644 > --- a/target/mips/translate.c > +++ b/target/mips/translate.c > @@ -4564,6 +4564,128 @@ static void gen_compute_branch (DisasContext *ctx, > uint32_t opc, > tcg_temp_free(t1); > } > > + > +/* nanoMIPS Branches */ > +static void gen_compute_branch_nm(DisasContext *ctx, uint32_t opc, > +int insn_bytes, > +int rs, int rt, int32_t offset) > +{ > +target_ulong btgt = -1; > +int bcond_compute = 0; > +TCGv t0 = tcg_temp_new(); > +TCGv t1 = tcg_temp_new(); > + > +/* Load needed operands */ > +switch (opc) { > +case OPC_BEQ: > +case OPC_BNE: > +/* Compare two registers */ > +if (rs != rt) { > +gen_load_gpr(t0, rs); > +gen_load_gpr(t1, rt); > +bcond_compute = 1; > +} > +btgt = ctx->base.pc_next + insn_bytes + offset; > +break; > +case OPC_BGEZAL: > +/* Compare to zero */ > +if (rs != 0) { > +gen_load_gpr(t0, rs); > +bcond_compute = 1; > +} > +btgt = ctx->base.pc_next + insn_bytes + offset; > +break; > +case OPC_BPOSGE32: > +tcg_gen_andi_tl(t0, cpu_dspctrl, 0x3F); > +bcond_compute = 1; > +btgt = ctx->base.pc_next + insn_bytes + offset; > +break; > +case OPC_JR: > +case OPC_JALR: > +/* Jump to register */ > +if (offset != 0 && offset != 16) { > +/* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the > + others are reserved. */ > +MIPS_INVAL("jump hint"); > +generate_exception_end(ctx, EXCP_RI); > +goto out; > +} > +gen_load_gpr(btarget, rs); > +break; > +default: > +MIPS_INVAL("branch/jump"); > +generate_exception_end(ctx, EXCP_RI); > +goto out; > +} > +if (bcond_compute == 0) { > +/* No condition to be computed */ > +switch (opc) { > +case OPC_BEQ: /* rx == rx*/ > +/* Always take */ > +ctx->hflags |= MIPS_HFLAG_B; > +break; > +case OPC_BGEZAL: /* 0 >= 0 */ > +/* Always take and link */ > +tcg_gen_movi_tl(cpu_gpr[31], > +ctx->base.pc_next + insn_bytes); > +ctx->hflags |= MIPS_HFLAG_B; > +break; > +case OPC_BNE: /* rx != rx*/ > +tcg_gen_movi_tl(cpu_gpr[31], ctx->base.pc_next + 8); > +/* Skip the instruction in the delay slot */ > +ctx->base.pc_next += 4; > +goto out; > +case OPC_JR: > +ctx->hflags |= MIPS_HFLAG_BR; > +break; > +case OPC_JALR: > +if (rt > 0) { > +tcg_gen_movi_tl(cpu_gpr[rt], > +ctx->base.pc_next + insn_bytes); > +} > +ctx->hflags |= MIPS_HFLAG_BR; > +break; > +default: > +MIPS_INVAL("branch/jump"); > +generate_exception_end(ctx, EXCP_RI); > +goto out; > +} > +} else { > +switch (opc) { > +case OPC_BEQ: > +tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); > +goto not_likely; > +case OPC_BNE: > +tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); > +goto not_likely; > +case OPC_BGEZAL: > +tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); > +tcg_gen_movi_tl(cpu_gpr[31], > +ctx->base.pc_next + insn_bytes); > +goto not_likely; > +case OPC_BPOSGE32: > +tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 32); This opcode implementation seems incomplete, per the ISA manual: If a control transfer instruction (CTI) is executed in the forbidden slot of a branch or jump, Release 6 implementations are required to signal a Reserved Instruction Exception. A CTI is considered to be one of the following instructions: branch, jump, NAL (Release 6), ERET, ERETNC (Release 5), DERET, WAIT, or PAUSE (Release 2). An instruction is in the forbidden slot if it is the instruction following the branch. > +not_likely: > +ctx->hflags |= MIPS_HFLAG_BC; > +break; > +default: > +MIPS_INVAL("conditional branch/jump"); > +generate_exception_end(ctx, EXCP_RI); > +goto out; >
Re: [PATCH v11 08/46] target/mips: Add emulation of nanoMIPS 16-bit branch instructions
On 5/29/21 3:52 PM, Philippe Mathieu-Daudé wrote: > On Mon, Aug 20, 2018 at 8:17 PM Aleksandar Markovic > wrote: >> >> From: Stefan Markovic >> >> Add emulation of nanoMIPS 16-bit branch instructions. >> >> Reviewed-by: Richard Henderson >> Signed-off-by: Yongbok Kim >> Signed-off-by: Aleksandar Markovic >> Signed-off-by: Stefan Markovic >> --- >> target/mips/translate.c | 158 >> >> 1 file changed, 158 insertions(+) >> >> diff --git a/target/mips/translate.c b/target/mips/translate.c >> index 261680e..b0bbf4c 100644 >> --- a/target/mips/translate.c >> +++ b/target/mips/translate.c >> @@ -4564,6 +4564,128 @@ static void gen_compute_branch (DisasContext *ctx, >> uint32_t opc, >> tcg_temp_free(t1); >> } >> >> + >> +/* nanoMIPS Branches */ >> +static void gen_compute_branch_nm(DisasContext *ctx, uint32_t opc, >> +int insn_bytes, >> +int rs, int rt, int32_t offset) >> +{ >> +target_ulong btgt = -1; >> +int bcond_compute = 0; >> +TCGv t0 = tcg_temp_new(); >> +TCGv t1 = tcg_temp_new(); >> + >> +/* Load needed operands */ >> +switch (opc) { >> +case OPC_BEQ: >> +case OPC_BNE: >> +/* Compare two registers */ >> +if (rs != rt) { >> +gen_load_gpr(t0, rs); >> +gen_load_gpr(t1, rt); >> +bcond_compute = 1; >> +} >> +btgt = ctx->base.pc_next + insn_bytes + offset; >> +break; >> +case OPC_BGEZAL: >> +/* Compare to zero */ >> +if (rs != 0) { >> +gen_load_gpr(t0, rs); >> +bcond_compute = 1; >> +} >> +btgt = ctx->base.pc_next + insn_bytes + offset; >> +break; >> +case OPC_BPOSGE32: >> +tcg_gen_andi_tl(t0, cpu_dspctrl, 0x3F); >> +bcond_compute = 1; >> +btgt = ctx->base.pc_next + insn_bytes + offset; I think this opcode never worked correctly. Per the "MIPS® Architecture Extension: nanoMIPS32 DSP Technical Reference Manual — Revision 0.04" p. 88 "BPOSGE32C": "First, the offset argument is left-shifted by one bit to form a 17-bit signed integer value." The caller, decode_nanomips_32_48_opc(), doesn't shift the offset: case NM_BPOSGE32C: check_dsp_r3(ctx); { int32_t imm = extract32(ctx->opcode, 1, 13) | extract32(ctx->opcode, 0, 1) << 13; gen_compute_branch_nm(ctx, OPC_BPOSGE32, 4, -1, -2, imm); } break; >> +break; >> +case OPC_JR: >> +case OPC_JALR: >> +/* Jump to register */ >> +if (offset != 0 && offset != 16) { >> +/* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the >> + others are reserved. */ >> +MIPS_INVAL("jump hint"); >> +generate_exception_end(ctx, EXCP_RI); >> +goto out; >> +} >> +gen_load_gpr(btarget, rs); >> +break; >> +default: >> +MIPS_INVAL("branch/jump"); >> +generate_exception_end(ctx, EXCP_RI); >> +goto out; >> +} >> +if (bcond_compute == 0) { >> +/* No condition to be computed */ >> +switch (opc) { >> +case OPC_BEQ: /* rx == rx*/ >> +/* Always take */ >> +ctx->hflags |= MIPS_HFLAG_B; >> +break; >> +case OPC_BGEZAL: /* 0 >= 0 */ >> +/* Always take and link */ >> +tcg_gen_movi_tl(cpu_gpr[31], >> +ctx->base.pc_next + insn_bytes); >> +ctx->hflags |= MIPS_HFLAG_B; >> +break; >> +case OPC_BNE: /* rx != rx*/ >> +tcg_gen_movi_tl(cpu_gpr[31], ctx->base.pc_next + 8); >> +/* Skip the instruction in the delay slot */ >> +ctx->base.pc_next += 4; >> +goto out; >> +case OPC_JR: >> +ctx->hflags |= MIPS_HFLAG_BR; >> +break; >> +case OPC_JALR: >> +if (rt > 0) { >> +tcg_gen_movi_tl(cpu_gpr[rt], >> +ctx->base.pc_next + insn_bytes); >> +} >> +ctx->hflags |= MIPS_HFLAG_BR; >> +break; >> +default: >> +MIPS_INVAL("branch/jump"); >> +generate_exception_end(ctx, EXCP_RI); >> +goto out; >> +} >> +} else { >> +switch (opc) { >> +case OPC_BEQ: >> +tcg_gen_setcond_tl(TCG_COND_EQ, bcond, t0, t1); >> +goto not_likely; >> +case OPC_BNE: >> +tcg_gen_setcond_tl(TCG_COND_NE, bcond, t0, t1); >> +goto not_likely; >> +case OPC_BGEZAL: >> +tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); >> +tcg_gen_movi_tl(cpu_gpr[31], >> +ctx->base.pc_next + insn_bytes); >> +goto not_likely; >> +
Re: Windows 7 fails to boot with patch 7eff2e7c
If you have any patches you would like me to test out please send them to me. Thank you. > On May 27, 2021, at 11:13 AM, Programmingkid > wrote: > > I have noticed that Windows 7 has stopped being able to boot recently. After > doing some bisecting I found out it was this patch that is causing this issue: > > 7eff2e7c652304157f503f2d406193bb9de10d58 is the first bad commit > commit 7eff2e7c652304157f503f2d406193bb9de10d58 > Author: Richard Henderson > Date: Fri May 14 10:13:31 2021 -0500 > >target/i386: Cleanup read_crN, write_crN, lmsw > >Pull the svm intercept check into the translator. >Pull the entire implementation of lmsw into the translator. >Push the check for CR8LEG into the regno validation switch. >Unify the gen_io_start check between read/write. >
ping: [PATCH] Set icon for QEMU binary on Mac OS
Ping, please implement this patch. The default icon on Mac OS 11 is not very good looking. https://lore.kernel.org/qemu-devel/20210202134410.9274-1-programmingk...@gmail.com/ Before switching the build system over to Meson, an icon was added to the QEMU binary on Mac OS. This patch adds back that feature. Signed-off-by: John Arbuckle --- meson.build | 20 1 file changed, 20 insertions(+) diff --git a/meson.build b/meson.build index f00b7754fd..7f534f4e75 100644 --- a/meson.build +++ b/meson.build @@ -2183,6 +2183,26 @@ foreach target : target_dirs link_args: link_args, gui_app: exe['gui']) +# set QEMU's icon on Mac OS +if targetos == 'darwin' +newiconpart1 = custom_target('Icon for ' + exe_name + ' - part 1', + depends : emulator, + input : emulator, + output : 'new icon for ' + exe_name + ' - 1', + command : ['Rez', '-append', + meson.source_root() + '/pc-bios/qemu.rsrc', '-o', + meson.current_build_dir() / exe['name']], + build_by_default : true) + +custom_target('Icon for ' + exe_name + ' - part 2', + depends : newiconpart1, + input : emulator, + output : 'new icon for ' + exe_name + ' - 2', + command : ['SetFile', '-a', 'C', + meson.current_build_dir() / exe['name']], + build_by_default : true) +endif + if exe_sign emulators += {exe['name'] : custom_target(exe['name'], install: true, -- 2.24.3 (Apple Git-128)
Re: [PATCH 03/11] softfloat: Introduce float_flag_inorm_denormal
On 5/28/21 10:41 AM, Michael Morrell wrote: I'm probably missing something, but why do we need both "float_flag_inorm_denormal" and "float_flag_iflush_denormal"? Couldn't the code that sets these flags set just a single flag for all denormal inputs and the code that checks these flags check that single flag combined with the "flush_inputs_to_zero" flag to accomplish what the two separate "input denormal" flags do? The thing that you're missing is that many guests leave the accumulated softfloat exceptions in the float_status structure until the guest FPSCR register is read. Unless the guest needs to raise an exception immediately, there's no reason to do otherwise. With this setup, you have no temporal connection between "any denormal" and "flush-to-zero is set", thus two flags. r~
[RFC PATCH 0/3] Cache modelling TCG plugin
In this RFC patch series, I propose an initial cache modelling TCG plugin. As of now, it models separate L1 data cache and L1 instruction cache. It supports three eviction policies: LRU, random, and FIFO. Once a policy is chosen, it's used for both instruction and data caches. Mahmoud Mandour (3): plugins: Added a new cache modelling plugin plugins: cache: Enabled parameterization and added trace printing plugins: cache: Added FIFO and LRU eviction policies. contrib/plugins/Makefile | 1 + contrib/plugins/cache.c | 595 +++ 2 files changed, 596 insertions(+) create mode 100644 contrib/plugins/cache.c -- 2.25.1
[RFC PATCH 3/3] plugins: cache: Added FIFO and LRU eviction policies.
Now one of the three eviction policies can be chosen as an argument. On not specifying an argument, LRU is used by default. Signed-off-by: Mahmoud Mandour --- contrib/plugins/cache.c | 159 1 file changed, 146 insertions(+), 13 deletions(-) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index 7d1d185480..341cd64e41 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -18,6 +18,8 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; +static bool fifo, lru, rnd; + static GRand *rng; static GHashTable *dmiss_ht; static GHashTable *imiss_ht; @@ -55,6 +57,8 @@ struct CacheBlock { struct CacheSet { struct CacheBlock *blocks; +uint16_t *priorities; +GQueue *evict_queue; }; struct Cache { @@ -93,6 +97,84 @@ static inline uint64_t extract_set(struct Cache *cache, uint64_t addr) return (addr & cache->set_mask) >> (pow_of_two(cache->blksize)); } +static void lru_priorities_init(struct Cache *cache) +{ +int i, j; + +for (i = 0; i < cache->num_sets; i++) { +cache->sets[i].priorities = g_new(uint16_t, cache->assoc); +for (j = 0; j < cache->assoc; j++) { +cache->sets[i].priorities[j] = cache->assoc - j - 1; +} +} +} + +static void lru_update_on_miss(struct Cache *cache, + int set_idx, + int blk_idx) +{ +int i; + +for (i = 0; i < cache->assoc; i++) { +cache->sets[set_idx].priorities[i]++; +} + +cache->sets[set_idx].priorities[blk_idx] = 0; +} + +static void lru_update_on_hit(struct Cache *cache, + int set_idx, + int blk_idx) +{ +uint16_t blk_priority; +int i; + +blk_priority = cache->sets[set_idx].priorities[blk_idx]; +for (i = 0; i < cache->assoc; i++) { +if (cache->sets[set_idx].priorities[i] < blk_priority) { +cache->sets[set_idx].priorities[i]++; +} +} +cache->sets[set_idx].priorities[blk_idx] = 0; +} + +static int lru_get_lru_block(struct Cache *cache, int set_idx) +{ +int i; + +for (i = 0; i < cache->assoc; i++) { +if (cache->sets[set_idx].priorities[i] == cache->assoc - 1) { +return i; +} +} + +g_assert_not_reached(); +} + +static void fifo_init(struct Cache *cache) +{ +int i; + +for (i = 0; i < cache->num_sets; i++) { +cache->sets[i].evict_queue = g_queue_new(); +} +} + +static int fifo_get_first_in_block(struct Cache *cache, int set) +{ +GQueue *q = cache->sets[set].evict_queue; +return GPOINTER_TO_INT(g_queue_pop_tail(q)); +} + +static void fifo_update_on_miss(struct Cache *cache, +int set, +int blk_idx) +{ +GQueue *q = cache->sets[set].evict_queue; +g_queue_push_head(q, GINT_TO_POINTER(blk_idx)); +} + + static struct Cache *cache_init(int blksize, int assoc, int cachesize) { struct Cache *cache; @@ -113,6 +195,12 @@ static struct Cache *cache_init(int blksize, int assoc, int cachesize) cache->set_mask = ((cache->num_sets - 1) << (pow_of_two(cache->blksize))); cache->tag_mask = ~(cache->set_mask | cache->blk_mask); +if (lru) { +lru_priorities_init(cache); +} else if (fifo) { +fifo_init(cache); +} + return cache; } @@ -131,12 +219,20 @@ static int get_invalid_block(struct Cache *cache, uint64_t set) return -1; } -static int get_replaced_block(struct Cache *cache) +static int get_replaced_block(struct Cache *cache, int set) { -return g_rand_int_range(rng, 0, cache->assoc); +if (rnd) { +return g_rand_int_range(rng, 0, cache->assoc); +} else if (lru) { +return lru_get_lru_block(cache, set); +} else if (fifo) { +return fifo_get_first_in_block(cache, set); +} + +g_assert_not_reached(); } -static bool in_cache(struct Cache *cache, uint64_t addr) +static int in_cache(struct Cache *cache, uint64_t addr) { int i; uint64_t tag, set; @@ -147,29 +243,39 @@ static bool in_cache(struct Cache *cache, uint64_t addr) for (i = 0; i < cache->assoc; i++) { if (cache->sets[set].blocks[i].tag == tag && cache->sets[set].blocks[i].valid) { -return true; +return i; } } -return false; +return -1; } static enum AccessResult access_cache(struct Cache *cache, uint64_t addr) { uint64_t tag, set; -int replaced_blk; - -if (in_cache(cache, addr)) { -return HIT; -} +int hit_blk, replaced_blk; tag = extract_tag(cache, addr); set = extract_set(cache, addr); +hit_blk = in_cache(cache, addr); + +if (hit_blk != -1) { +if (lru) { +lru_update_on_hit(cache, set, hit_blk); +} +return HIT; +} replaced_blk = get_i
[RFC PATCH 2/3] plugins: cache: Enabled parameterization and added trace printing
Made both icache and dcache configurable through plugin arguments and added memory trace printing in a separate file. Signed-off-by: Mahmoud Mandour --- contrib/plugins/cache.c | 68 +++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index f8c15ebed2..7d1d185480 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -22,7 +22,7 @@ static GRand *rng; static GHashTable *dmiss_ht; static GHashTable *imiss_ht; -static GMutex dmtx, imtx; +static GMutex dmtx, imtx, fmtx; static int limit; static bool sys; @@ -33,6 +33,8 @@ static uint64_t dmisses; static uint64_t imem_accesses; static uint64_t imisses; +FILE *tracefile; + static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW; enum AccessResult { @@ -205,6 +207,16 @@ static void vcpu_mem_access(unsigned int cpu_index, qemu_plugin_meminfo_t info, insn_addr = ((struct InsnData *) userdata)->addr; effective_addr = hwaddr ? qemu_plugin_hwaddr_phys_addr(hwaddr) : vaddr; +if (tracefile) { +g_mutex_lock(&fmtx); +g_autoptr(GString) rep = g_string_new(""); +bool is_store = qemu_plugin_mem_is_store(info); +g_string_append_printf(rep, "%c: 0x%" PRIx64, +is_store ? 'S' : 'L', effective_addr); +fprintf(tracefile, "%s\n", rep->str); +g_mutex_unlock(&fmtx); +} + if (access_cache(dcache, effective_addr) == MISS) { struct InsnData *insn = get_or_create(dmiss_ht, userdata, insn_addr); insn->misses++; @@ -221,11 +233,20 @@ static void vcpu_insn_exec(unsigned int vcpu_index, void *userdata) g_mutex_lock(&imtx); addr = ((struct InsnData *) userdata)->addr; +if (tracefile) { +g_mutex_lock(&fmtx); +g_autoptr(GString) rep = g_string_new(""); +g_string_append_printf(rep, "I: 0x%" PRIx64, addr); +fprintf(tracefile, "%s\n", rep->str); +g_mutex_unlock(&fmtx); +} + if (access_cache(icache, addr) == MISS) { struct InsnData *insn = get_or_create(imiss_ht, userdata, addr); insn->misses++; imisses++; } + imem_accesses++; g_mutex_unlock(&imtx); } @@ -352,6 +373,15 @@ static void plugin_exit() g_mutex_unlock(&dmtx); g_mutex_unlock(&imtx); + +if (tracefile) { +fclose(tracefile); +} +} + +static bool bad_cache_params(int blksize, int assoc, int cachesize) +{ +return (cachesize % blksize) != 0 || (cachesize % (blksize * assoc) != 0); } QEMU_PLUGIN_EXPORT @@ -377,14 +407,48 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, for (i = 0; i < argc; i++) { char *opt = argv[i]; -if (g_str_has_prefix(opt, "limit=")) { +if (g_str_has_prefix(opt, "I=")) { +gchar **toks = g_strsplit(opt + 2, " ", -1); +if (g_strv_length(toks) != 3) { +fprintf(stderr, "option parsing failed: %s\n", opt); +return -1; +} +icachesize = g_ascii_strtoull(toks[0], NULL, 10); +iassoc = g_ascii_strtoull(toks[1], NULL, 10); +iblksize = g_ascii_strtoull(toks[2], NULL, 10); +} else if (g_str_has_prefix(opt, "D=")) { +gchar **toks = g_strsplit(opt + 2, " ", -1); +if (g_strv_length(toks) != 3) { +fprintf(stderr, "option parsing failed: %s\n", opt); +return -1; +} +dcachesize = g_ascii_strtoull(toks[0], NULL, 10); +dassoc = g_ascii_strtoull(toks[1], NULL, 10); +dblksize = g_ascii_strtoull(toks[2], NULL, 10); +} else if (g_str_has_prefix(opt, "limit=")) { limit = g_ascii_strtoull(opt + 6, NULL, 10); +} else if (g_str_has_prefix(opt, "tracefile=")) { +char *file_name = opt + 10; +tracefile = fopen(file_name, "w"); +if (!tracefile) { +fprintf(stderr, "could not open: %s for writing\n", file_name); +} } else { fprintf(stderr, "option parsing failed: %s\n", opt); return -1; } } +if (bad_cache_params(iblksize, iassoc, icachesize)) { +fprintf(stderr, "icache cannot be constructed from given parameters\n"); +return -1; +} + +if (bad_cache_params(dblksize, dassoc, dcachesize)) { +fprintf(stderr, "dcache cannot be constructed from given parameters\n"); +return -1; +} + dcache = cache_init(dblksize, dassoc, dcachesize); icache = cache_init(iblksize, iassoc, icachesize); -- 2.25.1
[RFC PATCH 1/3] plugins: Added a new cache modelling plugin
Added a cache modelling plugin that uses a static configuration used in many of the commercial microprocessors and uses random eviction policy. Signed-off-by: Mahmoud Mandour --- contrib/plugins/Makefile | 1 + contrib/plugins/cache.c | 398 +++ 2 files changed, 399 insertions(+) create mode 100644 contrib/plugins/cache.c diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile index b9d7935e5e..2237b47f8b 100644 --- a/contrib/plugins/Makefile +++ b/contrib/plugins/Makefile @@ -18,6 +18,7 @@ NAMES += hotpages NAMES += howvec NAMES += lockstep NAMES += hwprofile +NAMES += cache SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES))) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c new file mode 100644 index 00..f8c15ebed2 --- /dev/null +++ b/contrib/plugins/cache.c @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2021, Mahmoud Mandour + * + * License: GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + +static GRand *rng; +static GHashTable *dmiss_ht; +static GHashTable *imiss_ht; + +static GMutex dmtx, imtx; + +static int limit; +static bool sys; + +static uint64_t dmem_accesses; +static uint64_t dmisses; + +static uint64_t imem_accesses; +static uint64_t imisses; + +static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW; + +enum AccessResult { +HIT = 0, +MISS = 1 +}; + +struct InsnData { +char *disas_str; +uint64_t addr; +uint64_t misses; +}; + +struct CacheBlock { +uint64_t tag; +bool valid; +}; + +struct CacheSet { +struct CacheBlock *blocks; +}; + +struct Cache { +struct CacheSet *sets; +int num_sets; + +int cachesize; +int blksize; +int assoc; + +uint64_t blk_mask; +uint64_t set_mask; +uint64_t tag_mask; +}; + +struct Cache *dcache, *icache; + +static int pow_of_two(int num) +{ +g_assert((num & (num - 1)) == 0); +int ret = 0; +while (num /= 2) { +ret++; +} +return ret; +} + +static inline uint64_t extract_tag(struct Cache *cache, uint64_t addr) +{ +return (addr & cache->tag_mask) >> +(pow_of_two(cache->num_sets) + pow_of_two(cache->blksize)); +} + +static inline uint64_t extract_set(struct Cache *cache, uint64_t addr) +{ +return (addr & cache->set_mask) >> (pow_of_two(cache->blksize)); +} + +static struct Cache *cache_init(int blksize, int assoc, int cachesize) +{ +struct Cache *cache; +int i; + +cache = g_new(struct Cache, 1); +cache->blksize = blksize; +cache->assoc = assoc; +cache->cachesize = cachesize; +cache->num_sets = cachesize / (blksize * assoc); +cache->sets = g_new(struct CacheSet, cache->num_sets); + +for (i = 0; i < cache->num_sets; i++) { +cache->sets[i].blocks = g_new0(struct CacheBlock, assoc); +} + +cache->blk_mask = blksize - 1; +cache->set_mask = ((cache->num_sets - 1) << (pow_of_two(cache->blksize))); +cache->tag_mask = ~(cache->set_mask | cache->blk_mask); + +return cache; +} + +static int get_invalid_block(struct Cache *cache, uint64_t set) +{ +int i; + +for (i = 0; i < cache->assoc; i++) { +if (!cache->sets[set].blocks[i].valid) { +/* conflict miss */ +return i; +} +} + +/* compulsary miss */ +return -1; +} + +static int get_replaced_block(struct Cache *cache) +{ +return g_rand_int_range(rng, 0, cache->assoc); +} + +static bool in_cache(struct Cache *cache, uint64_t addr) +{ +int i; +uint64_t tag, set; + +tag = extract_tag(cache, addr); +set = extract_set(cache, addr); + +for (i = 0; i < cache->assoc; i++) { +if (cache->sets[set].blocks[i].tag == tag && +cache->sets[set].blocks[i].valid) { +return true; +} +} + +return false; +} + +static enum AccessResult access_cache(struct Cache *cache, uint64_t addr) +{ +uint64_t tag, set; +int replaced_blk; + +if (in_cache(cache, addr)) { +return HIT; +} + +tag = extract_tag(cache, addr); +set = extract_set(cache, addr); + +replaced_blk = get_invalid_block(cache, set); + +if (replaced_blk == -1) { +replaced_blk = get_replaced_block(cache); +} + +cache->sets[set].blocks[replaced_blk].tag = tag; +cache->sets[set].blocks[replaced_blk].valid = true; + +return MISS; +} + +struct InsnData *get_or_create(GHashTable *ht, struct InsnData *insn_data, + uint64_t addr) +{ +struct InsnData *insn = g_hash_table_lookup(ht, GUINT_TO_POINTER(addr)); +if (!insn) { +g_hash_table_insert(ht, GUINT_TO_POINTER(addr), (gpointer) insn_data); +insn = insn_data; +} + +return insn; +} + +static void vcpu_mem_access(unsigned int cpu_index, qemu_plugin_meminfo_t inf
[PATCH] target/mips: Raise exception when DINSV opcode used with DSP disabled
Per the "MIPS® DSP Module for MIPS64 Architecture" manual, rev. 3.02, Table 5.3 "SPECIAL3 Encoding of Function Field for DSP Module": If the Module/ASE is not implemented, executing such an instruction must cause a Reserved Instruction Exception. The DINSV instruction lists the following exceptions: - Reserved Instruction - DSP Disabled If the MIPS core doesn't support the DSP module, or the DSP is disabled, do not handle the '$rt = $0' case as a no-op but raise the proper exception instead. Cc: Jia Liu Fixes: 1cb6686cf92 ("target-mips: Add ASE DSP bit/manipulation instructions") Signed-off-by: Philippe Mathieu-Daudé --- target/mips/tcg/translate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index c03a8ae1fed..6ccba34c050 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -24373,10 +24373,11 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx) { TCGv t0, t1; +check_dsp(ctx); + if (rt == 0) { break; } -check_dsp(ctx); t0 = tcg_temp_new(); t1 = tcg_temp_new(); -- 2.26.3
Re: [PATCH qemu v20] spapr: Implement Open Firmware client interface
On Thu, 20 May 2021, Alexey Kardashevskiy wrote: diff --git a/hw/ppc/spapr_vof.c b/hw/ppc/spapr_vof.c new file mode 100644 index ..5e34d5402abf --- /dev/null +++ b/hw/ppc/spapr_vof.c @@ -0,0 +1,156 @@ +/* + * SPAPR machine hooks to Virtual Open Firmware, + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include "qemu/osdep.h" +#include "qemu-common.h" +#include +#include "qapi/error.h" +#include "hw/ppc/spapr.h" +#include "hw/ppc/spapr_vio.h" +#include "hw/ppc/fdt.h" +#include "sysemu/sysemu.h" +#include "qom/qom-qobject.h" +#include "trace.h" + +/* Copied from SLOF, and 4K is definitely not enough for GRUB */ +#define OF_STACK_SIZE 0x8000 I found a reference explaining its value better than the comment above. Section 8.2.2 here: https://www.devicetree.org/open-firmware/bindings/ppc/release/ppc-2_1.html says it should be at least 32k. This define should be in vof.h so I don't have to duplicate it in pegasos2.c. Or vof_init could allocate and claim the stack so board code doesn't have to do that either. Maybe taking a pointer argument for preferred stack address as input and could return the aligned address where the stack was allocated or just store stack_base in struct vof where tha board code could get it for adding to r1 on calling the guest code. Regards, BALATON Zoltan
[PULL 0/2] Libslirp patches
From: Marc-André Lureau The following changes since commit 62c0ac5041e9130b041adfa13a41583d3c3ddd24: Merge remote-tracking branch 'remotes/rth-gitlab/tags/pull-tcg-20210526' into staging (2021-05-28 16:25:21 +0100) are available in the Git repository at: g...@github.com:elmarco/qemu.git tags/libslirp-pull-request for you to fetch changes up to b060428091c758781acc4d42849accc036d3c816: build-sys: make libslirp a meson subproject (2021-05-29 22:52:37 +0400) Update libslirp & make it a subproject Marc-André Lureau (2): Update libslirp to v4.5.0 build-sys: make libslirp a meson subproject configure| 2 +- meson.build | 63 +++- .gitmodules | 4 +-- slirp| 1 - subprojects/libslirp | 1 + 5 files changed, 8 insertions(+), 63 deletions(-) delete mode 16 slirp create mode 16 subprojects/libslirp -- 2.29.0
[PULL 1/2] Update libslirp to v4.5.0
From: Marc-André Lureau Switch from stable-4.2 branch to upstream v4.5.0 release. ## [4.5.0] - 2021-05-18 ### Added - IPv6 forwarding. !62 !75 !77 - slirp_neighbor_info() to dump the ARP/NDP tables. !71 ### Changed - Lazy guest address resolution for IPv6. !81 - Improve signal handling when spawning a child. !61 - Set macOS deployment target to macOS 10.4. !72 - slirp_add_hostfwd: Ensure all error paths set errno. !80 - More API documentation. ### Fixed - Assertion failure on unspecified IPv6 address. !86 - Disable polling for PRI on MacOS, fixing some closing streams issues. !73 - Various memory leak fixes on fastq/batchq. !68 - Memory leak on IPv6 fast-send. !67 - Slow socket response on Windows. !64 - Misc build and code cleanups. !60 !63 !76 !79 !84 ## [4.4.0] - 2020-12-02 ### Added - udp, udp6, icmp: handle TTL value. !48 - Enable forwarding ICMP errors. !49 - Add DNS resolving for iOS. !54 ### Changed - Improve meson subproject() support. !53 - Removed Makefile-based build system. !56 ### Fixed - socket: consume empty packets. !55 - check pkt_len before reading protocol header (CVE-2020-29129). !57 - ip_stripoptions use memmove (fixes undefined behaviour). !47 - various Coverity-related changes/fixes. ## [4.3.1] - 2020-07-08 ### Changed - A silent truncation could occur in `slirp_fmt()`, which will now print a critical message. See also #22. ### Fixed - CVE-2020-10756 - Drop bogus IPv6 messages that could lead to data leakage. See !44 and !42. - Fix win32 builds by using the SLIRP_PACKED definition. - Various coverity scan errors fixed. !41 - Fix new GCC warnings. !43 ## [4.3.0] - 2020-04-22 ### Added - `SLIRP_VERSION_STRING` macro, with the git sha suffix when building from git - `SlirpConfig.disable_dns`, to disable DNS redirection #16 ### Changed - `slirp_version_string()` now has the git sha suffix when building form git - Limit DNS redirection to port 53 #16 ### Fixed - Fix build regression with mingw & NetBSD - Fix use-afte-free in `ip_reass()` (CVE-2020-1983) Signed-off-by: Marc-André Lureau Reviewed-by: Doug Evans --- slirp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slirp b/slirp index 8f43a99191..a62890e711 16 --- a/slirp +++ b/slirp @@ -1 +1 @@ -Subproject commit 8f43a99191afb47ca3f3c6972f6306209f367ece +Subproject commit a62890e71126795ca593affa747f669bed88e89c -- 2.29.0
[PULL 2/2] build-sys: make libslirp a meson subproject
From: Marc-André Lureau Remove the manual build. Moving projects to subprojects/ is required when using meson subproject(): https://mesonbuild.com/Subprojects.html#why-must-all-subprojects-be-inside-a-single-directory Tested-by: Joelle van Dyne Signed-off-by: Marc-André Lureau --- configure | 2 +- meson.build | 63 +++ .gitmodules | 4 +-- slirp => subprojects/libslirp | 0 4 files changed, 7 insertions(+), 62 deletions(-) rename slirp => subprojects/libslirp (100%) diff --git a/configure b/configure index 90c0807347..b59ec8bd39 100755 --- a/configure +++ b/configure @@ -5279,7 +5279,7 @@ fi case "$slirp" in auto | enabled | internal) # Simpler to always update submodule, even if not needed. -git_submodules="${git_submodules} slirp" +git_submodules="${git_submodules} subprojects/libslirp" ;; esac diff --git a/meson.build b/meson.build index 20d7035e44..3bf0686985 100644 --- a/meson.build +++ b/meson.build @@ -1513,7 +1513,7 @@ slirp_opt = 'disabled' if have_system slirp_opt = get_option('slirp') if slirp_opt in ['enabled', 'auto', 'system'] -have_internal = fs.exists(meson.current_source_dir() / 'slirp/meson.build') +have_internal = fs.exists(meson.current_source_dir() / 'subprojects/libslirp/meson.build') slirp = dependency('slirp', kwargs: static_kwargs, method: 'pkg-config', required: slirp_opt == 'system' or @@ -1527,64 +1527,9 @@ if have_system endif endif if slirp_opt == 'internal' -slirp_deps = [] -if targetos == 'windows' - slirp_deps = cc.find_library('iphlpapi') -endif -slirp_conf = configuration_data() -slirp_conf.set('SLIRP_MAJOR_VERSION', meson.project_version().split('.')[0]) -slirp_conf.set('SLIRP_MINOR_VERSION', meson.project_version().split('.')[1]) -slirp_conf.set('SLIRP_MICRO_VERSION', meson.project_version().split('.')[2]) -slirp_conf.set_quoted('SLIRP_VERSION_STRING', meson.project_version()) -slirp_cargs = ['-DG_LOG_DOMAIN="Slirp"'] -slirp_files = [ - 'slirp/src/arp_table.c', - 'slirp/src/bootp.c', - 'slirp/src/cksum.c', - 'slirp/src/dhcpv6.c', - 'slirp/src/dnssearch.c', - 'slirp/src/if.c', - 'slirp/src/ip6_icmp.c', - 'slirp/src/ip6_input.c', - 'slirp/src/ip6_output.c', - 'slirp/src/ip_icmp.c', - 'slirp/src/ip_input.c', - 'slirp/src/ip_output.c', - 'slirp/src/mbuf.c', - 'slirp/src/misc.c', - 'slirp/src/ncsi.c', - 'slirp/src/ndp_table.c', - 'slirp/src/sbuf.c', - 'slirp/src/slirp.c', - 'slirp/src/socket.c', - 'slirp/src/state.c', - 'slirp/src/stream.c', - 'slirp/src/tcp_input.c', - 'slirp/src/tcp_output.c', - 'slirp/src/tcp_subr.c', - 'slirp/src/tcp_timer.c', - 'slirp/src/tftp.c', - 'slirp/src/udp.c', - 'slirp/src/udp6.c', - 'slirp/src/util.c', - 'slirp/src/version.c', - 'slirp/src/vmstate.c', -] - -configure_file( - input : 'slirp/src/libslirp-version.h.in', - output : 'libslirp-version.h', - configuration: slirp_conf) - -slirp_inc = include_directories('slirp', 'slirp/src') -libslirp = static_library('slirp', - build_by_default: false, - sources: slirp_files, - c_args: slirp_cargs, - include_directories: slirp_inc) -slirp = declare_dependency(link_with: libslirp, - dependencies: slirp_deps, - include_directories: slirp_inc) +libslirp = subproject('libslirp', + default_options: ['default_library=static']) +slirp = libslirp.get_variable('libslirp_dep') endif endif diff --git a/.gitmodules b/.gitmodules index 08b1b48a09..447bb3a4df 100644 --- a/.gitmodules +++ b/.gitmodules @@ -49,8 +49,8 @@ [submodule "roms/edk2"] path = roms/edk2 url = https://gitlab.com/qemu-project/edk2.git -[submodule "slirp"] - path = slirp +[submodule "subprojects/libslirp"] + path = subprojects/libslirp url = https://gitlab.com/qemu-project/libslirp.git [submodule "roms/opensbi"] path = roms/opensbi diff --git a/slirp b/subprojects/libslirp similarity index 100% rename from slirp rename to subprojects/libslirp -- 2.29.0
Re: [PATCH] target/mips: Raise exception when DINSV opcode used with DSP disabled
On 5/29/21 9:54 AM, Philippe Mathieu-Daudé wrote: Per the "MIPS® DSP Module for MIPS64 Architecture" manual, rev. 3.02, Table 5.3 "SPECIAL3 Encoding of Function Field for DSP Module": If the Module/ASE is not implemented, executing such an instruction must cause a Reserved Instruction Exception. The DINSV instruction lists the following exceptions: - Reserved Instruction - DSP Disabled If the MIPS core doesn't support the DSP module, or the DSP is disabled, do not handle the '$rt = $0' case as a no-op but raise the proper exception instead. Cc: Jia Liu Fixes: 1cb6686cf92 ("target-mips: Add ASE DSP bit/manipulation instructions") Signed-off-by: Philippe Mathieu-Daudé --- target/mips/tcg/translate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) Reviewed-by: Richard Henderson r~
Re: [PATCH] docs/devel: Explain in more detail the TB chaining mechanisms
On 5/28/21 1:15 PM, Luis Fernando Fujita Pires wrote: From: Richard Henderson More completely, update the CPU state with any information that has been assumed constant. For most guests, this is just the PC. But e.g. for hppa this is both iaoq.f (cip) and iaoq.b (nip). It is very much up to the guest to determine the set of data that is present in cpu_get_tb_cpu_state, and what can be assumed across the break. I’m not sure I understand what “assumed constant” means in this context. The pc of the branch destination is a constant, for instance. As would be the enabled instruction set (consider arm's blx, which toggles between arm and thumb isa). Would it be fair to say that step 2 should update any CPU state information that is required by the main loop to correctly locate and execute the next TB, but not anything that would be needed if we were to jump directly from step 1 to the first instruction in the next TB without going through the main loop? The information written in step 2, omitted by step 1, must be inferable from cpu_get_tb_cpu_state (via tcg_ops->synchronize_from_tb) and from cpu_restore_state. One of the two forms is how we return to the main loop after escaping from the chain of TB via interrupt or exception, respectively. r~
Google summer program
Hello i just saw the application you are developing from google summer of code and i'm curious about it what prerequisites that i need to learn so i can contribute in the application thanks in advance
[RFC PATCH v2 1/3] plugins: Added a new cache modelling plugin
Added a cache modelling plugin that uses a static configuration used in many of the commercial microprocessors and uses random eviction policy. Signed-off-by: Mahmoud Mandour --- contrib/plugins/Makefile | 1 + contrib/plugins/cache.c | 398 +++ 2 files changed, 399 insertions(+) create mode 100644 contrib/plugins/cache.c diff --git a/contrib/plugins/Makefile b/contrib/plugins/Makefile index b9d7935e5e..2237b47f8b 100644 --- a/contrib/plugins/Makefile +++ b/contrib/plugins/Makefile @@ -18,6 +18,7 @@ NAMES += hotpages NAMES += howvec NAMES += lockstep NAMES += hwprofile +NAMES += cache SONAMES := $(addsuffix .so,$(addprefix lib,$(NAMES))) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c new file mode 100644 index 00..8c9d1dd538 --- /dev/null +++ b/contrib/plugins/cache.c @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2021, Mahmoud Mandour + * + * License: GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; + +static GRand *rng; +static GHashTable *dmiss_ht; +static GHashTable *imiss_ht; + +static GMutex dmtx, imtx; + +static int limit; +static bool sys; + +static uint64_t dmem_accesses; +static uint64_t dmisses; + +static uint64_t imem_accesses; +static uint64_t imisses; + +static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW; + +enum AccessResult { +HIT = 0, +MISS = 1 +}; + +struct InsnData { +char *disas_str; +uint64_t addr; +uint64_t misses; +}; + +struct CacheBlock { +uint64_t tag; +bool valid; +}; + +struct CacheSet { +struct CacheBlock *blocks; +}; + +struct Cache { +struct CacheSet *sets; +int num_sets; + +int cachesize; +int blksize; +int assoc; + +uint64_t blk_mask; +uint64_t set_mask; +uint64_t tag_mask; +}; + +struct Cache *dcache, *icache; + +static int pow_of_two(int num) +{ +g_assert((num & (num - 1)) == 0); +int ret = 0; +while (num /= 2) { +ret++; +} +return ret; +} + +static inline uint64_t extract_tag(struct Cache *cache, uint64_t addr) +{ +return (addr & cache->tag_mask) >> +(pow_of_two(cache->num_sets) + pow_of_two(cache->blksize)); +} + +static inline uint64_t extract_set(struct Cache *cache, uint64_t addr) +{ +return (addr & cache->set_mask) >> (pow_of_two(cache->blksize)); +} + +static struct Cache *cache_init(int blksize, int assoc, int cachesize) +{ +struct Cache *cache; +int i; + +cache = g_new(struct Cache, 1); +cache->blksize = blksize; +cache->assoc = assoc; +cache->cachesize = cachesize; +cache->num_sets = cachesize / (blksize * assoc); +cache->sets = g_new(struct CacheSet, cache->num_sets); + +for (i = 0; i < cache->num_sets; i++) { +cache->sets[i].blocks = g_new0(struct CacheBlock, assoc); +} + +cache->blk_mask = blksize - 1; +cache->set_mask = ((cache->num_sets - 1) << (pow_of_two(cache->blksize))); +cache->tag_mask = ~(cache->set_mask | cache->blk_mask); + +return cache; +} + +static int get_invalid_block(struct Cache *cache, uint64_t set) +{ +int i; + +for (i = 0; i < cache->assoc; i++) { +if (!cache->sets[set].blocks[i].valid) { +/* conflict miss */ +return i; +} +} + +/* compulsary miss */ +return -1; +} + +static int get_replaced_block(struct Cache *cache) +{ +return g_rand_int_range(rng, 0, cache->assoc); +} + +static bool in_cache(struct Cache *cache, uint64_t addr) +{ +int i; +uint64_t tag, set; + +tag = extract_tag(cache, addr); +set = extract_set(cache, addr); + +for (i = 0; i < cache->assoc; i++) { +if (cache->sets[set].blocks[i].tag == tag && +cache->sets[set].blocks[i].valid) { +return true; +} +} + +return false; +} + +static enum AccessResult access_cache(struct Cache *cache, uint64_t addr) +{ +uint64_t tag, set; +int replaced_blk; + +if (in_cache(cache, addr)) { +return HIT; +} + +tag = extract_tag(cache, addr); +set = extract_set(cache, addr); + +replaced_blk = get_invalid_block(cache, set); + +if (replaced_blk == -1) { +replaced_blk = get_replaced_block(cache); +} + +cache->sets[set].blocks[replaced_blk].tag = tag; +cache->sets[set].blocks[replaced_blk].valid = true; + +return MISS; +} + +struct InsnData *get_or_create(GHashTable *ht, struct InsnData *insn_data, + uint64_t addr) +{ +struct InsnData *insn = g_hash_table_lookup(ht, GUINT_TO_POINTER(addr)); +if (!insn) { +g_hash_table_insert(ht, GUINT_TO_POINTER(addr), (gpointer) insn_data); +insn = insn_data; +} + +return insn; +} + +static void vcpu_mem_access(unsigned int cpu_index, qemu_plugin_meminfo_t inf
Re: [RFC PATCH 0/3] Cache modelling TCG plugin
Cc'ing Emilio too. On 5/29/21 5:22 PM, Mahmoud Mandour wrote: > In this RFC patch series, I propose an initial cache modelling TCG > plugin. As of now, it models separate L1 data cache and L1 instruction > cache. It supports three eviction policies: LRU, random, and FIFO. Once > a policy is chosen, it's used for both instruction and data caches. > > Mahmoud Mandour (3): > plugins: Added a new cache modelling plugin > plugins: cache: Enabled parameterization and added trace printing > plugins: cache: Added FIFO and LRU eviction policies. > > contrib/plugins/Makefile | 1 + > contrib/plugins/cache.c | 595 +++ > 2 files changed, 596 insertions(+) > create mode 100644 contrib/plugins/cache.c >
[RFC PATCH v2 0/3] Cache modelling TCG plugin
In this RFC patch series, I propose an initial cache modelling TCG plugin. As of now, it models separate L1 data cache and L1 instruction cache. It supports three eviction policies: LRU, random, and FIFO. Once a policy is chosen, it's used for both instruction and data caches. v1 -> v2: Unlocked dmtx on early return in vcpu_mem_access & removed a (probably?) bad InsnData free. This is probably still problematic since it does not free the ``idata`` allocated for the vcpu_mem_access callback even once, but if it's placed, it would double-free it. How do I mitigate this? I need to free the InsnData passed to vcpu_mem_access only once if we find out that it's an IO access since we do not need it anymore and it will early return every time. Mahmoud Mandour (3): plugins: Added a new cache modelling plugin plugins: cache: Enabled parameterization and added trace printing plugins: cache: Added FIFO and LRU eviction policies. contrib/plugins/Makefile | 1 + contrib/plugins/cache.c | 595 +++ 2 files changed, 596 insertions(+) create mode 100644 contrib/plugins/cache.c -- 2.25.1
[RFC PATCH v2 3/3] plugins: cache: Added FIFO and LRU eviction policies.
Now one of the three eviction policies can be chosen as an argument. On not specifying an argument, LRU is used by default. Signed-off-by: Mahmoud Mandour --- contrib/plugins/cache.c | 159 1 file changed, 146 insertions(+), 13 deletions(-) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index fa0bf1dd40..1e323494bf 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -18,6 +18,8 @@ QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION; +static bool fifo, lru, rnd; + static GRand *rng; static GHashTable *dmiss_ht; static GHashTable *imiss_ht; @@ -55,6 +57,8 @@ struct CacheBlock { struct CacheSet { struct CacheBlock *blocks; +uint16_t *priorities; +GQueue *evict_queue; }; struct Cache { @@ -93,6 +97,84 @@ static inline uint64_t extract_set(struct Cache *cache, uint64_t addr) return (addr & cache->set_mask) >> (pow_of_two(cache->blksize)); } +static void lru_priorities_init(struct Cache *cache) +{ +int i, j; + +for (i = 0; i < cache->num_sets; i++) { +cache->sets[i].priorities = g_new(uint16_t, cache->assoc); +for (j = 0; j < cache->assoc; j++) { +cache->sets[i].priorities[j] = cache->assoc - j - 1; +} +} +} + +static void lru_update_on_miss(struct Cache *cache, + int set_idx, + int blk_idx) +{ +int i; + +for (i = 0; i < cache->assoc; i++) { +cache->sets[set_idx].priorities[i]++; +} + +cache->sets[set_idx].priorities[blk_idx] = 0; +} + +static void lru_update_on_hit(struct Cache *cache, + int set_idx, + int blk_idx) +{ +uint16_t blk_priority; +int i; + +blk_priority = cache->sets[set_idx].priorities[blk_idx]; +for (i = 0; i < cache->assoc; i++) { +if (cache->sets[set_idx].priorities[i] < blk_priority) { +cache->sets[set_idx].priorities[i]++; +} +} +cache->sets[set_idx].priorities[blk_idx] = 0; +} + +static int lru_get_lru_block(struct Cache *cache, int set_idx) +{ +int i; + +for (i = 0; i < cache->assoc; i++) { +if (cache->sets[set_idx].priorities[i] == cache->assoc - 1) { +return i; +} +} + +g_assert_not_reached(); +} + +static void fifo_init(struct Cache *cache) +{ +int i; + +for (i = 0; i < cache->num_sets; i++) { +cache->sets[i].evict_queue = g_queue_new(); +} +} + +static int fifo_get_first_in_block(struct Cache *cache, int set) +{ +GQueue *q = cache->sets[set].evict_queue; +return GPOINTER_TO_INT(g_queue_pop_tail(q)); +} + +static void fifo_update_on_miss(struct Cache *cache, +int set, +int blk_idx) +{ +GQueue *q = cache->sets[set].evict_queue; +g_queue_push_head(q, GINT_TO_POINTER(blk_idx)); +} + + static struct Cache *cache_init(int blksize, int assoc, int cachesize) { struct Cache *cache; @@ -113,6 +195,12 @@ static struct Cache *cache_init(int blksize, int assoc, int cachesize) cache->set_mask = ((cache->num_sets - 1) << (pow_of_two(cache->blksize))); cache->tag_mask = ~(cache->set_mask | cache->blk_mask); +if (lru) { +lru_priorities_init(cache); +} else if (fifo) { +fifo_init(cache); +} + return cache; } @@ -131,12 +219,20 @@ static int get_invalid_block(struct Cache *cache, uint64_t set) return -1; } -static int get_replaced_block(struct Cache *cache) +static int get_replaced_block(struct Cache *cache, int set) { -return g_rand_int_range(rng, 0, cache->assoc); +if (rnd) { +return g_rand_int_range(rng, 0, cache->assoc); +} else if (lru) { +return lru_get_lru_block(cache, set); +} else if (fifo) { +return fifo_get_first_in_block(cache, set); +} + +g_assert_not_reached(); } -static bool in_cache(struct Cache *cache, uint64_t addr) +static int in_cache(struct Cache *cache, uint64_t addr) { int i; uint64_t tag, set; @@ -147,29 +243,39 @@ static bool in_cache(struct Cache *cache, uint64_t addr) for (i = 0; i < cache->assoc; i++) { if (cache->sets[set].blocks[i].tag == tag && cache->sets[set].blocks[i].valid) { -return true; +return i; } } -return false; +return -1; } static enum AccessResult access_cache(struct Cache *cache, uint64_t addr) { uint64_t tag, set; -int replaced_blk; - -if (in_cache(cache, addr)) { -return HIT; -} +int hit_blk, replaced_blk; tag = extract_tag(cache, addr); set = extract_set(cache, addr); +hit_blk = in_cache(cache, addr); + +if (hit_blk != -1) { +if (lru) { +lru_update_on_hit(cache, set, hit_blk); +} +return HIT; +} replaced_blk = get_i
[RFC PATCH v2 2/3] plugins: cache: Enabled parameterization and added trace printing
Made both icache and dcache configurable through plugin arguments and added memory trace printing in a separate file. Signed-off-by: Mahmoud Mandour --- contrib/plugins/cache.c | 68 +++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index 8c9d1dd538..fa0bf1dd40 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -22,7 +22,7 @@ static GRand *rng; static GHashTable *dmiss_ht; static GHashTable *imiss_ht; -static GMutex dmtx, imtx; +static GMutex dmtx, imtx, fmtx; static int limit; static bool sys; @@ -33,6 +33,8 @@ static uint64_t dmisses; static uint64_t imem_accesses; static uint64_t imisses; +FILE *tracefile; + static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW; enum AccessResult { @@ -205,6 +207,16 @@ static void vcpu_mem_access(unsigned int cpu_index, qemu_plugin_meminfo_t info, insn_addr = ((struct InsnData *) userdata)->addr; effective_addr = hwaddr ? qemu_plugin_hwaddr_phys_addr(hwaddr) : vaddr; +if (tracefile) { +g_mutex_lock(&fmtx); +g_autoptr(GString) rep = g_string_new(""); +bool is_store = qemu_plugin_mem_is_store(info); +g_string_append_printf(rep, "%c: 0x%" PRIx64, +is_store ? 'S' : 'L', effective_addr); +fprintf(tracefile, "%s\n", rep->str); +g_mutex_unlock(&fmtx); +} + if (access_cache(dcache, effective_addr) == MISS) { struct InsnData *insn = get_or_create(dmiss_ht, userdata, insn_addr); insn->misses++; @@ -221,11 +233,20 @@ static void vcpu_insn_exec(unsigned int vcpu_index, void *userdata) g_mutex_lock(&imtx); addr = ((struct InsnData *) userdata)->addr; +if (tracefile) { +g_mutex_lock(&fmtx); +g_autoptr(GString) rep = g_string_new(""); +g_string_append_printf(rep, "I: 0x%" PRIx64, addr); +fprintf(tracefile, "%s\n", rep->str); +g_mutex_unlock(&fmtx); +} + if (access_cache(icache, addr) == MISS) { struct InsnData *insn = get_or_create(imiss_ht, userdata, addr); insn->misses++; imisses++; } + imem_accesses++; g_mutex_unlock(&imtx); } @@ -352,6 +373,15 @@ static void plugin_exit() g_mutex_unlock(&dmtx); g_mutex_unlock(&imtx); + +if (tracefile) { +fclose(tracefile); +} +} + +static bool bad_cache_params(int blksize, int assoc, int cachesize) +{ +return (cachesize % blksize) != 0 || (cachesize % (blksize * assoc) != 0); } QEMU_PLUGIN_EXPORT @@ -377,14 +407,48 @@ int qemu_plugin_install(qemu_plugin_id_t id, const qemu_info_t *info, for (i = 0; i < argc; i++) { char *opt = argv[i]; -if (g_str_has_prefix(opt, "limit=")) { +if (g_str_has_prefix(opt, "I=")) { +gchar **toks = g_strsplit(opt + 2, " ", -1); +if (g_strv_length(toks) != 3) { +fprintf(stderr, "option parsing failed: %s\n", opt); +return -1; +} +icachesize = g_ascii_strtoull(toks[0], NULL, 10); +iassoc = g_ascii_strtoull(toks[1], NULL, 10); +iblksize = g_ascii_strtoull(toks[2], NULL, 10); +} else if (g_str_has_prefix(opt, "D=")) { +gchar **toks = g_strsplit(opt + 2, " ", -1); +if (g_strv_length(toks) != 3) { +fprintf(stderr, "option parsing failed: %s\n", opt); +return -1; +} +dcachesize = g_ascii_strtoull(toks[0], NULL, 10); +dassoc = g_ascii_strtoull(toks[1], NULL, 10); +dblksize = g_ascii_strtoull(toks[2], NULL, 10); +} else if (g_str_has_prefix(opt, "limit=")) { limit = g_ascii_strtoull(opt + 6, NULL, 10); +} else if (g_str_has_prefix(opt, "tracefile=")) { +char *file_name = opt + 10; +tracefile = fopen(file_name, "w"); +if (!tracefile) { +fprintf(stderr, "could not open: %s for writing\n", file_name); +} } else { fprintf(stderr, "option parsing failed: %s\n", opt); return -1; } } +if (bad_cache_params(iblksize, iassoc, icachesize)) { +fprintf(stderr, "icache cannot be constructed from given parameters\n"); +return -1; +} + +if (bad_cache_params(dblksize, dassoc, dcachesize)) { +fprintf(stderr, "dcache cannot be constructed from given parameters\n"); +return -1; +} + dcache = cache_init(dblksize, dassoc, dcachesize); icache = cache_init(iblksize, iassoc, icachesize); -- 2.25.1
Re: [RFC PATCH 0/3] Cache modelling TCG plugin
Thank you, I'll also CC Emilio in the v2 of this series. On Sun, May 30, 2021 at 8:36 AM Philippe Mathieu-Daudé wrote: > Cc'ing Emilio too. > > On 5/29/21 5:22 PM, Mahmoud Mandour wrote: > > In this RFC patch series, I propose an initial cache modelling TCG > > plugin. As of now, it models separate L1 data cache and L1 instruction > > cache. It supports three eviction policies: LRU, random, and FIFO. Once > > a policy is chosen, it's used for both instruction and data caches. > > > > Mahmoud Mandour (3): > > plugins: Added a new cache modelling plugin > > plugins: cache: Enabled parameterization and added trace printing > > plugins: cache: Added FIFO and LRU eviction policies. > > > > contrib/plugins/Makefile | 1 + > > contrib/plugins/cache.c | 595 +++ > > 2 files changed, 596 insertions(+) > > create mode 100644 contrib/plugins/cache.c > > > >
Re: [RFC PATCH v2 0/3] Cache modelling TCG plugin
On Sun, May 30, 2021 at 8:37 AM Mahmoud Mandour wrote: > In this RFC patch series, I propose an initial cache modelling TCG > plugin. As of now, it models separate L1 data cache and L1 instruction > cache. It supports three eviction policies: LRU, random, and FIFO. Once > a policy is chosen, it's used for both instruction and data caches. > > v1 -> v2: Unlocked dmtx on early return in vcpu_mem_access & removed a > (probably?) bad InsnData free. > This is probably still problematic since it does not free the > ``idata`` allocated for the vcpu_mem_access callback even > once, but if it's placed, it would double-free it. > How do I mitigate this? I need to free the InsnData passed to > vcpu_mem_access only once if we find out that it's an IO > access since we do not need it anymore and it will early > return every time. > > Mahmoud Mandour (3): > plugins: Added a new cache modelling plugin > plugins: cache: Enabled parameterization and added trace printing > plugins: cache: Added FIFO and LRU eviction policies. > > contrib/plugins/Makefile | 1 + > contrib/plugins/cache.c | 595 +++ > 2 files changed, 596 insertions(+) > create mode 100644 contrib/plugins/cache.c > > -- > 2.25.1 > >
Re: [PATCH] target/mips: Fix DBALIGN DSP-R2 opcode 'byte position' field size
On 5/29/21 3:05 PM, Philippe Mathieu-Daudé wrote: > Per the "MIPS® DSP Module for MIPS64 Architecture" manual (rev 3.02), > Figure 5.12 "SPECIAL3 Encoding of APPEND/DAPPEND Instruction Sub-class" > the byte position field ('bp') is 2 bits, not 3. > > Cc: Jia Liu > Fixes: 26690560240 ("target-mips: Add ASE DSP compare-pick instructions") > Signed-off-by: Philippe Mathieu-Daudé > --- > target/mips/tcg/translate.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c > index c03a8ae1fed..e68647ce14c 100644 > --- a/target/mips/tcg/translate.c > +++ b/target/mips/tcg/translate.c > @@ -23016,8 +23016,8 @@ static void gen_mipsdsp_append(CPUMIPSState *env, > DisasContext *ctx, > } > break; > case OPC_DBALIGN: > -sa &= 7; > -if (sa != 0 && sa != 2 && sa != 4) { > +sa &= 3; > +if (sa != 0 && sa != 2) { > tcg_gen_shli_tl(cpu_gpr[rt], cpu_gpr[rt], 8 * sa); > tcg_gen_shri_tl(t0, t0, 8 * (8 - sa)); > tcg_gen_or_tl(cpu_gpr[rt], cpu_gpr[rt], t0); > Looking at GCC, there is a patch adding this opcode: https://gcc.gnu.org/legacy-ml/gcc-patches/2012-02/msg00127.html which uses 2 bits: +(define_insn "mips_dbalign" + [(set (match_operand:DI 0 "register_operand" "=d") + (unspec:DI [(match_operand:DI 1 "register_operand" "0") + (match_operand:DI 2 "reg_or_0_operand" "dJ") + (match_operand:DI 3 "const_int_operand" "n")] + UNSPEC_DBALIGN))] + "ISA_HAS_DSPR2" +{ + if (INTVAL (operands[3]) & ~(unsigned HOST_WIDE_INT) 3) +operands[2] = GEN_INT (INTVAL (operands[2]) & 3); + return "dbalign\t%0,%z2,%3"; +} + [(set_attr "type""arith") + (set_attr "mode""DI")]) However looking at the releases/gcc-11.1.0 tag it seems GCC never supported DBALIGN...: https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/config/mips/mips-dspr2.md;h=95ba712f6a12946100cd4fe98d05732e70de8f98;hb=50bc9185c2821350f0b785d6e23a6e9dcde58466