diff mbox series

target/arm: Treat unknown SMC calls as NOP

Message ID 20200701200848.26746-1-agraf@csgraf.de (mailing list archive)
State New, archived
Headers show
Series target/arm: Treat unknown SMC calls as NOP | expand

Commit Message

Alexander Graf July 1, 2020, 8:08 p.m. UTC
We currently treat unknown SMC calls as UNDEF. This behavior is different
from KVM, which treats them as NOP.

Unfortunately, the UNDEF exception breaks running Windows for ARM in QEMU,
as that probes an OEM SMCCC call on boot, but does not expect to receive
an UNDEF exception as response.

So instead, let's follow the KVM path and ignore SMC calls that we don't
handle. This fixes booting the Windows 10 for ARM preview in TCG for me.

Signed-off-by: Alexander Graf <agraf@csgraf.de>
---
 target/arm/helper.c    |  8 ++++++++
 target/arm/op_helper.c | 13 ++++---------
 2 files changed, 12 insertions(+), 9 deletions(-)

Comments

Peter Maydell July 1, 2020, 8:47 p.m. UTC | #1
On Wed, 1 Jul 2020 at 21:08, Alexander Graf <agraf@csgraf.de> wrote:
>
> We currently treat unknown SMC calls as UNDEF. This behavior is different
> from KVM, which treats them as NOP.
>
> Unfortunately, the UNDEF exception breaks running Windows for ARM in QEMU,
> as that probes an OEM SMCCC call on boot, but does not expect to receive
> an UNDEF exception as response.
>
> So instead, let's follow the KVM path and ignore SMC calls that we don't
> handle. This fixes booting the Windows 10 for ARM preview in TCG for me.
>
> Signed-off-by: Alexander Graf <agraf@csgraf.de>

