diff mbox

[edk2,2/2] ArmGicLib: select GICv2 mode if SRE is present but unavailable

Message ID 1415792793-8488-2-git-send-email-ard.biesheuvel@linaro.org
State New
Headers show

Commit Message

Ard Biesheuvel Nov. 12, 2014, 11:46 a.m. UTC
Even if the CPU id registers indicate hardware support for the
System Register interface to the GIC, higher exception levels
may disable that interface and only allow access through MMIO.

So move the enabling of the SRE bit to the GIC version detection
routine: if we trigger an exception, we would have anyway at a
later stage, so the net effect is the same. However, if setting
the bit doesn't stick, it means we can switch to MMIO and proceed
normally otherwise. (This is analogous to how the Linux kernel
behaves when executed as a guest under KVM.)

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c | 14 +++++++++++++-
 ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c     | 14 +++++++++++++-
 ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c     |  8 --------
 3 files changed, 26 insertions(+), 10 deletions(-)

Comments

Olivier Martin Nov. 13, 2014, 4:47 p.m. UTC | #1
Ard, I have just reviewed and committed your patch (SVN rev16344).

I removed the reference to Linux kernel to answer Christoffer comment.
I also replaced 'lower levels' by 'higher privilege levels'.

Christoffer, yes ArmGicV3SetControlSystemRegisterEnable() does an isb()
after changing the system register.

