qemu-ppc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: e6500 stvx instruction


From: BALATON Zoltan
Subject: Re: e6500 stvx instruction
Date: Fri, 18 Jun 2021 03:11:19 +0200 (CEST)

On Thu, 17 Jun 2021, Fabiano Rosas wrote:
BALATON Zoltan <balaton@eik.bme.hu> writes:
On Wed, 16 Jun 2021, Mark Cave-Ayland wrote:
On 16/06/2021 10:57, BALATON Zoltan wrote:
Ah. thanks. I've missed that as I've only looked in .c files and it's in
.c.inc. If I get this macro correctly it pastes name to gen_st so I expect
to see a GEN_VR_STX(vx,...) somewhere for stvx but I can only find:

GEN_VR_STX(svx, 0x07, 0x07);
/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
GEN_VR_STX(svxl, 0x07, 0x0F);

so where is stvx defined at the end or how does this work?

Then I've checked the opcode above: 0x7e8029ce which seems to be
1f-07-07-00 so the GEN_VR_STX(svx, 0x07, 0x07) seems to match that.

From this you can see the exception is thrown if ctx->altivec_enabled
isn't true, where ctx->altivec_enabled is set in
ppc_tr_init_disas_context() to:

   ctx->altivec_enabled = (hflags >> HFLAGS_VR) & 1;

It seems the issue is that somehow HFLAGS_VR isn't being set from the
CPUPPCState env->flags in hreg_compute_hflags_value(). There was a recent
patchset from Richard that tidied up the hflags (see
https://patchew.org/QEMU/20210323184340.619757-1-richard.henderson@linaro.org/)
so it could be the issue was accidentally introduced there.

As far as I could trace this back MSR_VR that should correspond to
HFLAGS_VR is turned on by POWERPC_FLAG_VRE which is set in
PowerPCCPUClass::flags in POWERPC_FAMILY(e6500) in cpu_init.c (the last
thing in that function). This is done in hreg_compute_hflags_value(). Other
than that HFLAGS_VR only appears in ppc_tr_init_disas_context() so probably
this should correspond to MSR_VR which the e6500 manual calls MSR[SPV] and
seems to be off in the register dump above. So maybe it's a guest bug
trying to execute Altivec instruction without enabling the vector unit?

I guess it could be either the guest is trying to execute Altivec
instructions without configuring the MSR correctly, or perhaps that the
default value of the MSR is incorrect and should have the SPV bit set for
that particular CPU?

From the e6500 manual:

"11.4.5 MSR, FPSCR, and VSCR

At reset, the MSR, FPSCR, and VSCR of each thread are set to 0. The FPSCR
and VSCR do not require initialization and can be set at a later time
before floating-point or AltiVec is used depending on which modes software
wishes to operate in."

So this suggests it's not a problem with defaults unless the manual is
wrong or there's some interaction between regs that should turn this bit
on while setting another reg.

Then there may be two bugs: one that we don't have a handler for this
exception to raise it in the guest and another in the guest that it does
not init MSR properly. On a real machine the firmware may do it, so maybe
we could do that in reset method if it works with u-boot as the problem
was reported using -kernel but I think the ppce500 machine did not expect
to have e6500 CPU so it probably does not try to do anything with this.
It's probably a kind of imaginary machine (ppce500 with -cpu e6500) not
emulating any real machine.

It seems that when altivec support was added to the e6500 kernel in
2012[1], the QEMU code was not changed, so we don't register the
VPU/VPUA exceptions in init_excp_e200. And due to the way
spr_write_excp_vector works, when the kernel code tries to write the
IVOR for altivec exceptions, it ends up writing over SPEU (#32) and
DFPDI (#33) instead.

arch/powerpc/kernel/exceptions-64e.S:

_GLOBAL(setup_altivec_ivors)
        SET_IVOR(32, 0x200) /* AltiVec Unavailable */
        SET_IVOR(33, 0x220) /* AltiVec Assist */
        blr


target/ppc/translate.c:

void spr_write_excp_vector(DisasContext *ctx, int sprn, int gprn)
{
   int sprn_offs;

   if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) {
       sprn_offs = sprn - SPR_BOOKE_IVOR0;
   } else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) {
       sprn_offs = sprn - SPR_BOOKE_IVOR32 + 32;
   } else if (sprn >= SPR_BOOKE_IVOR38 && sprn <= SPR_BOOKE_IVOR42) {
       sprn_offs = sprn - SPR_BOOKE_IVOR38 + 38;
   } else {
       printf("Trying to write an unknown exception vector %d %03x\n",
              sprn, sprn);
       gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
       return;
   }

   TCGv t0 = tcg_temp_new();
   tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUPPCState, ivor_mask));
   tcg_gen_and_tl(t0, t0, cpu_gpr[gprn]);
   tcg_gen_st_tl(t0, cpu_env, offsetof(CPUPPCState, excp_vectors[sprn_offs])); 
<-- HERE
   gen_store_spr(sprn, t0);
   tcg_temp_free(t0);
}


runtime:

Thread 4 "qemu-system-ppc" hit Breakpoint 1, spr_write_excp_vector
(gdb) p sprn_offs
$6 = 32

Thread 4 "qemu-system-ppc" hit Breakpoint 2, powerpc_excp
(gdb) p/x env->excp_vectors[32] <-- SPEU
$1 = 0x1200
(gdb) p/x env->excp_vectors[33] <-- DFPDI
$2 = 0x1220

So spr_write_excp_vector depends on the order of the exceptions in the
POWERPC_EXCP enum matching the IVOR# that corresponds to that
exception. If I move VPU/VPUA to index 32/33 I can get the machine to
boot further (just a debug hack):

