Revision: 14482
http://sourceforge.net/p/edk2/code/14482
Author: oliviermartin
Date: 2013-07-18 06:20:33 +0000 (Thu, 18 Jul 2013)
Log Message:
-----------
ArmPkg/CpuDxe: Moved memory mapping functions that are not architecture
specific to 'CpuMmuCommon.c'
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Olivier Martin <[email protected]>
Modified Paths:
--------------
trunk/edk2/ArmPkg/Drivers/CpuDxe/ArmV6/Mmu.c
trunk/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.h
trunk/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
Added Paths:
-----------
trunk/edk2/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
Modified: trunk/edk2/ArmPkg/Drivers/CpuDxe/ArmV6/Mmu.c
===================================================================
--- trunk/edk2/ArmPkg/Drivers/CpuDxe/ArmV6/Mmu.c 2013-07-17 07:53:04 UTC
(rev 14481)
+++ trunk/edk2/ArmPkg/Drivers/CpuDxe/ArmV6/Mmu.c 2013-07-18 06:20:33 UTC
(rev 14482)
@@ -150,134 +150,7 @@
return EFI_SUCCESS;
}
-/**
- Searches memory descriptors covered by given memory range.
-
- This function searches into the Gcd Memory Space for descriptors
- (from StartIndex to EndIndex) that contains the memory range
- specified by BaseAddress and Length.
-
- @param MemorySpaceMap Gcd Memory Space Map as array.
- @param NumberOfDescriptors Number of descriptors in map.
- @param BaseAddress BaseAddress for the requested range.
- @param Length Length for the requested range.
- @param StartIndex Start index into the Gcd Memory Space Map.
- @param EndIndex End index into the Gcd Memory Space Map.
-
- @retval EFI_SUCCESS Search successfully.
- @retval EFI_NOT_FOUND The requested descriptors does not exist.
-
-**/
EFI_STATUS
-SearchGcdMemorySpaces (
- IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
- IN UINTN NumberOfDescriptors,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- OUT UINTN *StartIndex,
- OUT UINTN *EndIndex
- )
-{
- UINTN Index;
-
- *StartIndex = 0;
- *EndIndex = 0;
- for (Index = 0; Index < NumberOfDescriptors; Index++) {
- if (BaseAddress >= MemorySpaceMap[Index].BaseAddress &&
- BaseAddress < MemorySpaceMap[Index].BaseAddress +
MemorySpaceMap[Index].Length) {
- *StartIndex = Index;
- }
- if (BaseAddress + Length - 1 >= MemorySpaceMap[Index].BaseAddress &&
- BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress +
MemorySpaceMap[Index].Length) {
- *EndIndex = Index;
- return EFI_SUCCESS;
- }
- }
- return EFI_NOT_FOUND;
-}
-
-
-/**
- Sets the attributes for a specified range in Gcd Memory Space Map.
-
- This function sets the attributes for a specified range in
- Gcd Memory Space Map.
-
- @param MemorySpaceMap Gcd Memory Space Map as array
- @param NumberOfDescriptors Number of descriptors in map
- @param BaseAddress BaseAddress for the range
- @param Length Length for the range
- @param Attributes Attributes to set
-
- @retval EFI_SUCCESS Memory attributes set successfully
- @retval EFI_NOT_FOUND The specified range does not exist in Gcd
Memory Space
-
-**/
-EFI_STATUS
-SetGcdMemorySpaceAttributes (
- IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
- IN UINTN NumberOfDescriptors,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Attributes
- )
-{
- EFI_STATUS Status;
- UINTN Index;
- UINTN StartIndex;
- UINTN EndIndex;
- EFI_PHYSICAL_ADDRESS RegionStart;
- UINT64 RegionLength;
-
- //
- // Get all memory descriptors covered by the memory range
- //
- Status = SearchGcdMemorySpaces (
- MemorySpaceMap,
- NumberOfDescriptors,
- BaseAddress,
- Length,
- &StartIndex,
- &EndIndex
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Go through all related descriptors and set attributes accordingly
- //
- for (Index = StartIndex; Index <= EndIndex; Index++) {
- if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
- continue;
- }
- //
- // Calculate the start and end address of the overlapping range
- //
- if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
- RegionStart = BaseAddress;
- } else {
- RegionStart = MemorySpaceMap[Index].BaseAddress;
- }
- if (BaseAddress + Length - 1 < MemorySpaceMap[Index].BaseAddress +
MemorySpaceMap[Index].Length) {
- RegionLength = BaseAddress + Length - RegionStart;
- } else {
- RegionLength = MemorySpaceMap[Index].BaseAddress +
MemorySpaceMap[Index].Length - RegionStart;
- }
- //
- // Set memory attributes according to MTRR attribute and the original
attribute of descriptor
- //
- gDS->SetMemorySpaceAttributes (
- RegionStart,
- RegionLength,
- (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) |
(MemorySpaceMap[Index].Capabilities & Attributes)
- );
- }
-
- return EFI_SUCCESS;
-}
-
-EFI_STATUS
SyncCacheConfigPage (
IN UINT32 SectionIndex,
IN UINT32 FirstLevelDescriptor,
@@ -824,121 +697,3 @@
return Status;
}
-
-
-/**
- This function modifies the attributes for the memory region specified by
BaseAddress and
- Length from their current attributes to the attributes specified by
Attributes.
-
- @param This The EFI_CPU_ARCH_PROTOCOL instance.
- @param BaseAddress The physical address that is the start address of a
memory region.
- @param Length The size in bytes of the memory region.
- @param Attributes The bit mask of attributes to set for the memory
region.
-
- @retval EFI_SUCCESS The attributes were set for the memory region.
- @retval EFI_ACCESS_DENIED The attributes for the memory resource range
specified by
- BaseAddress and Length cannot be modified.
- @retval EFI_INVALID_PARAMETER Length is zero.
- @retval EFI_OUT_OF_RESOURCES There are not enough system resources to
modify the attributes of
- the memory resource range.
- @retval EFI_UNSUPPORTED The processor does not support one or more
bytes of the memory
- resource range specified by BaseAddress and
Length.
- The bit mask of attributes is not support for
the memory resource
- range specified by BaseAddress and Length.
-
-**/
-EFI_STATUS
-EFIAPI
-CpuSetMemoryAttributes (
- IN EFI_CPU_ARCH_PROTOCOL *This,
- IN EFI_PHYSICAL_ADDRESS BaseAddress,
- IN UINT64 Length,
- IN UINT64 Attributes
- )
-{
- DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(%lx, %lx, %lx)\n", BaseAddress,
Length, Attributes));
- if ( ((BaseAddress & ~TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK) != 0) ||
((Length & ~TT_DESCRIPTOR_PAGE_BASE_ADDRESS_MASK) != 0)){
- // minimum granularity is SIZE_4KB (4KB on ARM)
- DEBUG ((EFI_D_PAGE, "SetMemoryAttributes(%lx, %lx, %lx): minimum
ganularity is SIZE_4KB\n", BaseAddress, Length, Attributes));
- return EFI_UNSUPPORTED;
- }
-
- return SetMemoryAttributes (BaseAddress, Length, Attributes, 0);
-}
-
-
-
-//
-// Add a new protocol to support
-//
-
-EFI_STATUS
-EFIAPI
-CpuConvertPagesToUncachedVirtualAddress (
- IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This,
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN Length,
- IN EFI_PHYSICAL_ADDRESS VirtualMask,
- OUT UINT64 *Attributes OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
-
-
- if (Attributes != NULL) {
- Status = gDS->GetMemorySpaceDescriptor (Address, &GcdDescriptor);
- if (!EFI_ERROR (Status)) {
- *Attributes = GcdDescriptor.Attributes;
- }
- }
-
- //
- // Make this address range page fault if accessed. If it is a DMA buffer
than this would
- // be the PCI address. Code should always use the CPU address, and we will
or in VirtualMask
- // to that address.
- //
- Status = SetMemoryAttributes (Address, Length, EFI_MEMORY_WP, 0);
- if (!EFI_ERROR (Status)) {
- Status = SetMemoryAttributes (Address | VirtualMask, Length,
EFI_MEMORY_UC, VirtualMask);
- }
-
- DEBUG ((DEBUG_INFO | DEBUG_LOAD, "ConvertPagesToUncachedVirtualAddress()\n
Unmapped 0x%08lx Mapped 0x%08lx 0x%x bytes\n", Address, Address | VirtualMask,
Length));
-
- return Status;
-}
-
-
-EFI_STATUS
-EFIAPI
-CpuReconvertPages (
- IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This,
- IN EFI_PHYSICAL_ADDRESS Address,
- IN UINTN Length,
- IN EFI_PHYSICAL_ADDRESS VirtualMask,
- IN UINT64 Attributes
- )
-{
- EFI_STATUS Status;
-
- DEBUG ((DEBUG_INFO | DEBUG_LOAD, "CpuReconvertPages(%lx, %x, %lx, %lx)\n",
Address, Length, VirtualMask, Attributes));
-
- //
- // Unmap the alaised Address
- //
- Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_WP,
0);
- if (!EFI_ERROR (Status)) {
- //
- // Restore atttributes
- //
- Status = SetMemoryAttributes (Address, Length, Attributes, 0);
- }
-
- return Status;
-}
-
-
-VIRTUAL_UNCACHED_PAGES_PROTOCOL gVirtualUncachedPages = {
- CpuConvertPagesToUncachedVirtualAddress,
- CpuReconvertPages
-};
Modified: trunk/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.h
===================================================================
--- trunk/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.h 2013-07-17 07:53:04 UTC (rev
14481)
+++ trunk/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.h 2013-07-18 06:20:33 UTC (rev
14482)
@@ -1,6 +1,7 @@
/** @file
Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
+ Copyright (c) 2011 - 2013, ARM 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
@@ -139,6 +140,23 @@
VOID
);
+EFI_STATUS
+SetMemoryAttributes (
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes,
+ IN EFI_PHYSICAL_ADDRESS VirtualMask
+ );
+
+EFI_STATUS
+SetGcdMemorySpaceAttributes (
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
+ IN UINTN NumberOfDescriptors,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ );
+
extern VIRTUAL_UNCACHED_PAGES_PROTOCOL gVirtualUncachedPages;
#endif // __CPU_DXE_ARM_EXCEPTION_H__
Modified: trunk/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
===================================================================
--- trunk/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.inf 2013-07-17 07:53:04 UTC (rev
14481)
+++ trunk/edk2/ArmPkg/Drivers/CpuDxe/CpuDxe.inf 2013-07-18 06:20:33 UTC (rev
14482)
@@ -3,7 +3,7 @@
# DXE CPU driver
#
# Copyright (c) 2009, Apple Inc. All rights reserved.<BR>
-# Copyright (c) 2011-2012, ARM Limited. All rights reserved.
+# Copyright (c) 2011-2013, ARM Limited. All rights reserved.
#
# This program and the accompanying materials
# are licensed and made available under the terms and conditions of the BSD
License
@@ -28,6 +28,7 @@
CpuDxe.c
CpuDxe.h
CpuMpCore.c
+ CpuMmuCommon.c
#
# Prior to ARMv6 we have multiple stacks, one per mode
Added: trunk/edk2/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
===================================================================
--- trunk/edk2/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
(rev 0)
+++ trunk/edk2/ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c 2013-07-18 06:20:33 UTC
(rev 14482)
@@ -0,0 +1,256 @@
+/** @file
+*
+* Copyright (c) 2013, ARM Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD
License
+* which accompanies this distribution. The full text of the license may be
found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR
IMPLIED.
+*
+**/
+
+#include "CpuDxe.h"
+
+/**
+ Searches memory descriptors covered by given memory range.
+
+ This function searches into the Gcd Memory Space for descriptors
+ (from StartIndex to EndIndex) that contains the memory range
+ specified by BaseAddress and Length.
+
+ @param MemorySpaceMap Gcd Memory Space Map as array.
+ @param NumberOfDescriptors Number of descriptors in map.
+ @param BaseAddress BaseAddress for the requested range.
+ @param Length Length for the requested range.
+ @param StartIndex Start index into the Gcd Memory Space Map.
+ @param EndIndex End index into the Gcd Memory Space Map.
+
+ @retval EFI_SUCCESS Search successfully.
+ @retval EFI_NOT_FOUND The requested descriptors does not exist.
+
+**/
+EFI_STATUS
+SearchGcdMemorySpaces (
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
+ IN UINTN NumberOfDescriptors,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ OUT UINTN *StartIndex,
+ OUT UINTN *EndIndex
+ )
+{
+ UINTN Index;
+
+ *StartIndex = 0;
+ *EndIndex = 0;
+ for (Index = 0; Index < NumberOfDescriptors; Index++) {
+ if ((BaseAddress >= MemorySpaceMap[Index].BaseAddress) &&
+ (BaseAddress < (MemorySpaceMap[Index].BaseAddress +
MemorySpaceMap[Index].Length))) {
+ *StartIndex = Index;
+ }
+ if (((BaseAddress + Length - 1) >= MemorySpaceMap[Index].BaseAddress) &&
+ ((BaseAddress + Length - 1) < (MemorySpaceMap[Index].BaseAddress +
MemorySpaceMap[Index].Length))) {
+ *EndIndex = Index;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+
+/**
+ Sets the attributes for a specified range in Gcd Memory Space Map.
+
+ This function sets the attributes for a specified range in
+ Gcd Memory Space Map.
+
+ @param MemorySpaceMap Gcd Memory Space Map as array
+ @param NumberOfDescriptors Number of descriptors in map
+ @param BaseAddress BaseAddress for the range
+ @param Length Length for the range
+ @param Attributes Attributes to set
+
+ @retval EFI_SUCCESS Memory attributes set successfully
+ @retval EFI_NOT_FOUND The specified range does not exist in Gcd
Memory Space
+
+**/
+EFI_STATUS
+SetGcdMemorySpaceAttributes (
+ IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
+ IN UINTN NumberOfDescriptors,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN StartIndex;
+ UINTN EndIndex;
+ EFI_PHYSICAL_ADDRESS RegionStart;
+ UINT64 RegionLength;
+
+ DEBUG ((DEBUG_GCD, "SetGcdMemorySpaceAttributes[0x%lX; 0x%lX] = 0x%lX\n",
+ BaseAddress, BaseAddress + Length, Attributes));
+
+ //
+ // Get all memory descriptors covered by the memory range
+ //
+ Status = SearchGcdMemorySpaces (
+ MemorySpaceMap,
+ NumberOfDescriptors,
+ BaseAddress,
+ Length,
+ &StartIndex,
+ &EndIndex
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Go through all related descriptors and set attributes accordingly
+ //
+ for (Index = StartIndex; Index <= EndIndex; Index++) {
+ if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
+ continue;
+ }
+ //
+ // Calculate the start and end address of the overlapping range
+ //
+ if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
+ RegionStart = BaseAddress;
+ } else {
+ RegionStart = MemorySpaceMap[Index].BaseAddress;
+ }
+ if ((BaseAddress + Length - 1) < (MemorySpaceMap[Index].BaseAddress +
MemorySpaceMap[Index].Length)) {
+ RegionLength = BaseAddress + Length - RegionStart;
+ } else {
+ RegionLength = MemorySpaceMap[Index].BaseAddress +
MemorySpaceMap[Index].Length - RegionStart;
+ }
+ //
+ // Set memory attributes according to MTRR attribute and the original
attribute of descriptor
+ //
+ gDS->SetMemorySpaceAttributes (
+ RegionStart,
+ RegionLength,
+ (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) |
(MemorySpaceMap[Index].Capabilities & Attributes)
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function modifies the attributes for the memory region specified by
BaseAddress and
+ Length from their current attributes to the attributes specified by
Attributes.
+
+ @param This The EFI_CPU_ARCH_PROTOCOL instance.
+ @param BaseAddress The physical address that is the start address of a
memory region.
+ @param Length The size in bytes of the memory region.
+ @param Attributes The bit mask of attributes to set for the memory
region.
+
+ @retval EFI_SUCCESS The attributes were set for the memory region.
+ @retval EFI_ACCESS_DENIED The attributes for the memory resource range
specified by
+ BaseAddress and Length cannot be modified.
+ @retval EFI_INVALID_PARAMETER Length is zero.
+ @retval EFI_OUT_OF_RESOURCES There are not enough system resources to
modify the attributes of
+ the memory resource range.
+ @retval EFI_UNSUPPORTED The processor does not support one or more
bytes of the memory
+ resource range specified by BaseAddress and
Length.
+ The bit mask of attributes is not support for
the memory resource
+ range specified by BaseAddress and Length.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuSetMemoryAttributes (
+ IN EFI_CPU_ARCH_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN UINT64 Attributes
+ )
+{
+ DEBUG ((EFI_D_PAGE, "CpuSetMemoryAttributes(%lx, %lx, %lx)\n", BaseAddress,
Length, Attributes));
+
+ if ((BaseAddress & (SIZE_4KB - 1)) != 0) {
+ // Minimum granularity is SIZE_4KB (4KB on ARM)
+ DEBUG ((EFI_D_PAGE, "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum
ganularity is SIZE_4KB\n", BaseAddress, Length, Attributes));
+ return EFI_UNSUPPORTED;
+ }
+
+ return SetMemoryAttributes (BaseAddress, Length, Attributes, 0);
+}
+
+EFI_STATUS
+EFIAPI
+CpuConvertPagesToUncachedVirtualAddress (
+ IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN Length,
+ IN EFI_PHYSICAL_ADDRESS VirtualMask,
+ OUT UINT64 *Attributes OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
+
+ if (Attributes != NULL) {
+ Status = gDS->GetMemorySpaceDescriptor (Address, &GcdDescriptor);
+ if (!EFI_ERROR (Status)) {
+ *Attributes = GcdDescriptor.Attributes;
+ }
+ }
+
+ //
+ // Make this address range page fault if accessed. If it is a DMA buffer
than this would
+ // be the PCI address. Code should always use the CPU address, and we will
or in VirtualMask
+ // to that address.
+ //
+ Status = SetMemoryAttributes (Address, Length, EFI_MEMORY_WP, 0);
+ if (!EFI_ERROR (Status)) {
+ Status = SetMemoryAttributes (Address | VirtualMask, Length,
EFI_MEMORY_UC, VirtualMask);
+ }
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD,
"CpuConvertPagesToUncachedVirtualAddress()\n Unmapped 0x%08lx Mapped 0x%08lx
0x%x bytes\n", Address, Address | VirtualMask, Length));
+
+ return Status;
+}
+
+
+EFI_STATUS
+EFIAPI
+CpuReconvertPages (
+ IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This,
+ IN EFI_PHYSICAL_ADDRESS Address,
+ IN UINTN Length,
+ IN EFI_PHYSICAL_ADDRESS VirtualMask,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "CpuReconvertPages(%lx, %x, %lx, %lx)\n",
Address, Length, VirtualMask, Attributes));
+
+ //
+ // Unmap the aliased Address
+ //
+ Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_WP,
0);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Restore atttributes
+ //
+ Status = SetMemoryAttributes (Address, Length, Attributes, 0);
+ }
+
+ return Status;
+}
+
+
+VIRTUAL_UNCACHED_PAGES_PROTOCOL gVirtualUncachedPages = {
+ CpuConvertPagesToUncachedVirtualAddress,
+ CpuReconvertPages
+};
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
See everything from the browser to the database with AppDynamics
Get end-to-end visibility with application monitoring from AppDynamics
Isolate bottlenecks and diagnose root cause in seconds.
Start your free trial of AppDynamics Pro today!
http://pubads.g.doubleclick.net/gampad/clk?id=48808831&iu=/4140/ostg.clktrk
_______________________________________________
edk2-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-commits