VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdePkg/Library/PciSegmentLibSegmentInfo/DxeRuntimePciSegmentLib.c@ 80721

最後變更 在這個檔案從80721是 80721,由 vboxsync 提交於 6 年 前

Devices/EFI/FirmwareNew: Start upgrade process to edk2-stable201908 (compiles on Windows and works to some extent), bugref:4643

  • 屬性 svn:eol-style 設為 native
檔案大小: 9.6 KB
 
1/** @file
2 Instance of Runtime PCI Segment Library that support multi-segment PCI configuration access.
3
4 PCI Segment Library that consumes segment information provided by PciSegmentInfoLib to
5 support multi-segment PCI configuration access through enhanced configuration access mechanism.
6
7 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
9
10**/
11
12#include "PciSegmentLibCommon.h"
13#include <PiDxe.h>
14#include <Guid/EventGroup.h>
15#include <Library/UefiRuntimeLib.h>
16#include <Library/DxeServicesTableLib.h>
17#include <Library/UefiBootServicesTableLib.h>
18#include <Library/MemoryAllocationLib.h>
19#include <Library/PciSegmentInfoLib.h>
20
21///
22/// Define table for mapping PCI Segment MMIO physical addresses to virtual addresses at OS runtime
23///
24typedef struct {
25 UINTN PhysicalAddress;
26 UINTN VirtualAddress;
27} PCI_SEGMENT_RUNTIME_REGISTRATION_TABLE;
28
29///
30/// Set Virtual Address Map Event
31///
32EFI_EVENT mDxeRuntimePciSegmentLibVirtualNotifyEvent = NULL;
33
34///
35/// The number of PCI devices that have been registered for runtime access.
36///
37UINTN mDxeRuntimePciSegmentLibNumberOfRuntimeRanges = 0;
38
39///
40/// The table of PCI devices that have been registered for runtime access.
41///
42PCI_SEGMENT_RUNTIME_REGISTRATION_TABLE *mDxeRuntimePciSegmentLibRegistrationTable = NULL;
43
44///
45/// The table index of the most recent virtual address lookup.
46///
47UINTN mDxeRuntimePciSegmentLibLastRuntimeRange = 0;
48
49/**
50 Convert the physical PCI Express MMIO addresses for all registered PCI devices
51 to virtual addresses.
52
53 @param[in] Event The event that is being processed.
54 @param[in] Context The Event Context.
55**/
56VOID
57EFIAPI
58DxeRuntimePciSegmentLibVirtualNotify (
59 IN EFI_EVENT Event,
60 IN VOID *Context
61 )
62{
63 UINTN Index;
64 EFI_STATUS Status;
65
66 //
67 // If there have been no runtime registrations, then just return
68 //
69 if (mDxeRuntimePciSegmentLibRegistrationTable == NULL) {
70 return;
71 }
72
73 //
74 // Convert physical addresses associated with the set of registered PCI devices to
75 // virtual addresses.
76 //
77 for (Index = 0; Index < mDxeRuntimePciSegmentLibNumberOfRuntimeRanges; Index++) {
78 Status = EfiConvertPointer (0, (VOID **) &(mDxeRuntimePciSegmentLibRegistrationTable[Index].VirtualAddress));
79 ASSERT_EFI_ERROR (Status);
80 }
81
82 //
83 // Convert table pointer that is allocated from EfiRuntimeServicesData to a virtual address.
84 //
85 Status = EfiConvertPointer (0, (VOID **) &mDxeRuntimePciSegmentLibRegistrationTable);
86 ASSERT_EFI_ERROR (Status);
87}
88
89/**
90 The constructor function caches the PCI Express Base Address and creates a
91 Set Virtual Address Map event to convert physical address to virtual addresses.
92
93 @param ImageHandle The firmware allocated handle for the EFI image.
94 @param SystemTable A pointer to the EFI System Table.
95
96 @retval EFI_SUCCESS The constructor completed successfully.
97 @retval Other value The constructor did not complete successfully.
98
99**/
100EFI_STATUS
101EFIAPI
102DxeRuntimePciSegmentLibConstructor (
103 IN EFI_HANDLE ImageHandle,
104 IN EFI_SYSTEM_TABLE *SystemTable
105 )
106{
107 EFI_STATUS Status;
108
109 //
110 // Register SetVirtualAddressMap () notify function
111 //
112 Status = gBS->CreateEventEx (
113 EVT_NOTIFY_SIGNAL,
114 TPL_NOTIFY,
115 DxeRuntimePciSegmentLibVirtualNotify,
116 NULL,
117 &gEfiEventVirtualAddressChangeGuid,
118 &mDxeRuntimePciSegmentLibVirtualNotifyEvent
119 );
120 ASSERT_EFI_ERROR (Status);
121
122 return Status;
123}
124
125/**
126 The destructor function frees any allocated buffers and closes the Set Virtual
127 Address Map event.
128
129 @param ImageHandle The firmware allocated handle for the EFI image.
130 @param SystemTable A pointer to the EFI System Table.
131
132 @retval EFI_SUCCESS The destructor completed successfully.
133 @retval Other value The destructor did not complete successfully.
134
135**/
136EFI_STATUS
137EFIAPI
138DxeRuntimePciSegmentLibDestructor (
139 IN EFI_HANDLE ImageHandle,
140 IN EFI_SYSTEM_TABLE *SystemTable
141 )
142{
143 EFI_STATUS Status;
144
145 //
146 // If one or more PCI devices have been registered for runtime access, then
147 // free the registration table.
148 //
149 if (mDxeRuntimePciSegmentLibRegistrationTable != NULL) {
150 FreePool (mDxeRuntimePciSegmentLibRegistrationTable);
151 }
152
153 //
154 // Close the Set Virtual Address Map event
155 //
156 Status = gBS->CloseEvent (mDxeRuntimePciSegmentLibVirtualNotifyEvent);
157 ASSERT_EFI_ERROR (Status);
158
159 return Status;
160}
161
162/**
163 Register a PCI device so PCI configuration registers may be accessed after
164 SetVirtualAddressMap().
165
166 If any reserved bits in Address are set, then ASSERT().
167
168 @param Address The address that encodes the PCI Bus, Device, Function and
169 Register.
170
171 @retval RETURN_SUCCESS The PCI device was registered for runtime access.
172 @retval RETURN_UNSUPPORTED An attempt was made to call this function
173 after ExitBootServices().
174 @retval RETURN_UNSUPPORTED The resources required to access the PCI device
175 at runtime could not be mapped.
176 @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to
177 complete the registration.
178
179**/
180RETURN_STATUS
181EFIAPI
182PciSegmentRegisterForRuntimeAccess (
183 IN UINTN Address
184 )
185{
186 RETURN_STATUS Status;
187 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
188 UINTN Index;
189 VOID *NewTable;
190 UINTN Count;
191 PCI_SEGMENT_INFO *SegmentInfo;
192 UINT64 EcamAddress;
193
194 //
195 // Convert Address to a ECAM address at the beginning of the PCI Configuration
196 // header for the specified PCI Bus/Dev/Func
197 //
198 Address &= ~(UINTN)EFI_PAGE_MASK;
199 SegmentInfo = GetPciSegmentInfo (&Count);
200 EcamAddress = PciSegmentLibGetEcamAddress (Address, SegmentInfo, Count);
201
202 //
203 // Return an error if this function is called after ExitBootServices().
204 //
205 if (EfiAtRuntime ()) {
206 return RETURN_UNSUPPORTED;
207 }
208 if (sizeof (UINTN) == sizeof (UINT32)) {
209 ASSERT (EcamAddress < BASE_4GB);
210 }
211 Address = (UINTN)EcamAddress;
212
213 //
214 // See if Address has already been registerd for runtime access
215 //
216 for (Index = 0; Index < mDxeRuntimePciSegmentLibNumberOfRuntimeRanges; Index++) {
217 if (mDxeRuntimePciSegmentLibRegistrationTable[Index].PhysicalAddress == Address) {
218 return RETURN_SUCCESS;
219 }
220 }
221
222 //
223 // Get the GCD Memory Descriptor for the ECAM Address
224 //
225 Status = gDS->GetMemorySpaceDescriptor (Address, &Descriptor);
226 if (EFI_ERROR (Status)) {
227 return RETURN_UNSUPPORTED;
228 }
229
230 //
231 // Mark the 4KB region for the PCI Express Bus/Dev/Func as EFI_RUNTIME_MEMORY so the OS
232 // will allocate a virtual address range for the 4KB PCI Configuration Header.
233 //
234 Status = gDS->SetMemorySpaceAttributes (Address, EFI_PAGE_SIZE, Descriptor.Attributes | EFI_MEMORY_RUNTIME);
235 if (EFI_ERROR (Status)) {
236 return RETURN_UNSUPPORTED;
237 }
238
239 //
240 // Grow the size of the registration table
241 //
242 NewTable = ReallocateRuntimePool (
243 (mDxeRuntimePciSegmentLibNumberOfRuntimeRanges + 0) * sizeof (PCI_SEGMENT_RUNTIME_REGISTRATION_TABLE),
244 (mDxeRuntimePciSegmentLibNumberOfRuntimeRanges + 1) * sizeof (PCI_SEGMENT_RUNTIME_REGISTRATION_TABLE),
245 mDxeRuntimePciSegmentLibRegistrationTable
246 );
247 if (NewTable == NULL) {
248 return RETURN_OUT_OF_RESOURCES;
249 }
250 mDxeRuntimePciSegmentLibRegistrationTable = NewTable;
251 mDxeRuntimePciSegmentLibRegistrationTable[mDxeRuntimePciSegmentLibNumberOfRuntimeRanges].PhysicalAddress = Address;
252 mDxeRuntimePciSegmentLibRegistrationTable[mDxeRuntimePciSegmentLibNumberOfRuntimeRanges].VirtualAddress = Address;
253 mDxeRuntimePciSegmentLibNumberOfRuntimeRanges++;
254
255 return RETURN_SUCCESS;
256}
257
258/**
259 Return the linear address for the physical address.
260
261 @param Address The physical address.
262
263 @retval The linear address.
264**/
265UINTN
266PciSegmentLibVirtualAddress (
267 IN UINTN Address
268 )
269{
270 UINTN Index;
271 //
272 // If SetVirtualAddressMap() has not been called, then just return the physical address
273 //
274 if (!EfiGoneVirtual ()) {
275 return Address;
276 }
277
278 //
279 // See if there is a physical address match at the exact same index as the last address match
280 //
281 if (mDxeRuntimePciSegmentLibRegistrationTable[mDxeRuntimePciSegmentLibLastRuntimeRange].PhysicalAddress == (Address & (~(UINTN)EFI_PAGE_MASK))) {
282 //
283 // Convert the physical address to a virtual address and return the virtual address
284 //
285 return (Address & EFI_PAGE_MASK) + mDxeRuntimePciSegmentLibRegistrationTable[mDxeRuntimePciSegmentLibLastRuntimeRange].VirtualAddress;
286 }
287
288 //
289 // Search the entire table for a physical address match
290 //
291 for (Index = 0; Index < mDxeRuntimePciSegmentLibNumberOfRuntimeRanges; Index++) {
292 if (mDxeRuntimePciSegmentLibRegistrationTable[Index].PhysicalAddress == (Address & (~(UINTN)EFI_PAGE_MASK))) {
293 //
294 // Cache the matching index value
295 //
296 mDxeRuntimePciSegmentLibLastRuntimeRange = Index;
297 //
298 // Convert the physical address to a virtual address and return the virtual address
299 //
300 return (Address & EFI_PAGE_MASK) + mDxeRuntimePciSegmentLibRegistrationTable[Index].VirtualAddress;
301 }
302 }
303
304 //
305 // No match was found. This is a critical error at OS runtime, so ASSERT() and force a breakpoint.
306 //
307 ASSERT (FALSE);
308 CpuBreakpoint ();
309
310 //
311 // Return the physical address
312 //
313 return Address;
314}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette