[PATCH 02/23] Added CPU loop function

Ajeet Singh posted 23 patches 5 months, 1 week ago
Only 22 patches received!
There is a newer version of this series
[PATCH 02/23] Added CPU loop function
Posted by Ajeet Singh 5 months, 1 week ago
From: Stacey Son <sson@FreeBSD.org>

CPU loop function to handle exceptions
and emulate execution of instructions

Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Ajeet Singh <itachis@FreeBSD.org>
Co-authored-by: Kyle Evans <kevans@freebsd.org>
Co-authored-by: Sean Bruno <sbruno@freebsd.org>
Co-authored-by: Jessica Clarke <jrtc27@jrtc27.com>
---
 bsd-user/aarch64/target_arch_cpu.h | 132 +++++++++++++++++++++++++++++
 1 file changed, 132 insertions(+)

diff --git a/bsd-user/aarch64/target_arch_cpu.h b/bsd-user/aarch64/target_arch_cpu.h
index db5c7062b9..1962d2c99b 100644
--- a/bsd-user/aarch64/target_arch_cpu.h
+++ b/bsd-user/aarch64/target_arch_cpu.h
@@ -40,3 +40,135 @@ static inline void target_cpu_init(CPUARMState *env,
     env->pc = regs->pc;
     env->xregs[31] = regs->sp;
 }
+
+
+static inline void target_cpu_loop(CPUARMState *env)
+{
+    CPUState *cs = env_cpu(env);
+    int trapnr, ec, fsc, si_code, si_signo;
+    uint64_t code, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+    uint32_t pstate;
+    abi_long ret;
+
+    for (;;) {
+        cpu_exec_start(cs);
+        trapnr = cpu_exec(cs);
+        cpu_exec_end(cs);
+        process_queued_cpu_work(cs);
+
+        switch (trapnr) {
+        case EXCP_SWI:
+            /* See arm64/arm64/trap.c cpu_fetch_syscall_args() */
+            code = env->xregs[8];
+            if (code == TARGET_FREEBSD_NR_syscall ||
+                code == TARGET_FREEBSD_NR___syscall) {
+                code = env->xregs[0];
+                arg1 = env->xregs[1];
+                arg2 = env->xregs[2];
+                arg3 = env->xregs[3];
+                arg4 = env->xregs[4];
+                arg5 = env->xregs[5];
+                arg6 = env->xregs[6];
+                arg7 = env->xregs[7];
+                arg8 = 0;
+            } else {
+                arg1 = env->xregs[0];
+                arg2 = env->xregs[1];
+                arg3 = env->xregs[2];
+                arg4 = env->xregs[3];
+                arg5 = env->xregs[4];
+                arg6 = env->xregs[5];
+                arg7 = env->xregs[6];
+                arg8 = env->xregs[7];
+            }
+            ret = do_freebsd_syscall(env, code, arg1, arg2, arg3,
+                    arg4, arg5, arg6, arg7, arg8);
+            /*
+             * The carry bit is cleared for no error; set for error.
+             * See arm64/arm64/vm_machdep.c cpu_set_syscall_retval()
+             */
+            pstate = pstate_read(env);
+            if (ret >= 0) {
+                pstate &= ~PSTATE_C;
+                env->xregs[0] = ret;
+            } else if (ret == -TARGET_ERESTART) {
+                env->pc -= 4;
+                break;
+            } else if (ret != -TARGET_EJUSTRETURN) {
+                pstate |= PSTATE_C;
+                env->xregs[0] = -ret;
+            }
+            pstate_write(env, pstate);
+            break;
+
+        case EXCP_INTERRUPT:
+            /* Just indicate that signals should be handle ASAP. */
+            break;
+
+        case EXCP_UDEF:
+            force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc);
+            break;
+
+
+        case EXCP_PREFETCH_ABORT:
+        case EXCP_DATA_ABORT:
+            /* We should only arrive here with EC in {DATAABORT, INSNABORT}. */
+            ec = syn_get_ec(env->exception.syndrome);
+            assert(ec == EC_DATAABORT || ec == EC_INSNABORT);
+
+            /* Both EC have the same format for FSC, or close enough. */
+            fsc = extract32(env->exception.syndrome, 0, 6);
+            switch (fsc) {
+            case 0x04 ... 0x07: /* Translation fault, level {0-3} */
+                si_signo = TARGET_SIGSEGV;
+                si_code = TARGET_SEGV_MAPERR;
+                break;
+            case 0x09 ... 0x0b: /* Access flag fault, level {1-3} */
+            case 0x0d ... 0x0f: /* Permission fault, level {1-3} */
+                si_signo = TARGET_SIGSEGV;
+                si_code = TARGET_SEGV_ACCERR;
+                break;
+            case 0x11: /* Synchronous Tag Check Fault */
+                si_signo = TARGET_SIGSEGV;
+                si_code = /* TARGET_SEGV_MTESERR; */ TARGET_SEGV_ACCERR;
+                break;
+            case 0x21: /* Alignment fault */
+                si_signo = TARGET_SIGBUS;
+                si_code = TARGET_BUS_ADRALN;
+                break;
+            default:
+                g_assert_not_reached();
+            }
+            force_sig_fault(si_signo, si_code, env->exception.vaddress);
+            break;
+
+        case EXCP_DEBUG:
+        case EXCP_BKPT:
+            force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
+            break;
+
+        case EXCP_ATOMIC:
+            cpu_exec_step_atomic(cs);
+            break;
+
+        case EXCP_YIELD:
+            /* nothing to do here for user-mode, just resume guest code */
+            break;
+        default:
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+                    trapnr);
+            cpu_dump_state(cs, stderr, 0);
+            abort();
+        } /* switch() */
+        process_pending_signals(env);
+        /*
+         * Exception return on AArch64 always clears the exclusive
+         * monitor, so any return to running guest code implies this.
+         * A strex (successful or otherwise) also clears the monitor, so
+         * we don't need to specialcase EXCP_STREX.
+         */
+        env->exclusive_addr = -1;
+    } /* for (;;) */
+}
+
+#endif /* TARGET_ARCH_CPU_H */
-- 
2.34.1
Re: [PATCH 02/23] Added CPU loop function
Posted by Richard Henderson 5 months, 1 week ago
On 6/17/24 11:57, Ajeet Singh wrote:
> +            /*
> +             * The carry bit is cleared for no error; set for error.
> +             * See arm64/arm64/vm_machdep.c cpu_set_syscall_retval()
> +             */
> +            pstate = pstate_read(env);
> +            if (ret >= 0) {
> +                pstate &= ~PSTATE_C;
> +                env->xregs[0] = ret;
> +            } else if (ret == -TARGET_ERESTART) {
> +                env->pc -= 4;
> +                break;
> +            } else if (ret != -TARGET_EJUSTRETURN) {
> +                pstate |= PSTATE_C;
> +                env->xregs[0] = -ret;
> +            }
> +            pstate_write(env, pstate);

