]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Drivers/CpuDxe/CpuMmuCommon.c
b1364820a452fe2af06ac2406b80dc494a3e0fc1
[mirror_edk2.git] / ArmPkg / Drivers / CpuDxe / CpuMmuCommon.c
1 /** @file
2 *
3 * Copyright (c) 2013, ARM Limited. All rights reserved.
4 *
5 * This program and the accompanying materials
6 * are licensed and made available under the terms and conditions of the BSD License
7 * which accompanies this distribution. The full text of the license may be found at
8 * http://opensource.org/licenses/bsd-license.php
9 *
10 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 *
13 **/
14
15 #include "CpuDxe.h"
16
17 /**
18 Searches memory descriptors covered by given memory range.
19
20 This function searches into the Gcd Memory Space for descriptors
21 (from StartIndex to EndIndex) that contains the memory range
22 specified by BaseAddress and Length.
23
24 @param MemorySpaceMap Gcd Memory Space Map as array.
25 @param NumberOfDescriptors Number of descriptors in map.
26 @param BaseAddress BaseAddress for the requested range.
27 @param Length Length for the requested range.
28 @param StartIndex Start index into the Gcd Memory Space Map.
29 @param EndIndex End index into the Gcd Memory Space Map.
30
31 @retval EFI_SUCCESS Search successfully.
32 @retval EFI_NOT_FOUND The requested descriptors does not exist.
33
34 **/
35 EFI_STATUS
36 SearchGcdMemorySpaces (
37 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
38 IN UINTN NumberOfDescriptors,
39 IN EFI_PHYSICAL_ADDRESS BaseAddress,
40 IN UINT64 Length,
41 OUT UINTN *StartIndex,
42 OUT UINTN *EndIndex
43 )
44 {
45 UINTN Index;
46
47 *StartIndex = 0;
48 *EndIndex = 0;
49 for (Index = 0; Index < NumberOfDescriptors; Index++) {
50 if ((BaseAddress >= MemorySpaceMap[Index].BaseAddress) &&
51 (BaseAddress < (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length))) {
52 *StartIndex = Index;
53 }
54 if (((BaseAddress + Length - 1) >= MemorySpaceMap[Index].BaseAddress) &&
55 ((BaseAddress + Length - 1) < (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length))) {
56 *EndIndex = Index;
57 return EFI_SUCCESS;
58 }
59 }
60 return EFI_NOT_FOUND;
61 }
62
63
64 /**
65 Sets the attributes for a specified range in Gcd Memory Space Map.
66
67 This function sets the attributes for a specified range in
68 Gcd Memory Space Map.
69
70 @param MemorySpaceMap Gcd Memory Space Map as array
71 @param NumberOfDescriptors Number of descriptors in map
72 @param BaseAddress BaseAddress for the range
73 @param Length Length for the range
74 @param Attributes Attributes to set
75
76 @retval EFI_SUCCESS Memory attributes set successfully
77 @retval EFI_NOT_FOUND The specified range does not exist in Gcd Memory Space
78
79 **/
80 EFI_STATUS
81 SetGcdMemorySpaceAttributes (
82 IN EFI_GCD_MEMORY_SPACE_DESCRIPTOR *MemorySpaceMap,
83 IN UINTN NumberOfDescriptors,
84 IN EFI_PHYSICAL_ADDRESS BaseAddress,
85 IN UINT64 Length,
86 IN UINT64 Attributes
87 )
88 {
89 EFI_STATUS Status;
90 UINTN Index;
91 UINTN StartIndex;
92 UINTN EndIndex;
93 EFI_PHYSICAL_ADDRESS RegionStart;
94 UINT64 RegionLength;
95
96 DEBUG ((DEBUG_GCD, "SetGcdMemorySpaceAttributes[0x%lX; 0x%lX] = 0x%lX\n",
97 BaseAddress, BaseAddress + Length, Attributes));
98
99 //
100 // Get all memory descriptors covered by the memory range
101 //
102 Status = SearchGcdMemorySpaces (
103 MemorySpaceMap,
104 NumberOfDescriptors,
105 BaseAddress,
106 Length,
107 &StartIndex,
108 &EndIndex
109 );
110 if (EFI_ERROR (Status)) {
111 return Status;
112 }
113
114 //
115 // Go through all related descriptors and set attributes accordingly
116 //
117 for (Index = StartIndex; Index <= EndIndex; Index++) {
118 if (MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeNonExistent) {
119 continue;
120 }
121 //
122 // Calculate the start and end address of the overlapping range
123 //
124 if (BaseAddress >= MemorySpaceMap[Index].BaseAddress) {
125 RegionStart = BaseAddress;
126 } else {
127 RegionStart = MemorySpaceMap[Index].BaseAddress;
128 }
129 if ((BaseAddress + Length - 1) < (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length)) {
130 RegionLength = BaseAddress + Length - RegionStart;
131 } else {
132 RegionLength = MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - RegionStart;
133 }
134 //
135 // Set memory attributes according to MTRR attribute and the original attribute of descriptor
136 //
137 gDS->SetMemorySpaceAttributes (
138 RegionStart,
139 RegionLength,
140 (MemorySpaceMap[Index].Attributes & ~EFI_MEMORY_CACHETYPE_MASK) | (MemorySpaceMap[Index].Capabilities & Attributes)
141 );
142 }
143
144 return EFI_SUCCESS;
145 }
146
147 /**
148 This function modifies the attributes for the memory region specified by BaseAddress and
149 Length from their current attributes to the attributes specified by Attributes.
150
151 @param This The EFI_CPU_ARCH_PROTOCOL instance.
152 @param BaseAddress The physical address that is the start address of a memory region.
153 @param Length The size in bytes of the memory region.
154 @param Attributes The bit mask of attributes to set for the memory region.
155
156 @retval EFI_SUCCESS The attributes were set for the memory region.
157 @retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
158 BaseAddress and Length cannot be modified.
159 @retval EFI_INVALID_PARAMETER Length is zero.
160 @retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
161 the memory resource range.
162 @retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
163 resource range specified by BaseAddress and Length.
164 The bit mask of attributes is not support for the memory resource
165 range specified by BaseAddress and Length.
166
167 **/
168 EFI_STATUS
169 EFIAPI
170 CpuSetMemoryAttributes (
171 IN EFI_CPU_ARCH_PROTOCOL *This,
172 IN EFI_PHYSICAL_ADDRESS BaseAddress,
173 IN UINT64 Length,
174 IN UINT64 Attributes
175 )
176 {
177 DEBUG ((EFI_D_PAGE, "CpuSetMemoryAttributes(%lx, %lx, %lx)\n", BaseAddress, Length, Attributes));
178
179 if ((BaseAddress & (SIZE_4KB - 1)) != 0) {
180 // Minimum granularity is SIZE_4KB (4KB on ARM)
181 DEBUG ((EFI_D_PAGE, "CpuSetMemoryAttributes(%lx, %lx, %lx): Minimum ganularity is SIZE_4KB\n", BaseAddress, Length, Attributes));
182 return EFI_UNSUPPORTED;
183 }
184
185 return SetMemoryAttributes (BaseAddress, Length, Attributes, 0);
186 }
187
188 EFI_STATUS
189 EFIAPI
190 CpuConvertPagesToUncachedVirtualAddress (
191 IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This,
192 IN EFI_PHYSICAL_ADDRESS Address,
193 IN UINTN Length,
194 IN EFI_PHYSICAL_ADDRESS VirtualMask,
195 OUT UINT64 *Attributes OPTIONAL
196 )
197 {
198 EFI_STATUS Status;
199 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
200
201 if (Attributes != NULL) {
202 Status = gDS->GetMemorySpaceDescriptor (Address, &GcdDescriptor);
203 if (!EFI_ERROR (Status)) {
204 *Attributes = GcdDescriptor.Attributes;
205 }
206 }
207
208 //
209 // Make this address range page fault if accessed. If it is a DMA buffer than this would
210 // be the PCI address. Code should always use the CPU address, and we will or in VirtualMask
211 // to that address.
212 //
213 Status = SetMemoryAttributes (Address, Length, EFI_MEMORY_WP, 0);
214 if (!EFI_ERROR (Status)) {
215 Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_UC, VirtualMask);
216 }
217
218 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "CpuConvertPagesToUncachedVirtualAddress()\n Unmapped 0x%08lx Mapped 0x%08lx 0x%x bytes\n", Address, Address | VirtualMask, Length));
219
220 return Status;
221 }
222
223
224 EFI_STATUS
225 EFIAPI
226 CpuReconvertPages (
227 IN VIRTUAL_UNCACHED_PAGES_PROTOCOL *This,
228 IN EFI_PHYSICAL_ADDRESS Address,
229 IN UINTN Length,
230 IN EFI_PHYSICAL_ADDRESS VirtualMask,
231 IN UINT64 Attributes
232 )
233 {
234 EFI_STATUS Status;
235
236 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "CpuReconvertPages(%lx, %x, %lx, %lx)\n", Address, Length, VirtualMask, Attributes));
237
238 //
239 // Unmap the aliased Address
240 //
241 Status = SetMemoryAttributes (Address | VirtualMask, Length, EFI_MEMORY_WP, 0);
242 if (!EFI_ERROR (Status)) {
243 //
244 // Restore atttributes
245 //
246 Status = SetMemoryAttributes (Address, Length, Attributes, 0);
247 }
248
249 return Status;
250 }
251
252
253 VIRTUAL_UNCACHED_PAGES_PROTOCOL gVirtualUncachedPages = {
254 CpuConvertPagesToUncachedVirtualAddress,
255 CpuReconvertPages
256 };