> +    if (cs->exception_index == EXCP_SMC &&
> +        !arm_feature(env, ARM_FEATURE_EL3) &&
> +        cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) {

This condition says: "we got an SMC, and this CPU doesn't
have EL3, and we're not imitating real EL3 firmware".
The architecturally correct behaviour here (since we don't
implement nested-virt yet, which might allow it to trap
to guest EL2) is to UNDEF, as far as I can see from a quick
look at the AArch64.CheckForSMCUndefOrTrap().

I'm not sure why KVM makes these NOP; if I'm right about the
architectural behaviour then making them NOP would be a KVM bug.

If Windows makes an SMC call on boot that seems like a guest
bug: it would crash on a real CPU without EL2/EL3 as well.

      *  Conduit SMC, valid call  Trap to EL2         PSCI Call
      *  Conduit SMC, inval call  Trap to EL2         Undef insn
-     *  Conduit not SMC          Undef insn          Undef insn
+     *  Conduit not SMC          nop                 nop

The line in this table that your commit message says you're
fixing is "Conduit SMC, inval call"; the line your code
change affects is "Conduit not SMC", which is not the same
thing. (I'd have to look at the PSCI spec to see what it
requires for SMCs that aren't valid PSCI calls.)

thanks
-- PMM
Alexander Graf July 1, 2020, 10:16 p.m. UTC | #2
On 01.07.20 22:47, Peter Maydell wrote:
> On Wed, 1 Jul 2020 at 21:08, Alexander Graf <agraf@csgraf.de> wrote:
>> We currently treat unknown SMC calls as UNDEF. This behavior is different
>> from KVM, which treats them as NOP.
>>
>> Unfortunately, the UNDEF exception breaks running Windows for ARM in QEMU,
>> as that probes an OEM SMCCC call on boot, but does not expect to receive
>> an UNDEF exception as response.
>>
>> So instead, let's follow the KVM path and ignore SMC calls that we don't
>> handle. This fixes booting the Windows 10 for ARM preview in TCG for me.
>>
>> Signed-off-by: Alexander Graf <agraf@csgraf.de>
>> +    if (cs->exception_index == EXCP_SMC &&
>> +        !arm_feature(env, ARM_FEATURE_EL3) &&
>> +        cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) {
> This condition says: "we got an SMC, and this CPU doesn't
> have EL3, and we're not imitating real EL3 firmware".


I like to think of it as "This CPU exposes an environment that looks
like KVM, so it implements HVC calls (EL2) and is responsible for
handling SMC calls as well.

The main difference between the two semantics is that in yours, you
don't have EL3. In mine, there is an EL3, but it's virtualized by the
same layer that implements EL2.


> The architecturally correct behaviour here (since we don't
> implement nested-virt yet, which might allow it to trap
> to guest EL2) is to UNDEF, as far as I can see from a quick
> look at the AArch64.CheckForSMCUndefOrTrap().
>
> I'm not sure why KVM makes these NOP; if I'm right about the
> architectural behaviour then making them NOP would be a KVM bug.
>
> If Windows makes an SMC call on boot that seems like a guest
> bug: it would crash on a real CPU without EL2/EL3 as well.


I don't think there can be a real SBBR compatible CPU without EL2/EL3,
because PSCI is a base requirement. That means either SMC calls succeed
(Windows running in EL2) or SMC calls are trapped into EL2 and it's up
to the hypervisor to decide what to do with them.


>
>       *  Conduit SMC, valid call  Trap to EL2         PSCI Call
>       *  Conduit SMC, inval call  Trap to EL2         Undef insn
> -     *  Conduit not SMC          Undef insn          Undef insn
> +     *  Conduit not SMC          nop                 nop
>
> The line in this table that your commit message says you're
> fixing is "Conduit SMC, inval call"; the line your code
> change affects is "Conduit not SMC", which is not the same
> thing. (I'd have to look at the PSCI spec to see what it
> requires for SMCs that aren't valid PSCI calls.)


The patch fixes the default environment, which is "Conduit HVC, PSCI
over HVC implemented by QEMU". If the patch description wasn't clear,
I'm happy to reword it :).


Alex
Alex Bennée July 2, 2020, 7:54 a.m. UTC | #3
Alexander Graf <agraf@csgraf.de> writes:

> On 01.07.20 22:47, Peter Maydell wrote:
>> On Wed, 1 Jul 2020 at 21:08, Alexander Graf <agraf@csgraf.de> wrote:
>>> We currently treat unknown SMC calls as UNDEF. This behavior is different
>>> from KVM, which treats them as NOP.
>>>
>>> Unfortunately, the UNDEF exception breaks running Windows for ARM in QEMU,
>>> as that probes an OEM SMCCC call on boot, but does not expect to receive
>>> an UNDEF exception as response.
>>>
>>> So instead, let's follow the KVM path and ignore SMC calls that we don't
>>> handle. This fixes booting the Windows 10 for ARM preview in TCG for me.
>>>
>>> Signed-off-by: Alexander Graf <agraf@csgraf.de>
>>> +    if (cs->exception_index == EXCP_SMC &&
>>> +        !arm_feature(env, ARM_FEATURE_EL3) &&
>>> +        cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) {
>> This condition says: "we got an SMC, and this CPU doesn't
>> have EL3, and we're not imitating real EL3 firmware".
>
>
> I like to think of it as "This CPU exposes an environment that looks
> like KVM, so it implements HVC calls (EL2) and is responsible for
> handling SMC calls as well.

That is a very KVM centric view of the world ;-)

I thought the aim was always to behave as the real processor would.

> The main difference between the two semantics is that in yours, you
> don't have EL3. In mine, there is an EL3, but it's virtualized by the
> same layer that implements EL2.

If you boot up with secure firmware + EL2 aware KVM kernel I assume
everything behaves as expected?

>
>
>> The architecturally correct behaviour here (since we don't
>> implement nested-virt yet, which might allow it to trap
>> to guest EL2) is to UNDEF, as far as I can see from a quick
>> look at the AArch64.CheckForSMCUndefOrTrap().
>>
>> I'm not sure why KVM makes these NOP; if I'm right about the
>> architectural behaviour then making them NOP would be a KVM bug.
>>
>> If Windows makes an SMC call on boot that seems like a guest
>> bug: it would crash on a real CPU without EL2/EL3 as well.
>
>
> I don't think there can be a real SBBR compatible CPU without EL2/EL3,
> because PSCI is a base requirement. That means either SMC calls succeed
> (Windows running in EL2) or SMC calls are trapped into EL2 and it's up
> to the hypervisor to decide what to do with them.
>
>
>>
>>       *  Conduit SMC, valid call  Trap to EL2         PSCI Call
>>       *  Conduit SMC, inval call  Trap to EL2         Undef insn
>> -     *  Conduit not SMC          Undef insn          Undef insn
>> +     *  Conduit not SMC          nop                 nop
>>
>> The line in this table that your commit message says you're
>> fixing is "Conduit SMC, inval call"; the line your code
>> change affects is "Conduit not SMC", which is not the same
>> thing. (I'd have to look at the PSCI spec to see what it
>> requires for SMCs that aren't valid PSCI calls.)
>
>
> The patch fixes the default environment, which is "Conduit HVC, PSCI
> over HVC implemented by QEMU". If the patch description wasn't clear,
> I'm happy to reword it :).
>
>
> Alex
Alexander Graf July 2, 2020, 9:02 a.m. UTC | #4
On 02.07.20 09:54, Alex Bennée wrote:
> Alexander Graf <agraf@csgraf.de> writes:
>
>> On 01.07.20 22:47, Peter Maydell wrote:
>>> On Wed, 1 Jul 2020 at 21:08, Alexander Graf <agraf@csgraf.de> wrote:
>>>> We currently treat unknown SMC calls as UNDEF. This behavior is different
>>>> from KVM, which treats them as NOP.
>>>>
>>>> Unfortunately, the UNDEF exception breaks running Windows for ARM in QEMU,
>>>> as that probes an OEM SMCCC call on boot, but does not expect to receive
>>>> an UNDEF exception as response.
>>>>
>>>> So instead, let's follow the KVM path and ignore SMC calls that we don't
>>>> handle. This fixes booting the Windows 10 for ARM preview in TCG for me.
>>>>
>>>> Signed-off-by: Alexander Graf <agraf@csgraf.de>
>>>> +    if (cs->exception_index == EXCP_SMC &&
>>>> +        !arm_feature(env, ARM_FEATURE_EL3) &&
>>>> +        cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) {
>>> This condition says: "we got an SMC, and this CPU doesn't
>>> have EL3, and we're not imitating real EL3 firmware".
>>
>> I like to think of it as "This CPU exposes an environment that looks
>> like KVM, so it implements HVC calls (EL2) and is responsible for
>> handling SMC calls as well.
> That is a very KVM centric view of the world ;-)
>
> I thought the aim was always to behave as the real processor would.


If we aim to behave like a "real processor", then why do we implement 
PSCI using HVC? A much more likely "real processor" would implement EL3, 
but no EL2 and then have PSCI as SMC calls, no?

My understanding for the rationale on why we do PSCI over HVC by default 
was to make the VM as similar between KVM and TCG as possible.


>
>> The main difference between the two semantics is that in yours, you
>> don't have EL3. In mine, there is an EL3, but it's virtualized by the
>> same layer that implements EL2.
> If you boot up with secure firmware + EL2 aware KVM kernel I assume
> everything behaves as expected?


I would assume so as well, but I don't have a working ATF setup handy. 
I'm also not worried about making it work for me - I have my local debug 
setup now :). I'm worried about a good out of the box experience for 
users who want to run Windows on ARM in TCG.


Alex
diff mbox series

Patch

diff --git a/target/arm/helper.c b/target/arm/helper.c
index dc9c29f998..bc1bd2e704 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -9778,6 +9778,14 @@  void arm_cpu_do_interrupt(CPUState *cs)
         return;
     }
 
+    if (cs->exception_index == EXCP_SMC &&
+        !arm_feature(env, ARM_FEATURE_EL3) &&
+        cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) {
+        /* Treat unknown SMC calls as NOP, just like KVM */
+        qemu_log_mask(CPU_LOG_INT, "...handled as NOP\n");
+        return;
+    }
+
     /*
      * Semihosting semantics depend on the register width of the code
      * that caused the exception, not the target exception level, so
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index b1065216b2..42b1687860 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -823,7 +823,7 @@  void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
      *
      *  Conduit SMC, valid call  Trap to EL2         PSCI Call
      *  Conduit SMC, inval call  Trap to EL2         Undef insn
-     *  Conduit not SMC          Undef insn          Undef insn
+     *  Conduit not SMC          nop                 nop
      */
 
     /* On ARMv8 with EL3 AArch64, SMD applies to both S and NS state.
@@ -838,16 +838,11 @@  void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
 
     if (!arm_feature(env, ARM_FEATURE_EL3) &&
         cpu->psci_conduit != QEMU_PSCI_CONDUIT_SMC) {
-        /* If we have no EL3 then SMC always UNDEFs and can't be
-         * trapped to EL2. PSCI-via-SMC is a sort of ersatz EL3
-         * firmware within QEMU, and we want an EL2 guest to be able
-         * to forbid its EL1 from making PSCI calls into QEMU's
-         * "firmware" via HCR.TSC, so for these purposes treat
-         * PSCI-via-SMC as implying an EL3.
+        /* If we have no EL3 then we simulate KVM behavior which
+         * simply treats every unknown SMC as a nop.
          * This handles the very last line of the previous table.
          */
-        raise_exception(env, EXCP_UDEF, syn_uncategorized(),
-                        exception_target_el(env));
+        return;
     }
 
     if (cur_el == 1 && (arm_hcr_el2_eff(env) & HCR_TSC)) {