No need for full pstate read/write:

     env->CF = {0,1};


> +            break;
> +
> +        case EXCP_INTERRUPT:
> +            /* Just indicate that signals should be handle ASAP. */
> +            break;
> +
> +        case EXCP_UDEF:
> +            force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc);
> +            break;
> +
> +
> +        case EXCP_PREFETCH_ABORT:
> +        case EXCP_DATA_ABORT:
> +            /* We should only arrive here with EC in {DATAABORT, INSNABORT}. */
> +            ec = syn_get_ec(env->exception.syndrome);

Nevermind about my question about syndrome.h vs patch 1.


r~
Re: [PATCH 02/23] Added CPU loop function
Posted by Warner Losh 5 months ago
On Mon, Jun 17, 2024 at 10:24 PM Richard Henderson <
richard.henderson@linaro.org> wrote:

> On 6/17/24 11:57, Ajeet Singh wrote:
> > +            /*
> > +             * The carry bit is cleared for no error; set for error.
> > +             * See arm64/arm64/vm_machdep.c cpu_set_syscall_retval()
> > +             */
> > +            pstate = pstate_read(env);
> > +            if (ret >= 0) {
> > +                pstate &= ~PSTATE_C;
> > +                env->xregs[0] = ret;
> > +            } else if (ret == -TARGET_ERESTART) {
> > +                env->pc -= 4;
> > +                break;
> > +            } else if (ret != -TARGET_EJUSTRETURN) {
> > +                pstate |= PSTATE_C;
> > +                env->xregs[0] = -ret;
> > +            }
> > +            pstate_write(env, pstate);
>
> No need for full pstate read/write:
>
>      env->CF = {0,1};
>