Thanks for debugging this, I've also got to the conclusion that it's missing IVORs causing this problem. The e6500 docs (see below) say that these indeed should be IVOR32 and 33 so this may not be just a debug hack but what is needed for e6500 but I'm not sure if other cores may put other exceptions on these IVORs and if so what to do with that.

diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index b4de0db7ff..ec2469cb28 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -66,8 +66,8 @@ enum {
    POWERPC_EXCP_ITLB     = 14, /* Instruction TLB miss                      */
    POWERPC_EXCP_DEBUG    = 15, /* Debug interrupt                           */
    /* Vectors 16 to 31 are reserved                                         */
-    POWERPC_EXCP_SPEU     = 32, /* SPE/embedded floating-point unavailable   */
-    POWERPC_EXCP_EFPDI    = 33, /* Embedded floating-point data interrupt    */
+    POWERPC_EXCP_VPU     = 32,
+    POWERPC_EXCP_VPUA    = 33,
    POWERPC_EXCP_EFPRI    = 34, /* Embedded floating-point round interrupt   */
    POWERPC_EXCP_EPERFM   = 35, /* Embedded performance monitor interrupt    */
    POWERPC_EXCP_DOORI    = 36, /* Embedded doorbell interrupt               */
@@ -86,7 +86,7 @@ enum {
    POWERPC_EXCP_HISI     = 70, /* Hypervisor instruction storage exception  */
    POWERPC_EXCP_HDSEG    = 71, /* Hypervisor data segment exception         */
    POWERPC_EXCP_HISEG    = 72, /* Hypervisor instruction segment exception  */
-    POWERPC_EXCP_VPU      = 73, /* Vector unavailable exception              */
+    POWERPC_EXCP_SPEU      = 73,
    /* 40x specific exceptions                                               */
    POWERPC_EXCP_PIT      = 74, /* Programmable interval timer interrupt     */
    /* 601 specific exceptions                                               */
@@ -107,7 +107,7 @@ enum {
    /* 7xx/74xx specific exceptions                                          */
    POWERPC_EXCP_THERM    = 86, /* Thermal interrupt                         */
    /* 74xx specific exceptions                                              */
-    POWERPC_EXCP_VPUA     = 87, /* Vector assist exception                   */
+    POWERPC_EXCP_EFPDI     = 87,
    /* 970FX specific exceptions                                             */
    POWERPC_EXCP_SOFTP    = 88, /* Soft patch exception                      */
    POWERPC_EXCP_MAINT    = 89, /* Maintenance exception                     */
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index d0411e7302..a33c3c36a1 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -2277,6 +2277,8 @@ static void init_excp_e200(CPUPPCState *env, target_ulong 
ivpr_mask)
    env->excp_vectors[POWERPC_EXCP_SPEU]     = 0x00000000;
    env->excp_vectors[POWERPC_EXCP_EFPDI]    = 0x00000000;
    env->excp_vectors[POWERPC_EXCP_EFPRI]    = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_VPU]    = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_VPUA]    = 0x00000000;
    env->ivor_mask = 0x0000FFF7UL;
    env->ivpr_mask = ivpr_mask;
    /* Hardware reset vector */

I've also ended up at these functions and noticed that these could be simplified by chaining them as they are done from POWER7 upwards. But I'm not sure these are left as they are because they have to be checked against corresponding docs or were just copy&pasted and modified for adding new models. One suspicious part (but unrelated to this thread) that I've noticed is that init_excp_MPC5xx and init_excp_MPC8xx has

    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000900;
    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;

Is that a typo and should one be 800?

As for this problem with e6500 probably we need a new init_excp function for e6500 as the e200 one is used for all e500 cores most of which don't have altivec so we can't just add these to init_excp_e200 I think. I've tried to do the above clean up but stopped because I don't have enough knowledge about different cores to know if these are correct and had no time to dig up and check each manual so I hope somebody with more knowledge about different PPC chips can do it.

---

$ qemu-system-ppc64 -nographic -machine ppce500 -cpu e6500 -serial \
mon:stdio -smp 2 -m 1024 -kernel book3e_e6500_kernel_5.12.10 -append \
"root=/dev/vda1 rw" -drive \
format=qcow2,file=hdd_debian_sid_ppc64_basic.qcow2,index=0,if=virtio \
 (...)
 Run /sbin/init as init process
 random: fast init done
 systemd[1]: systemd 247.3-5 running in system mode. (+PAM +AUDIT
 +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT
 +GNUTLS +ACL +XZ +LZ4 +ZSTD +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN
 +PCRE2
 default-hierarchy=unified)
 systemd[1]: Detected architecture ppc64.

 Welcome to Debian GNU/Linux 11 (bullseye)!

 systemd[1]: Set hostname to <debianppc64>.
 (...)


Unfornately, the boot still fails further down the line due to:

Bad kernel stack pointer 3fffe830c200 at c000000000052afc
Oops: Bad kernel stack pointer, sig: 6 [#17]

But I suspect this is another issue by itself.

I did not get to that point yet so no idea but Mario said the same worked on real hardware so maybe another bug.

So the question is: If SPEU/DPFDI and VPU/VPUA share IVOR#, is one them
being incorrectly registered for e6500?

According to docs at https://www.nxp.com/docs/en/reference-manual/E6500RM.pdf Table 4-2 on page 4-9 IVOR32 and 33 are Altivec exceptions while Floating pont unavailable is IVOR7. Not sure what DPFDI is but the table does not list anything similar as far as I can tell.

Regards,
BALATON Zoltan

reply via email to

[Prev in Thread] Current Thread [Next in Thread]