]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Csm/CsmSupportLib/LegacyRegion.c
OvmfPkg/LegacyRegion: Support legacy region manipulation of Q35
[mirror_edk2.git] / OvmfPkg / Csm / CsmSupportLib / LegacyRegion.c
CommitLineData
8016da21 1/** @file\r
2 Legacy Region Support\r
3\r
db27e9f3 4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>\r
8016da21 5\r
6 This program and the accompanying materials are\r
7 licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "LegacyRegion.h"\r
17\r
18//\r
db27e9f3 19// 440/Q35 PAM map.\r
8016da21 20//\r
db27e9f3
RN
21// PAM Range Offset Bits Operation\r
22// 440 Q35\r
23// =============== ==== ==== ==== ===============================================================\r
24// 0xC0000-0xC3FFF 0x5a 0x91 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
25// 0xC4000-0xC7FFF 0x5a 0x91 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
26// 0xC8000-0xCBFFF 0x5b 0x92 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
27// 0xCC000-0xCFFFF 0x5b 0x92 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
28// 0xD0000-0xD3FFF 0x5c 0x93 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
29// 0xD4000-0xD7FFF 0x5c 0x93 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
30// 0xD8000-0xDBFFF 0x5d 0x94 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
31// 0xDC000-0xDFFFF 0x5d 0x94 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
32// 0xE0000-0xE3FFF 0x5e 0x95 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
33// 0xE4000-0xE7FFF 0x5e 0x95 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
34// 0xE8000-0xEBFFF 0x5f 0x96 1:0 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
35// 0xEC000-0xEFFFF 0x5f 0x96 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
36// 0xF0000-0xFFFFF 0x59 0x90 5:4 00 = DRAM Disabled, 01= Read Only, 10 = Write Only, 11 = Normal\r
8016da21 37//\r
38STATIC LEGACY_MEMORY_SECTION_INFO mSectionArray[] = {\r
39 {0xC0000, SIZE_16KB, FALSE, FALSE},\r
40 {0xC4000, SIZE_16KB, FALSE, FALSE},\r
41 {0xC8000, SIZE_16KB, FALSE, FALSE},\r
42 {0xCC000, SIZE_16KB, FALSE, FALSE},\r
43 {0xD0000, SIZE_16KB, FALSE, FALSE},\r
44 {0xD4000, SIZE_16KB, FALSE, FALSE},\r
45 {0xD8000, SIZE_16KB, FALSE, FALSE},\r
46 {0xDC000, SIZE_16KB, FALSE, FALSE},\r
47 {0xE0000, SIZE_16KB, FALSE, FALSE},\r
48 {0xE4000, SIZE_16KB, FALSE, FALSE},\r
49 {0xE8000, SIZE_16KB, FALSE, FALSE},\r
50 {0xEC000, SIZE_16KB, FALSE, FALSE},\r
51 {0xF0000, SIZE_64KB, FALSE, FALSE}\r
52};\r
53\r
db27e9f3
RN
54STATIC PAM_REGISTER_VALUE mRegisterValues440[] = {\r
55 {REG_PAM1_OFFSET_440, 0x01, 0x02},\r
56 {REG_PAM1_OFFSET_440, 0x10, 0x20},\r
57 {REG_PAM2_OFFSET_440, 0x01, 0x02},\r
58 {REG_PAM2_OFFSET_440, 0x10, 0x20},\r
59 {REG_PAM3_OFFSET_440, 0x01, 0x02},\r
60 {REG_PAM3_OFFSET_440, 0x10, 0x20},\r
61 {REG_PAM4_OFFSET_440, 0x01, 0x02},\r
62 {REG_PAM4_OFFSET_440, 0x10, 0x20},\r
63 {REG_PAM5_OFFSET_440, 0x01, 0x02},\r
64 {REG_PAM5_OFFSET_440, 0x10, 0x20},\r
65 {REG_PAM6_OFFSET_440, 0x01, 0x02},\r
66 {REG_PAM6_OFFSET_440, 0x10, 0x20},\r
67 {REG_PAM0_OFFSET_440, 0x10, 0x20}\r
8016da21 68};\r
69\r
db27e9f3
RN
70STATIC PAM_REGISTER_VALUE mRegisterValuesQ35[] = {\r
71 {REG_PAM1_OFFSET_Q35, 0x01, 0x02},\r
72 {REG_PAM1_OFFSET_Q35, 0x10, 0x20},\r
73 {REG_PAM2_OFFSET_Q35, 0x01, 0x02},\r
74 {REG_PAM2_OFFSET_Q35, 0x10, 0x20},\r
75 {REG_PAM3_OFFSET_Q35, 0x01, 0x02},\r
76 {REG_PAM3_OFFSET_Q35, 0x10, 0x20},\r
77 {REG_PAM4_OFFSET_Q35, 0x01, 0x02},\r
78 {REG_PAM4_OFFSET_Q35, 0x10, 0x20},\r
79 {REG_PAM5_OFFSET_Q35, 0x01, 0x02},\r
80 {REG_PAM5_OFFSET_Q35, 0x10, 0x20},\r
81 {REG_PAM6_OFFSET_Q35, 0x01, 0x02},\r
82 {REG_PAM6_OFFSET_Q35, 0x10, 0x20},\r
83 {REG_PAM0_OFFSET_Q35, 0x10, 0x20}\r
84};\r
85\r
86STATIC PAM_REGISTER_VALUE *mRegisterValues;\r
87\r
8016da21 88//\r
89// Handle used to install the Legacy Region Protocol\r
90//\r
91STATIC EFI_HANDLE mHandle = NULL;\r
92\r
93//\r
94// Instance of the Legacy Region Protocol to install into the handle database\r
95//\r
96STATIC EFI_LEGACY_REGION2_PROTOCOL mLegacyRegion2 = {\r
97 LegacyRegion2Decode,\r
98 LegacyRegion2Lock,\r
99 LegacyRegion2BootLock,\r
100 LegacyRegion2Unlock,\r
101 LegacyRegionGetInfo\r
102};\r
103\r
104STATIC\r
105EFI_STATUS\r
106LegacyRegionManipulationInternal (\r
107 IN UINT32 Start,\r
108 IN UINT32 Length,\r
109 IN BOOLEAN *ReadEnable,\r
110 IN BOOLEAN *WriteEnable,\r
111 OUT UINT32 *Granularity\r
112 )\r
113{\r
114 UINT32 EndAddress;\r
115 UINTN Index;\r
116 UINTN StartIndex;\r
117\r
118 //\r
119 // Validate input parameters.\r
120 //\r
121 if (Length == 0 || Granularity == NULL) {\r
122 return EFI_INVALID_PARAMETER;\r
123 }\r
124 EndAddress = Start + Length - 1;\r
125 if ((Start < PAM_BASE_ADDRESS) || EndAddress > PAM_LIMIT_ADDRESS) {\r
126 return EFI_INVALID_PARAMETER;\r
127 }\r
128\r
129 //\r
130 // Loop to find the start PAM.\r
131 //\r
132 StartIndex = 0;\r
133 for (Index = 0; Index < (sizeof(mSectionArray) / sizeof (mSectionArray[0])); Index++) {\r
134 if ((Start >= mSectionArray[Index].Start) && (Start < (mSectionArray[Index].Start + mSectionArray[Index].Length))) {\r
135 StartIndex = Index;\r
136 break;\r
137 }\r
138 }\r
139 ASSERT (Index < (sizeof(mSectionArray) / sizeof (mSectionArray[0])));\r
140\r
141 //\r
142 // Program PAM until end PAM is encountered\r
143 //\r
144 for (Index = StartIndex; Index < (sizeof(mSectionArray) / sizeof (mSectionArray[0])); Index++) {\r
145 if (ReadEnable != NULL) {\r
146 if (*ReadEnable) {\r
147 PciOr8 (\r
148 PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset),\r
149 mRegisterValues[Index].ReadEnableData\r
150 );\r
151 } else {\r
152 PciAnd8 (\r
153 PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset),\r
154 (UINT8) (~mRegisterValues[Index].ReadEnableData)\r
155 );\r
156 }\r
157 }\r
158 if (WriteEnable != NULL) {\r
159 if (*WriteEnable) {\r
160 PciOr8 (\r
161 PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset),\r
162 mRegisterValues[Index].WriteEnableData\r
163 );\r
164 } else {\r
165 PciAnd8 (\r
166 PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset),\r
167 (UINT8) (~mRegisterValues[Index].WriteEnableData)\r
168 );\r
169 }\r
170 }\r
171\r
172 //\r
173 // If the end PAM is encountered, record its length as granularity and jump out.\r
174 //\r
175 if ((EndAddress >= mSectionArray[Index].Start) && (EndAddress < (mSectionArray[Index].Start + mSectionArray[Index].Length))) {\r
176 *Granularity = mSectionArray[Index].Length;\r
177 break;\r
178 }\r
179 }\r
180 ASSERT (Index < (sizeof(mSectionArray) / sizeof (mSectionArray[0])));\r
181\r
182 return EFI_SUCCESS;\r
183}\r
184\r
185STATIC\r
186EFI_STATUS\r
187LegacyRegionGetInfoInternal (\r
188 OUT UINT32 *DescriptorCount,\r
189 OUT LEGACY_MEMORY_SECTION_INFO **Descriptor\r
190 )\r
191{\r
192 UINTN Index;\r
193 UINT8 PamValue;\r
194\r
195 //\r
196 // Check input parameters\r
197 //\r
198 if (DescriptorCount == NULL || Descriptor == NULL) {\r
199 return EFI_INVALID_PARAMETER;\r
200 }\r
201\r
202 //\r
203 // Fill in current status of legacy region.\r
204 //\r
205 *DescriptorCount = sizeof(mSectionArray) / sizeof (mSectionArray[0]);\r
206 for (Index = 0; Index < *DescriptorCount; Index++) {\r
207 PamValue = PciRead8 (PCI_LIB_ADDRESS(PAM_PCI_BUS, PAM_PCI_DEV, PAM_PCI_FUNC, mRegisterValues[Index].PAMRegOffset));\r
208 mSectionArray[Index].ReadEnabled = FALSE;\r
209 if ((PamValue & mRegisterValues[Index].ReadEnableData) != 0) {\r
210 mSectionArray[Index].ReadEnabled = TRUE;\r
211 }\r
212 mSectionArray[Index].WriteEnabled = FALSE;\r
213 if ((PamValue & mRegisterValues[Index].WriteEnableData) != 0) {\r
214 mSectionArray[Index].WriteEnabled = TRUE;\r
215 }\r
216 }\r
217\r
218 *Descriptor = mSectionArray;\r
219 return EFI_SUCCESS;\r
220}\r
221\r
222/**\r
223 Modify the hardware to allow (decode) or disallow (not decode) memory reads in a region.\r
224\r
225 If the On parameter evaluates to TRUE, this function enables memory reads in the address range\r
226 Start to (Start + Length - 1).\r
227 If the On parameter evaluates to FALSE, this function disables memory reads in the address range\r
228 Start to (Start + Length - 1).\r
229\r
230 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
231 @param Start[in] The beginning of the physical address of the region whose attributes\r
232 should be modified.\r
233 @param Length[in] The number of bytes of memory whose attributes should be modified.\r
234 The actual number of bytes modified may be greater than the number\r
235 specified.\r
236 @param Granularity[out] The number of bytes in the last region affected. This may be less\r
237 than the total number of bytes affected if the starting address\r
238 was not aligned to a region's starting address or if the length\r
239 was greater than the number of bytes in the first region.\r
240 @param On[in] Decode / Non-Decode flag.\r
241\r
242 @retval EFI_SUCCESS The region's attributes were successfully modified.\r
243 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
244\r
245**/\r
246EFI_STATUS\r
247EFIAPI\r
248LegacyRegion2Decode (\r
249 IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
250 IN UINT32 Start,\r
251 IN UINT32 Length,\r
252 OUT UINT32 *Granularity,\r
253 IN BOOLEAN *On\r
254 )\r
255{\r
256 return LegacyRegionManipulationInternal (Start, Length, On, NULL, Granularity);\r
257}\r
258\r
259\r
260/**\r
261 Modify the hardware to disallow memory attribute changes in a region.\r
262\r
263 This function makes the attributes of a region read only. Once a region is boot-locked with this\r
264 function, the read and write attributes of that region cannot be changed until a power cycle has\r
265 reset the boot-lock attribute. Calls to Decode(), Lock() and Unlock() will have no effect.\r
266\r
267 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
268 @param Start[in] The beginning of the physical address of the region whose\r
269 attributes should be modified.\r
270 @param Length[in] The number of bytes of memory whose attributes should be modified.\r
271 The actual number of bytes modified may be greater than the number\r
272 specified.\r
273 @param Granularity[out] The number of bytes in the last region affected. This may be less\r
274 than the total number of bytes affected if the starting address was\r
275 not aligned to a region's starting address or if the length was\r
276 greater than the number of bytes in the first region.\r
277\r
278 @retval EFI_SUCCESS The region's attributes were successfully modified.\r
279 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
280 @retval EFI_UNSUPPORTED The chipset does not support locking the configuration registers in\r
281 a way that will not affect memory regions outside the legacy memory\r
282 region.\r
283\r
284**/\r
285EFI_STATUS\r
286EFIAPI\r
287LegacyRegion2BootLock (\r
288 IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
289 IN UINT32 Start,\r
290 IN UINT32 Length,\r
291 OUT UINT32 *Granularity\r
292 )\r
293{\r
294 if ((Start < 0xC0000) || ((Start + Length - 1) > 0xFFFFF)) {\r
295 return EFI_INVALID_PARAMETER;\r
296 }\r
297\r
298 return EFI_UNSUPPORTED;\r
299}\r
300\r
301\r
302/**\r
303 Modify the hardware to disallow memory writes in a region.\r
304\r
305 This function changes the attributes of a memory range to not allow writes.\r
306\r
307 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
308 @param Start[in] The beginning of the physical address of the region whose\r
309 attributes should be modified.\r
310 @param Length[in] The number of bytes of memory whose attributes should be modified.\r
311 The actual number of bytes modified may be greater than the number\r
312 specified.\r
313 @param Granularity[out] The number of bytes in the last region affected. This may be less\r
314 than the total number of bytes affected if the starting address was\r
315 not aligned to a region's starting address or if the length was\r
316 greater than the number of bytes in the first region.\r
317\r
318 @retval EFI_SUCCESS The region's attributes were successfully modified.\r
319 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
320\r
321**/\r
322EFI_STATUS\r
323EFIAPI\r
324LegacyRegion2Lock (\r
325 IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
326 IN UINT32 Start,\r
327 IN UINT32 Length,\r
328 OUT UINT32 *Granularity\r
329 )\r
330{\r
331 BOOLEAN WriteEnable;\r
332\r
333 WriteEnable = FALSE;\r
334 return LegacyRegionManipulationInternal (Start, Length, NULL, &WriteEnable, Granularity);\r
335}\r
336\r
337\r
338/**\r
339 Modify the hardware to allow memory writes in a region.\r
340\r
341 This function changes the attributes of a memory range to allow writes.\r
342\r
343 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
344 @param Start[in] The beginning of the physical address of the region whose\r
345 attributes should be modified.\r
346 @param Length[in] The number of bytes of memory whose attributes should be modified.\r
347 The actual number of bytes modified may be greater than the number\r
348 specified.\r
349 @param Granularity[out] The number of bytes in the last region affected. This may be less\r
350 than the total number of bytes affected if the starting address was\r
351 not aligned to a region's starting address or if the length was\r
352 greater than the number of bytes in the first region.\r
353\r
354 @retval EFI_SUCCESS The region's attributes were successfully modified.\r
355 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
356\r
357**/\r
358EFI_STATUS\r
359EFIAPI\r
360LegacyRegion2Unlock (\r
361 IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
362 IN UINT32 Start,\r
363 IN UINT32 Length,\r
364 OUT UINT32 *Granularity\r
365 )\r
366{\r
367 BOOLEAN WriteEnable;\r
368\r
369 WriteEnable = TRUE;\r
370 return LegacyRegionManipulationInternal (Start, Length, NULL, &WriteEnable, Granularity);\r
371}\r
372\r
373/**\r
374 Get region information for the attributes of the Legacy Region.\r
375\r
376 This function is used to discover the granularity of the attributes for the memory in the legacy\r
377 region. Each attribute may have a different granularity and the granularity may not be the same\r
378 for all memory ranges in the legacy region.\r
379\r
380 @param This[in] Indicates the EFI_LEGACY_REGION_PROTOCOL instance.\r
381 @param DescriptorCount[out] The number of region descriptor entries returned in the Descriptor\r
382 buffer.\r
383 @param Descriptor[out] A pointer to a pointer used to return a buffer where the legacy\r
384 region information is deposited. This buffer will contain a list of\r
385 DescriptorCount number of region descriptors. This function will\r
386 provide the memory for the buffer.\r
387\r
388 @retval EFI_SUCCESS The region's attributes were successfully modified.\r
389 @retval EFI_INVALID_PARAMETER If Start or Length describe an address not in the Legacy Region.\r
390\r
391**/\r
392EFI_STATUS\r
393EFIAPI\r
394LegacyRegionGetInfo (\r
395 IN EFI_LEGACY_REGION2_PROTOCOL *This,\r
396 OUT UINT32 *DescriptorCount,\r
397 OUT EFI_LEGACY_REGION_DESCRIPTOR **Descriptor\r
398 )\r
399{\r
400 LEGACY_MEMORY_SECTION_INFO *SectionInfo;\r
401 UINT32 SectionCount;\r
402 EFI_LEGACY_REGION_DESCRIPTOR *DescriptorArray;\r
403 UINTN Index;\r
404 UINTN DescriptorIndex;\r
405\r
406 //\r
407 // Get section numbers and information\r
408 //\r
409 LegacyRegionGetInfoInternal (&SectionCount, &SectionInfo);\r
410\r
411 //\r
412 // Each section has 3 descriptors, corresponding to readability, writeability, and lock status.\r
413 //\r
414 DescriptorArray = AllocatePool (sizeof (EFI_LEGACY_REGION_DESCRIPTOR) * SectionCount * 3);\r
415 if (DescriptorArray == NULL) {\r
416 return EFI_OUT_OF_RESOURCES;\r
417 }\r
418\r
419 DescriptorIndex = 0;\r
420 for (Index = 0; Index < SectionCount; Index++) {\r
421 DescriptorArray[DescriptorIndex].Start = SectionInfo[Index].Start;\r
422 DescriptorArray[DescriptorIndex].Length = SectionInfo[Index].Length;\r
423 DescriptorArray[DescriptorIndex].Granularity = SectionInfo[Index].Length;\r
424 if (SectionInfo[Index].ReadEnabled) {\r
425 DescriptorArray[DescriptorIndex].Attribute = LegacyRegionDecoded;\r
426 } else {\r
427 DescriptorArray[DescriptorIndex].Attribute = LegacyRegionNotDecoded;\r
428 }\r
429 DescriptorIndex++;\r
430\r
431 //\r
432 // Create descriptor for writeability, according to lock status\r
433 //\r
434 DescriptorArray[DescriptorIndex].Start = SectionInfo[Index].Start;\r
435 DescriptorArray[DescriptorIndex].Length = SectionInfo[Index].Length;\r
436 DescriptorArray[DescriptorIndex].Granularity = SectionInfo[Index].Length;\r
437 if (SectionInfo[Index].WriteEnabled) {\r
438 DescriptorArray[DescriptorIndex].Attribute = LegacyRegionWriteEnabled;\r
439 } else {\r
440 DescriptorArray[DescriptorIndex].Attribute = LegacyRegionWriteDisabled;\r
441 }\r
442 DescriptorIndex++;\r
443\r
444 //\r
445 // Chipset does not support bootlock.\r
446 //\r
447 DescriptorArray[DescriptorIndex].Start = SectionInfo[Index].Start;\r
448 DescriptorArray[DescriptorIndex].Length = SectionInfo[Index].Length;\r
449 DescriptorArray[DescriptorIndex].Granularity = SectionInfo[Index].Length;\r
450 DescriptorArray[DescriptorIndex].Attribute = LegacyRegionNotLocked;\r
451 DescriptorIndex++;\r
452 }\r
453\r
454 *DescriptorCount = (UINT32) DescriptorIndex;\r
455 *Descriptor = DescriptorArray;\r
456\r
457 return EFI_SUCCESS;\r
458}\r
459\r
460/**\r
461 Initialize Legacy Region support\r
462\r
463 @retval EFI_SUCCESS Successfully initialized\r
464\r
465**/\r
466EFI_STATUS\r
467LegacyRegionInit (\r
468 VOID\r
469 )\r
470{\r
471 EFI_STATUS Status;\r
db27e9f3
RN
472 UINT16 HostBridgeDevId;\r
473\r
474 //\r
475 // Query Host Bridge DID to determine platform type\r
476 //\r
477 HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);\r
478 switch (HostBridgeDevId) {\r
479 case INTEL_82441_DEVICE_ID:\r
480 mRegisterValues = mRegisterValues440;\r
481 break;\r
482 case INTEL_Q35_MCH_DEVICE_ID:\r
483 mRegisterValues = mRegisterValuesQ35;\r
484 break;\r
485 default:\r
486 DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",\r
487 __FUNCTION__, HostBridgeDevId));\r
488 ASSERT (FALSE);\r
489 return RETURN_UNSUPPORTED;\r
490 }\r
8016da21 491\r
492 //\r
493 // Install the Legacy Region Protocol on a new handle\r
494 //\r
495 Status = gBS->InstallMultipleProtocolInterfaces (\r
496 &mHandle,\r
497 &gEfiLegacyRegion2ProtocolGuid, &mLegacyRegion2,\r
498 NULL\r
499 );\r
500 ASSERT_EFI_ERROR (Status);\r
501\r
502 return Status;\r
503}\r
504\r