If I understand what you're suggesting, the quoted code can be replaced
by the following, faster construct:

            /*
             * The carry bit is cleared for no error; set for error.
             * See arm64/arm64/vm_machdep.c cpu_set_syscall_retval()
             */
            if (ret >= 0) {
                env->CF = 0;
                env->xregs[0] = ret;
            } else if (ret == -TARGET_ERESTART) {
                env->pc -= 4;
                break;
            } else if (ret != -TARGET_EJUSTRETURN) {
                env->CF = 1;
                env->xregs[0] = -ret;
            }
            break;

Is that what you're saying?


> > +            break;
> > +
> > +        case EXCP_INTERRUPT:
> > +            /* Just indicate that signals should be handle ASAP. */
> > +            break;
> > +
> > +        case EXCP_UDEF:
> > +            force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc);
> > +            break;
> > +
> > +
> > +        case EXCP_PREFETCH_ABORT:
> > +        case EXCP_DATA_ABORT:
> > +            /* We should only arrive here with EC in {DATAABORT,
> INSNABORT}. */
> > +            ec = syn_get_ec(env->exception.syndrome);
>
> Nevermind about my question about syndrome.h vs patch 1.
>

Ah, Since we have to re-roll this patch anyway, maybe moving it is a good
idea?
Honestly, I'm good either way.

Warner


> r~
>
Re: [PATCH 02/23] Added CPU loop function
Posted by Richard Henderson 5 months ago
On 6/22/24 11:49, Warner Losh wrote:
> 
> 
> On Mon, Jun 17, 2024 at 10:24 PM Richard Henderson <richard.henderson@linaro.org 
> <mailto:richard.henderson@linaro.org>> wrote:
> 
>     On 6/17/24 11:57, Ajeet Singh wrote:
>      > +            /*
>      > +             * The carry bit is cleared for no error; set for error.
>      > +             * See arm64/arm64/vm_machdep.c cpu_set_syscall_retval()
>      > +             */
>      > +            pstate = pstate_read(env);
>      > +            if (ret >= 0) {
>      > +                pstate &= ~PSTATE_C;
>      > +                env->xregs[0] = ret;
>      > +            } else if (ret == -TARGET_ERESTART) {
>      > +                env->pc -= 4;
>      > +                break;
>      > +            } else if (ret != -TARGET_EJUSTRETURN) {
>      > +                pstate |= PSTATE_C;
>      > +                env->xregs[0] = -ret;
>      > +            }
>      > +            pstate_write(env, pstate);
> 
>     No need for full pstate read/write:
> 
>           env->CF = {0,1};
> 
> 
> If I understand what you're suggesting, the quoted code can be replaced
> by the following, faster construct:
> 
>              /*
>               * The carry bit is cleared for no error; set for error.
>               * See arm64/arm64/vm_machdep.c cpu_set_syscall_retval()
>               */
>              if (ret >= 0) {
>                  env->CF = 0;
>                  env->xregs[0] = ret;
>              } else if (ret == -TARGET_ERESTART) {
>                  env->pc -= 4;
>                  break;
>              } else if (ret != -TARGET_EJUSTRETURN) {
>                  env->CF = 1;
>                  env->xregs[0] = -ret;
>              }
>              break;
> 
> Is that what you're saying?

Yes.

> 
>      > +            break;
>      > +
>      > +        case EXCP_INTERRUPT:
>      > +            /* Just indicate that signals should be handle ASAP. */
>      > +            break;
>      > +
>      > +        case EXCP_UDEF:
>      > +            force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLOPN, env->pc);
>      > +            break;
>      > +
>      > +
>      > +        case EXCP_PREFETCH_ABORT:
>      > +        case EXCP_DATA_ABORT:
>      > +            /* We should only arrive here with EC in {DATAABORT, INSNABORT}. */
>      > +            ec = syn_get_ec(env->exception.syndrome);
> 
>     Nevermind about my question about syndrome.h vs patch 1.
> 
> 
> Ah, Since we have to re-roll this patch anyway, maybe moving it is a good idea?
> Honestly, I'm good either way.

Least effort is called for.  :-)


r~