]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
13fa7cd01ebac7a75c448c0a6bea44b76af854bf
[mirror_edk2.git] / ArmPkg / Drivers / CpuDxe / CpuMmuCommon.c
1 /** @file
2 *
3 * Copyright (c) 2013, ARM Limited. All rights reserved.
4 * Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
5 *
6 * SPDX-License-Identifier: BSD-2-Clause-Patent
7 *
8 **/
9
10 #include "CpuDxe.h"
11
12 /**
13 Searches memory descriptors covered by given memory range.
14
15 This function searches into the Gcd Memory Space for descriptors
16 (from StartIndex to EndIndex) that contains the memory range
17 specified by BaseAddress and Length.
18
19 @param MemorySpaceMap Gcd Memory Space Map as array.
20 @param NumberOfDescriptors Number of descriptors in map.
21 @param BaseAddress BaseAddress for the requested range.
22 @param Length Length for the requested range.
23 @param StartIndex Start index into the Gcd Memory Space Map.
24 @param EndIndex End index into the Gcd Memory Space Map.
25
26 @retval EFI_SUCCESS Search successfully.
27 @retval EFI_NOT_FOUND The requested descriptors does not exist.
28
29 **/
30 EFI_STATUS
31 SearchGcdMemorySpaces (
32 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
33 IN UINTN NumberOfDescriptors,
34 IN EFI_PHYSICAL_ADDRESS BaseAddress,
35 IN UINT64 Length,
36 OUT UINTN *StartIndex,
37 OUT UINTN *EndIndex
38 )
39 {
40 UINTN Index;
41
42 *StartIndex = 0;
43 *EndIndex = 0;
44 for (Index = 0; Index < NumberOfDescriptors; Index++) {
45 if ((BaseAddress >= MemorySpaceMap[Index].BaseAddress) &&
46 (BaseAddress < (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length))) {
47 *StartIndex = Index;
48 }
49 if (((BaseAddress + Length - 1) >= MemorySpaceMap[Index].BaseAddress) &&
50 ((BaseAddress + Length - 1) < (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length))) {
51 *EndIndex = Index;
52 return EFI_SUCCESS;
53 }
54 }
55 return EFI_NOT_FOUND;
56 }
57
58
59 /**
60 Sets the attributes for a specified range in Gcd Memory Space Map.
61
62 This function sets the attributes for a specified range in
63 Gcd Memory Space Map.
64
65 @param MemorySpaceMap Gcd Memory Space Map as array
66 @param NumberOfDescriptors Number of descriptors in map
67 @param BaseAddress BaseAddress for the range
68 @param Length Length for the range
69 @param Attributes Attributes to set
70
71 @retval EFI_SUCCESS Memory attributes set successfully
72 @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space
73
74 **/
75 EFI_STATUS
76 SetGcdMemorySpaceAttributes (
77 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
78 IN UINTN NumberOfDescriptors,
79 IN EFI_PHYSICAL_ADDRESS BaseAddress,
80 IN UINT64 Length,
81 IN UINT64 Attributes
82 )
83 {
84 EFI_STATUS Status;
85 UINTN Index;
86 UINTN StartIndex;
87 UINTN EndIndex;
88 EFI_PHYSICAL_ADDRESS RegionStart;
89 UINT64 RegionLength;
90
91 DEBUG ((DEBUG_GCD, "SetGcdMemorySpaceAttributes[0x%lX; 0x%lX] = 0x%lX\n",
92 BaseAddress, BaseAddress + Length, Attributes));
93
94 // We do not support a smaller granularity than 4KB on ARM Architecture
95 if ((Length & EFI_PAGE_MASK) != 0) {
96 DEBUG ((DEBUG_WARN,
97 "Warning: We do not support smaller granularity than 4KB on ARM Architecture (passed length: 0x%lX).\n",
98 Length));
99 }
100
101 //
102 // Get all memory descriptors covered by the memory range
103 //
104 Status = SearchGcdMemorySpaces (
105 MemorySpaceMap,
106 NumberOfDescriptors,
107 BaseAddress,
108 Length,
109 &StartIndex,
110 &EndIndex
111 );
112 if (EFI_ERROR (Status)) {
113 return Status;
114 }
115
116 //
117 // Go through all related descriptors and set attributes accordingly
118 //
119 for (Index = StartIndex; Index <= EndIndex; Index++) {
120 if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
121 continue;
122 }
123 //
124 // Calculate the start and end address of the overlapping range
125 //
126 if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
127 RegionStart = BaseAddress;
128 } else {
129 RegionStart = MemorySpaceMap[Index].BaseAddress;
130 }
131 if ((BaseAddress + Length - 1) < (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length)) {
132 RegionLength = BaseAddress + Length - RegionStart;
133 } else {
134 RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;
135 }
136 //
137 // Set memory attributes according to MTRR attribute and the original attribute of descriptor
138 //
139 gDS->SetMemorySpaceAttributes (
140 RegionStart,
141 RegionLength,
142 (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)
143 );
144 }
145
146 return EFI_SUCCESS;
147 }
148
149 /**
150 This function modifies the attributes for the memory region specified by BaseAddress and
151 Length from their current attributes to the attributes specified by Attributes.
152
153 @param This The EFI_CPU_ARCH_PROTOCOL instance.
154 @param BaseAddress The physical address that is the start address of a memory region.
155 @param Length The size in bytes of the memory region.
156 @param Attributes The bit mask of attributes to set for the memory region.
157
158 @retval EFI_SUCCESS The attributes were set for the memory region.
159 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
160 BaseAddress and Length cannot be modified.
161 @retval EFI_INVALID_PARAMETER Length is zero.
162 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
163 the memory resource range.
164 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
165 resource range specified by BaseAddress and Length.
166 The bit mask of attributes is not support for the memory resource
167 range specified by BaseAddress and Length.
168
169 **/
170 EFI_STATUS
171 EFIAPI
172 CpuSetMemoryAttributes (
173 IN EFI_CPU_ARCH_PROTOCOL *This,
174 IN EFI_PHYSICAL_ADDRESS BaseAddress,
175 IN UINT64 Length,
176 IN UINT64 EfiAttributes
177 )
178 {
179 EFI_STATUS Status;
180 UINTN ArmAttributes;
181 UINTN RegionBaseAddress;
182 UINTN RegionLength;
183 UINTN RegionArmAttributes;
184
185 if (mIsFlushingGCD) {
186 return EFI_SUCCESS;
187 }
188
189 if ((BaseAddress & (SIZE_4KB - 1)) != 0) {
190 // Minimum granularity is SIZE_4KB (4KB on ARM)
191 DEBUG ((EFI_D_PAGE, "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum ganularity is SIZE_4KB\n", BaseAddress, Length, EfiAttributes));
192 return EFI_UNSUPPORTED;
193 }
194
195 // Convert the 'Attribute' into ARM Attribute
196 ArmAttributes = EfiAttributeToArmAttribute (EfiAttributes);
197
198 // Get the region starting from 'BaseAddress' and its 'Attribute'
199 RegionBaseAddress = BaseAddress;
200 Status = GetMemoryRegion (&RegionBaseAddress, &RegionLength, &RegionArmAttributes);
201
202 // Data & Instruction Caches are flushed when we set new memory attributes.
203 // So, we only set the attributes if the new region is different.
204 if (EFI_ERROR (Status) || (RegionArmAttributes != ArmAttributes) ||
205 ((BaseAddress + Length) > (RegionBaseAddress + RegionLength)))
206 {
207 return ArmSetMemoryAttributes (BaseAddress, Length, EfiAttributes);
208 } else {
209 return EFI_SUCCESS;
210 }
211 }