diff --git a/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.c b/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.c
index 732860cadfe6..686622228831 100644
--- a/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.c
+++ b/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.c
@@ -1,7 +1,7 @@
 /** @file
   ArmGicArchLib library class implementation for DT based virt platforms
 
-  Copyright (c) 2015, Linaro Ltd. All rights reserved.<BR>
+  Copyright (c) 2015 - 2016, Linaro Ltd. All rights reserved.<BR>
 
   This program and the accompanying materials
   are licensed and made available under the terms and conditions of the BSD License
@@ -19,21 +19,83 @@
 #include <Library/ArmGicArchLib.h>
 #include <Library/PcdLib.h>
 #include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <libfdt.h>
+
+#include <Protocol/FdtClient.h>
 
 STATIC ARM_GIC_ARCH_REVISION        mGicArchRevision;
 
-RETURN_STATUS
+EFI_STATUS
 EFIAPI
 ArmVirtGicArchLibConstructor (
-  VOID
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
   )
 {
-  UINT32  IccSre;
+  UINT32                IccSre;
+  FDT_CLIENT_PROTOCOL   *FdtClient;
+  CONST VOID            *Reg;
+  UINTN                 RegElemSize, RegSize;
+  UINTN                 GicRevision;
+  EFI_STATUS            Status;
+  UINT64                DistBase, CpuBase, RedistBase;
 
-  switch (PcdGet32 (PcdArmGicRevision)) {
+  Status = gBS->LocateProtocol (&gFdtClientProtocolGuid, NULL, (VOID **)&FdtClient);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  GicRevision = 2;
+  Status = FdtClient->FindCompatibleNodeReg (FdtClient,
+                                             "arm,cortex-a15-gic",
+                                             &Reg,
+                                             &RegElemSize,
+                                             &RegSize);
+  if (Status == EFI_NOT_FOUND) {
+    GicRevision = 3;
+    Status = FdtClient->FindCompatibleNodeReg (FdtClient,
+                                               "arm,gic-v3",
+                                               &Reg,
+                                               &RegElemSize,
+                                               &RegSize);
+  }
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  switch (GicRevision) {
 
   case 3:
     //
+    // The GIC v3 DT binding describes a series of at least 3 physical (base
+    // addresses, size) pairs: the distributor interface (GICD), at least one
+    // redistributor region (GICR) containing dedicated redistributor
+    // interfaces for all individual CPUs, and the CPU interface (GICC).
+    // Under virtualization, we assume that the first redistributor region
+    // listed covers the boot CPU. Also, our GICv3 driver only supports the
+    // system register CPU interface, so we can safely ignore the MMIO version
+    // which is listed after the sequence of redistributor interfaces.
+    // This means we are only interested in the first two memory regions
+    // supplied, and ignore everything else.
+    //
+    ASSERT (RegSize >= 32);
+
+    // RegProp[0..1] == { GICD base, GICD size }
+    DistBase = fdt64_to_cpu (((UINT64 *)Reg)[0]);
+    ASSERT (DistBase < MAX_UINT32);
+
+    // RegProp[2..3] == { GICR base, GICR size }
+    RedistBase = fdt64_to_cpu (((UINT64 *)Reg)[2]);
+    ASSERT (RedistBase < MAX_UINT32);
+
+    PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);
+    PcdSet32 (PcdGicRedistributorsBase, (UINT32)RedistBase);
+
+    DEBUG ((EFI_D_INFO, "Found GIC v3 (re)distributor @ 0x%Lx (0x%Lx)\n",
+      DistBase, RedistBase));
+
+    //
     // The default implementation of ArmGicArchLib is responsible for enabling
     // the system register interface on the GICv3 if one is found. So let's do
     // the same here.
@@ -55,6 +117,18 @@ ArmVirtGicArchLibConstructor (
     break;
 
   case 2:
+    ASSERT (RegSize == 32);
+
+    DistBase = fdt64_to_cpu (((UINT64 *)Reg)[0]);
+    CpuBase  = fdt64_to_cpu (((UINT64 *)Reg)[2]);
+    ASSERT (DistBase < MAX_UINT32);
+    ASSERT (CpuBase < MAX_UINT32);
+
+    PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);
+    PcdSet32 (PcdGicInterruptInterfaceBase, (UINT32)CpuBase);
+
+    DEBUG ((EFI_D_INFO, "Found GIC @ 0x%Lx/0x%Lx\n", DistBase, CpuBase));
+
     mGicArchRevision = ARM_GIC_ARCH_REVISION_2;
     break;
 
diff --git a/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.inf b/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.inf
index c85b2d44d856..57086242de1f 100644
--- a/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.inf
+++ b/ArmVirtPkg/Library/ArmVirtGicArchLib/ArmVirtGicArchLib.inf
@@ -18,7 +18,7 @@ [Defines]
   INF_VERSION                    = 0x00010005
   BASE_NAME                      = ArmVirtGicArchLib
   FILE_GUID                      = 87b0dc84-4661-4deb-a789-97977ff636ed
-  MODULE_TYPE                    = BASE
+  MODULE_TYPE                    = DXE_DRIVER
   VERSION_STRING                 = 1.0
   LIBRARY_CLASS                  = ArmGicArchLib|DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION
   CONSTRUCTOR                    = ArmVirtGicArchLibConstructor
@@ -30,11 +30,22 @@ [LibraryClasses]
   PcdLib
   DebugLib
   ArmGicLib
+  UefiBootServicesTableLib
+  FdtLib
 
 [Packages]
   MdePkg/MdePkg.dec
   ArmPkg/ArmPkg.dec
   ArmVirtPkg/ArmVirtPkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+
+[Protocols]
+  gFdtClientProtocolGuid
 
 [Pcd]
-  gArmVirtTokenSpaceGuid.PcdArmGicRevision
+  gArmTokenSpaceGuid.PcdGicDistributorBase
+  gArmTokenSpaceGuid.PcdGicRedistributorsBase
+  gArmTokenSpaceGuid.PcdGicInterruptInterfaceBase
+
+[Depex]
+  gFdtClientProtocolGuid