> -----Original Message-----
> From: Christoffer Dall [mailto:christoffer.dall@linaro.org]
> Sent: 12 November 2014 19:49
> To: Ard Biesheuvel
> Cc: Olivier Martin; edk2-devel@lists.sourceforge.net; Marc Zyngier;
> leif.lindholm@linaro.org; kvmarm@lists.cs.columbia.edu;
> lersek@redhat.com
> Subject: Re: [PATCH 2/2] ArmGicLib: select GICv2 mode if SRE is present
> but unavailable
> 
> On Wed, Nov 12, 2014 at 12:46:33PM +0100, Ard Biesheuvel wrote:
> > Even if the CPU id registers indicate hardware support for the
> > System Register interface to the GIC, higher exception levels
> > may disable that interface and only allow access through MMIO.
> >
> > So move the enabling of the SRE bit to the GIC version detection
> > routine: if we trigger an exception, we would have anyway at a
> > later stage, so the net effect is the same. However, if setting
> > the bit doesn't stick, it means we can switch to MMIO and proceed
> > normally otherwise. (This is analogous to how the Linux kernel
> > behaves when executed as a guest under KVM.)
> 
> not quite, Linux tries to use the device it's being told about in the
> DT.  But it still does the set/check of the bit, but if it doesn't
> stick, it prints an error and dies...
> 
> >
> > Contributed-under: TianoCore Contribution Agreement 1.0
> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > ---
> >  ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c | 14 +++++++++++++-
> >  ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c     | 14 +++++++++++++-
> >  ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c     |  8 --------
> >  3 files changed, 26 insertions(+), 10 deletions(-)
> >
> > diff --git a/ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c
> b/ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c
> > index 5a7837f43d94..e2955ae861d5 100644
> > --- a/ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c
> > +++ b/ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c
> > @@ -15,6 +15,8 @@
> >  #include <Library/ArmLib.h>
> >  #include <Library/ArmGicLib.h>
> >
> > +#include "GicV3/ArmGicV3Lib.h"
> > +
> >  ARM_GIC_ARCH_REVISION
> >  EFIAPI
> >  ArmGicGetSupportedArchRevision (
> > @@ -28,7 +30,17 @@ ArmGicGetSupportedArchRevision (
> >    // driver requires SRE. If only Memory mapped access is available
> we try to
> >    // drive the GIC as a v2.
> >    if (ArmReadIdPfr0 () & AARCH64_PFR0_GIC) {
> > -    return ARM_GIC_ARCH_REVISION_3;
> > +    // Make sure System Register access is enabled (SRE). This
> depends on the
> > +    // lower levels giving us permission, otherwise we will either
> cause an
> 
> lower levels...  not sure what the convention here is, but higher
> privilege level would be more accurate, no?
> 
> > +    // exception here, or the write doesn't stick in which case we
> need to
> > +    // fall back to the GICv2 MMIO interface.
> > +    // Note: We do not need to set ICC_SRE_EL2.Enable because the OS
> is started
> > +    // at the same exception level.
> > +    // It is the OS responsibility to set this bit.
> > +    ArmGicV3SetControlSystemRegisterEnable
> (ArmGicV3GetControlSystemRegisterEnable () | ICC_SRE_EL2_SRE);
> 
> don't you need an isb() here like the linux code has or is that implied
> in the ArmGicV3SetControlSystemRegisterEnable function?
> 
> > +    if (ArmGicV3GetControlSystemRegisterEnable () & ICC_SRE_EL2_SRE)
> {
> > +      return ARM_GIC_ARCH_REVISION_3;
> > +    }
> >    }
> >
> >    return ARM_GIC_ARCH_REVISION_2;
> > diff --git a/ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c
> b/ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c
> > index 668858f79a3d..02e5638f2fcf 100644
> > --- a/ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c
> > +++ b/ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c
> > @@ -15,6 +15,8 @@
> >  #include <Library/ArmLib.h>
> >  #include <Library/ArmGicLib.h>
> >
> > +#include "GicV3/ArmGicV3Lib.h"
> > +
> >  ARM_GIC_ARCH_REVISION
> >  EFIAPI
> >  ArmGicGetSupportedArchRevision (
> > @@ -28,7 +30,17 @@ ArmGicGetSupportedArchRevision (
> >    // driver requires SRE. If only Memory mapped access is available
> we try to
> >    // drive the GIC as a v2.
> >    if (ArmReadIdPfr1 () & ARM_PFR1_GIC) {
> > -    return ARM_GIC_ARCH_REVISION_3;
> > +    // Make sure System Register access is enabled (SRE). This
> depends on the
> > +    // lower levels giving us permission, otherwise we will either
> cause an
> > +    // exception here, or the write doesn't stick in which case we
> need to
> > +    // fall back to the GICv2 MMIO interface.
> > +    // Note: We do not need to set ICC_SRE_EL2.Enable because the OS
> is started
> > +    // at the same exception level.
> > +    // It is the OS responsibility to set this bit.
> > +    ArmGicV3SetControlSystemRegisterEnable
> (ArmGicV3GetControlSystemRegisterEnable () | ICC_SRE_EL2_SRE);
> 
> same
> 
> > +    if (ArmGicV3GetControlSystemRegisterEnable () & ICC_SRE_EL2_SRE)
> {
> > +      return ARM_GIC_ARCH_REVISION_3;
> > +    }
> >    }
> >
> >    return ARM_GIC_ARCH_REVISION_2;
> > diff --git a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
> b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
> > index 8042f718f5b0..f756d3080386 100644
> > --- a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
> > +++ b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
> > @@ -281,14 +281,6 @@ GicV3DxeInitialize (
> >      }
> >    }
> >
> > -  // Make sure System Register access is enabled (SRE). This depends
> on the
> > -  // lower levels giving us permission, otherwise we will cause an
> exception
> > -  // here.
> > -  // Note: We do not need to set ICC_SRE_EL2.Enable because the OS
> is started at the
> > -  // same exception level.
> > -  // It is the OS responsibility to set this bit.
> > -  ArmGicV3SetControlSystemRegisterEnable
> (ArmGicV3GetControlSystemRegisterEnable () | ICC_SRE_EL2_SRE);
> > -
> >    // Set binary point reg to 0x7 (no preemption)
> >    ArmGicV3SetBinaryPointer (0x7);
> >
> > --
> > 1.8.3.2
> >
> apart from the above, the logic looks good to me.





------------------------------------------------------------------------------
Comprehensive Server Monitoring with Site24x7.
Monitor 10 servers for $9/Month.
Get alerted through email, SMS, voice calls or mobile push notifications.
Take corrective actions from your mobile device.
http://pubads.g.doubleclick.net/gampad/clk?id=154624111&iu=/4140/ostg.clktrk
Ard Biesheuvel Nov. 13, 2014, 5:18 p.m. UTC | #2
On 13 November 2014 17:47, Olivier Martin <olivier.martin@arm.com> wrote:
> Ard, I have just reviewed and committed your patch (SVN rev16344).
>
> I removed the reference to Linux kernel to answer Christoffer comment.
> I also replaced 'lower levels' by 'higher privilege levels'.
>

OK, thanks!

For the record, the original symptom I experienced was an unresponsive
BDS UI, i.e., countdown timer not changing and no response to key
presses. However, it turned out that I was using the GICv3 capable
Foundation model (using --gicv3 cmdline option) in combination with a
GICv2 device tree, and hence there was no awareness in KVM of the SRE
capability and the need to disable/trap it.

So when I started using the correct device tree, I started getting
exceptions due to the fact that KVM trapped the ICC_SRE_EL1 access but
did not actually handle it. Christoffer's fix for that issue is here:
http://marc.info/?l=linux-arm-kernel&m=141582259511445&w=2

In summary, if you want to run the latest version of QEMU/KVM
mach-virt port of Tianocore on a GICv3 capable host, you will need to
apply this patch and the Linux patch above *and* ensure that the host
device tree accurately reports the GICv3 capability and not just the
GICv2 compatible MMIO interface.

Regards,
Ard.


> Christoffer, yes ArmGicV3SetControlSystemRegisterEnable() does an isb()
> after changing the system register.
>
>> -----Original Message-----
>> From: Christoffer Dall [mailto:christoffer.dall@linaro.org]
>> Sent: 12 November 2014 19:49
>> To: Ard Biesheuvel
>> Cc: Olivier Martin; edk2-devel@lists.sourceforge.net; Marc Zyngier;
>> leif.lindholm@linaro.org; kvmarm@lists.cs.columbia.edu;
>> lersek@redhat.com
>> Subject: Re: [PATCH 2/2] ArmGicLib: select GICv2 mode if SRE is present
>> but unavailable
>>
>> On Wed, Nov 12, 2014 at 12:46:33PM +0100, Ard Biesheuvel wrote:
>> > Even if the CPU id registers indicate hardware support for the
>> > System Register interface to the GIC, higher exception levels
>> > may disable that interface and only allow access through MMIO.
>> >
>> > So move the enabling of the SRE bit to the GIC version detection
>> > routine: if we trigger an exception, we would have anyway at a
>> > later stage, so the net effect is the same. However, if setting
>> > the bit doesn't stick, it means we can switch to MMIO and proceed
>> > normally otherwise. (This is analogous to how the Linux kernel
>> > behaves when executed as a guest under KVM.)
>>
>> not quite, Linux tries to use the device it's being told about in the
>> DT.  But it still does the set/check of the bit, but if it doesn't
>> stick, it prints an error and dies...
>>
>> >
>> > Contributed-under: TianoCore Contribution Agreement 1.0
>> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
>> > ---
>> >  ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c | 14 +++++++++++++-
>> >  ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c     | 14 +++++++++++++-
>> >  ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c     |  8 --------
>> >  3 files changed, 26 insertions(+), 10 deletions(-)
>> >
>> > diff --git a/ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c
>> b/ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c
>> > index 5a7837f43d94..e2955ae861d5 100644
>> > --- a/ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c
>> > +++ b/ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c
>> > @@ -15,6 +15,8 @@
>> >  #include <Library/ArmLib.h>
>> >  #include <Library/ArmGicLib.h>
>> >
>> > +#include "GicV3/ArmGicV3Lib.h"
>> > +
>> >  ARM_GIC_ARCH_REVISION
>> >  EFIAPI
>> >  ArmGicGetSupportedArchRevision (
>> > @@ -28,7 +30,17 @@ ArmGicGetSupportedArchRevision (
>> >    // driver requires SRE. If only Memory mapped access is available
>> we try to
>> >    // drive the GIC as a v2.
>> >    if (ArmReadIdPfr0 () & AARCH64_PFR0_GIC) {
>> > -    return ARM_GIC_ARCH_REVISION_3;
>> > +    // Make sure System Register access is enabled (SRE). This
>> depends on the
>> > +    // lower levels giving us permission, otherwise we will either
>> cause an
>>
>> lower levels...  not sure what the convention here is, but higher
>> privilege level would be more accurate, no?
>>
>> > +    // exception here, or the write doesn't stick in which case we
>> need to
>> > +    // fall back to the GICv2 MMIO interface.
>> > +    // Note: We do not need to set ICC_SRE_EL2.Enable because the OS
>> is started
>> > +    // at the same exception level.
>> > +    // It is the OS responsibility to set this bit.
>> > +    ArmGicV3SetControlSystemRegisterEnable
>> (ArmGicV3GetControlSystemRegisterEnable () | ICC_SRE_EL2_SRE);
>>
>> don't you need an isb() here like the linux code has or is that implied
>> in the ArmGicV3SetControlSystemRegisterEnable function?
>>
>> > +    if (ArmGicV3GetControlSystemRegisterEnable () & ICC_SRE_EL2_SRE)
>> {
>> > +      return ARM_GIC_ARCH_REVISION_3;
>> > +    }
>> >    }
>> >
>> >    return ARM_GIC_ARCH_REVISION_2;
>> > diff --git a/ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c
>> b/ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c
>> > index 668858f79a3d..02e5638f2fcf 100644
>> > --- a/ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c
>> > +++ b/ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c
>> > @@ -15,6 +15,8 @@
>> >  #include <Library/ArmLib.h>
>> >  #include <Library/ArmGicLib.h>
>> >
>> > +#include "GicV3/ArmGicV3Lib.h"
>> > +
>> >  ARM_GIC_ARCH_REVISION
>> >  EFIAPI
>> >  ArmGicGetSupportedArchRevision (
>> > @@ -28,7 +30,17 @@ ArmGicGetSupportedArchRevision (
>> >    // driver requires SRE. If only Memory mapped access is available
>> we try to
>> >    // drive the GIC as a v2.
>> >    if (ArmReadIdPfr1 () & ARM_PFR1_GIC) {
>> > -    return ARM_GIC_ARCH_REVISION_3;
>> > +    // Make sure System Register access is enabled (SRE). This
>> depends on the
>> > +    // lower levels giving us permission, otherwise we will either
>> cause an
>> > +    // exception here, or the write doesn't stick in which case we
>> need to
>> > +    // fall back to the GICv2 MMIO interface.
>> > +    // Note: We do not need to set ICC_SRE_EL2.Enable because the OS
>> is started
>> > +    // at the same exception level.
>> > +    // It is the OS responsibility to set this bit.
>> > +    ArmGicV3SetControlSystemRegisterEnable
>> (ArmGicV3GetControlSystemRegisterEnable () | ICC_SRE_EL2_SRE);
>>
>> same
>>
>> > +    if (ArmGicV3GetControlSystemRegisterEnable () & ICC_SRE_EL2_SRE)
>> {
>> > +      return ARM_GIC_ARCH_REVISION_3;
>> > +    }
>> >    }
>> >
>> >    return ARM_GIC_ARCH_REVISION_2;
>> > diff --git a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
>> b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
>> > index 8042f718f5b0..f756d3080386 100644
>> > --- a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
>> > +++ b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
>> > @@ -281,14 +281,6 @@ GicV3DxeInitialize (
>> >      }
>> >    }
>> >
>> > -  // Make sure System Register access is enabled (SRE). This depends
>> on the
>> > -  // lower levels giving us permission, otherwise we will cause an
>> exception
>> > -  // here.
>> > -  // Note: We do not need to set ICC_SRE_EL2.Enable because the OS
>> is started at the
>> > -  // same exception level.
>> > -  // It is the OS responsibility to set this bit.
>> > -  ArmGicV3SetControlSystemRegisterEnable
>> (ArmGicV3GetControlSystemRegisterEnable () | ICC_SRE_EL2_SRE);
>> > -
>> >    // Set binary point reg to 0x7 (no preemption)
>> >    ArmGicV3SetBinaryPointer (0x7);
>> >
>> > --
>> > 1.8.3.2
>> >
>> apart from the above, the logic looks good to me.
>
>
>
>

------------------------------------------------------------------------------
Comprehensive Server Monitoring with Site24x7.
Monitor 10 servers for $9/Month.
Get alerted through email, SMS, voice calls or mobile push notifications.
Take corrective actions from your mobile device.
http://pubads.g.doubleclick.net/gampad/clk?id=154624111&iu=/4140/ostg.clktrk
diff mbox

Patch

diff --git a/ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c b/ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c
index 5a7837f43d94..e2955ae861d5 100644
--- a/ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c
+++ b/ArmPkg/Drivers/ArmGic/AArch64/ArmGicArchLib.c
@@ -15,6 +15,8 @@ 
 #include <Library/ArmLib.h>
 #include <Library/ArmGicLib.h>
 
+#include "GicV3/ArmGicV3Lib.h"
+
 ARM_GIC_ARCH_REVISION
 EFIAPI
 ArmGicGetSupportedArchRevision (
@@ -28,7 +30,17 @@  ArmGicGetSupportedArchRevision (
   // driver requires SRE. If only Memory mapped access is available we try to
   // drive the GIC as a v2.
   if (ArmReadIdPfr0 () & AARCH64_PFR0_GIC) {
-    return ARM_GIC_ARCH_REVISION_3;
+    // Make sure System Register access is enabled (SRE). This depends on the
+    // lower levels giving us permission, otherwise we will either cause an
+    // exception here, or the write doesn't stick in which case we need to
+    // fall back to the GICv2 MMIO interface.
+    // Note: We do not need to set ICC_SRE_EL2.Enable because the OS is started
+    // at the same exception level.
+    // It is the OS responsibility to set this bit.
+    ArmGicV3SetControlSystemRegisterEnable (ArmGicV3GetControlSystemRegisterEnable () | ICC_SRE_EL2_SRE);
+    if (ArmGicV3GetControlSystemRegisterEnable () & ICC_SRE_EL2_SRE) {
+      return ARM_GIC_ARCH_REVISION_3;
+    }
   }
 
   return ARM_GIC_ARCH_REVISION_2;
diff --git a/ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c b/ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c
index 668858f79a3d..02e5638f2fcf 100644
--- a/ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c
+++ b/ArmPkg/Drivers/ArmGic/Arm/ArmGicArchLib.c
@@ -15,6 +15,8 @@ 
 #include <Library/ArmLib.h>
 #include <Library/ArmGicLib.h>
 
+#include "GicV3/ArmGicV3Lib.h"
+
 ARM_GIC_ARCH_REVISION
 EFIAPI
 ArmGicGetSupportedArchRevision (
@@ -28,7 +30,17 @@  ArmGicGetSupportedArchRevision (
   // driver requires SRE. If only Memory mapped access is available we try to
   // drive the GIC as a v2.
   if (ArmReadIdPfr1 () & ARM_PFR1_GIC) {
-    return ARM_GIC_ARCH_REVISION_3;
+    // Make sure System Register access is enabled (SRE). This depends on the
+    // lower levels giving us permission, otherwise we will either cause an
+    // exception here, or the write doesn't stick in which case we need to
+    // fall back to the GICv2 MMIO interface.
+    // Note: We do not need to set ICC_SRE_EL2.Enable because the OS is started
+    // at the same exception level.
+    // It is the OS responsibility to set this bit.
+    ArmGicV3SetControlSystemRegisterEnable (ArmGicV3GetControlSystemRegisterEnable () | ICC_SRE_EL2_SRE);
+    if (ArmGicV3GetControlSystemRegisterEnable () & ICC_SRE_EL2_SRE) {
+      return ARM_GIC_ARCH_REVISION_3;
+    }
   }
 
   return ARM_GIC_ARCH_REVISION_2;
diff --git a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
index 8042f718f5b0..f756d3080386 100644
--- a/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
+++ b/ArmPkg/Drivers/ArmGic/GicV3/ArmGicV3Dxe.c
@@ -281,14 +281,6 @@  GicV3DxeInitialize (
     }
   }
 
-  // Make sure System Register access is enabled (SRE). This depends on the
-  // lower levels giving us permission, otherwise we will cause an exception
-  // here.
-  // Note: We do not need to set ICC_SRE_EL2.Enable because the OS is started at the
-  // same exception level.
-  // It is the OS responsibility to set this bit.
-  ArmGicV3SetControlSystemRegisterEnable (ArmGicV3GetControlSystemRegisterEnable () | ICC_SRE_EL2_SRE);
-
   // Set binary point reg to 0x7 (no preemption)
   ArmGicV3SetBinaryPointer (0x7);