IntelSiliconPkg/VtdPeiSample: Add premem support.
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / PlatformVTdInfoSamplePei / PlatformVTdInfoSamplePei.c
1 /** @file
2 Platform VTd Info Sample PEI driver.
3
4 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
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 <PiPei.h>
16
17 #include <Ppi/VtdInfo.h>
18
19 #include <Library/PeiServicesLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/PciLib.h>
22 #include <Library/IoLib.h>
23 #include <Library/MemoryAllocationLib.h>
24
25 #define R_SA_MCHBAR (0x48)
26 #define R_SA_GGC (0x50)
27 #define N_SKL_SA_GGC_GGMS_OFFSET (0x6)
28 #define B_SKL_SA_GGC_GGMS_MASK (0xc0)
29 #define N_SKL_SA_GGC_GMS_OFFSET (0x8)
30 #define B_SKL_SA_GGC_GMS_MASK (0xff00)
31 #define V_SKL_SA_GGC_GGMS_8MB 3
32 #define R_SA_TOLUD (0xbc)
33
34 #define R_SA_MCHBAR_VTD1_OFFSET 0x5400 ///< HW UNIT for IGD
35 #define R_SA_MCHBAR_VTD2_OFFSET 0x5410 ///< HW UNIT for all other - PEG, USB, SATA etc
36
37 EFI_GUID gEdkiiSiliconInitializedPpiGuid = {0x82a72dc8, 0x61ec, 0x403e, {0xb1, 0x5a, 0x8d, 0x7a, 0x3a, 0x71, 0x84, 0x98}};
38
39 typedef struct {
40 EFI_ACPI_DMAR_HEADER DmarHeader;
41 //
42 // VTd engine 1 - integrated graphic
43 //
44 EFI_ACPI_DMAR_DRHD_HEADER Drhd1;
45 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER Drhd11;
46 EFI_ACPI_DMAR_PCI_PATH Drhd111;
47 //
48 // VTd engine 2 - all rest
49 //
50 EFI_ACPI_DMAR_DRHD_HEADER Drhd2;
51 //
52 // RMRR 1 - integrated graphic
53 //
54 EFI_ACPI_DMAR_RMRR_HEADER Rmrr1;
55 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER Rmrr11;
56 EFI_ACPI_DMAR_PCI_PATH Rmrr111;
57 } MY_VTD_INFO_PPI;
58
59 MY_VTD_INFO_PPI mPlatformVTdSample = {
60 { // DmarHeader
61 { // Header
62 EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE,
63 sizeof(MY_VTD_INFO_PPI),
64 EFI_ACPI_DMAR_REVISION,
65 },
66 0x26, // HostAddressWidth
67 },
68
69 { // Drhd1
70 { // Header
71 EFI_ACPI_DMAR_TYPE_DRHD,
72 sizeof(EFI_ACPI_DMAR_DRHD_HEADER) +
73 sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER) +
74 sizeof(EFI_ACPI_DMAR_PCI_PATH)
75 },
76 0, // Flags
77 0, // Reserved
78 0, // SegmentNumber
79 0xFED90000 // RegisterBaseAddress -- TO BE PATCHED
80 },
81 { // Drhd11
82 EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT,
83 sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER) +
84 sizeof(EFI_ACPI_DMAR_PCI_PATH),
85 0, // Reserved2
86 0, // EnumerationId
87 0 // StartBusNumber
88 },
89 { // Drhd111
90 2, // Device
91 0 // Function
92 },
93
94 { // Drhd2
95 { // Header
96 EFI_ACPI_DMAR_TYPE_DRHD,
97 sizeof(EFI_ACPI_DMAR_DRHD_HEADER)
98 },
99 EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL, // Flags
100 0, // Reserved
101 0, // SegmentNumber
102 0xFED91000 // RegisterBaseAddress -- TO BE PATCHED
103 },
104
105 { // Rmrr1
106 { // Header
107 EFI_ACPI_DMAR_TYPE_RMRR,
108 sizeof(EFI_ACPI_DMAR_RMRR_HEADER) +
109 sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER) +
110 sizeof(EFI_ACPI_DMAR_PCI_PATH)
111 },
112 {0}, // Reserved
113 0, // SegmentNumber
114 0x0, // ReservedMemoryRegionBaseAddress -- TO BE PATCHED
115 0x0 // ReservedMemoryRegionLimitAddress -- TO BE PATCHED
116 },
117 { // Rmrr11
118 EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT,
119 sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER) +
120 sizeof(EFI_ACPI_DMAR_PCI_PATH),
121 0, // Reserved2
122 0, // EnumerationId
123 0 // StartBusNumber
124 },
125 { // Rmrr111
126 2, // Device
127 0 // Function
128 },
129 };
130
131 EFI_PEI_PPI_DESCRIPTOR mPlatformVTdInfoSampleDesc = {
132 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
133 &gEdkiiVTdInfoPpiGuid,
134 &mPlatformVTdSample
135 };
136
137 typedef struct {
138 EFI_ACPI_DMAR_HEADER DmarHeader;
139 //
140 // VTd engine 2 - all rest
141 //
142 EFI_ACPI_DMAR_DRHD_HEADER Drhd2;
143 } MY_VTD_INFO_NO_IGD_PPI;
144
145 MY_VTD_INFO_NO_IGD_PPI mPlatformVTdNoIgdSample = {
146 { // DmarHeader
147 { // Header
148 EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE,
149 sizeof(MY_VTD_INFO_NO_IGD_PPI),
150 EFI_ACPI_DMAR_REVISION,
151 },
152 0x26, // HostAddressWidth
153 },
154
155 { // Drhd2
156 { // Header
157 EFI_ACPI_DMAR_TYPE_DRHD,
158 sizeof(EFI_ACPI_DMAR_DRHD_HEADER)
159 },
160 EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL, // Flags
161 0, // Reserved
162 0, // SegmentNumber
163 0xFED91000 // RegisterBaseAddress -- TO BE PATCHED
164 },
165 };
166
167 EFI_PEI_PPI_DESCRIPTOR mPlatformVTdNoIgdInfoSampleDesc = {
168 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
169 &gEdkiiVTdInfoPpiGuid,
170 &mPlatformVTdNoIgdSample
171 };
172
173 /**
174 Initialize VTd register.
175 **/
176 VOID
177 InitDmar (
178 VOID
179 )
180 {
181 UINT32 MchBar;
182
183 DEBUG ((DEBUG_INFO, "InitDmar\n"));
184
185 MchBar = PciRead32 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_MCHBAR)) & ~BIT0;
186 PciWrite32 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_MCHBAR), 0xFED10000 | BIT0);
187 DEBUG ((DEBUG_INFO, "MchBar - %x\n", MchBar));
188
189 MmioWrite32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET, (UINT32)mPlatformVTdSample.Drhd2.RegisterBaseAddress | 1);
190 DEBUG ((DEBUG_INFO, "VTd2 - %x\n", (MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET))));
191 }
192
193 /**
194 Patch Graphic UMA address in RMRR and base address.
195 **/
196 EFI_PEI_PPI_DESCRIPTOR *
197 PatchDmar (
198 VOID
199 )
200 {
201 UINT32 MchBar;
202 UINT16 IgdMode;
203 UINT16 GttMode;
204 UINT32 IgdMemSize;
205 UINT32 GttMemSize;
206 MY_VTD_INFO_PPI *PlatformVTdSample;
207 EFI_PEI_PPI_DESCRIPTOR *PlatformVTdInfoSampleDesc;
208 MY_VTD_INFO_NO_IGD_PPI *PlatformVTdNoIgdSample;
209 EFI_PEI_PPI_DESCRIPTOR *PlatformVTdNoIgdInfoSampleDesc;
210
211 DEBUG ((DEBUG_INFO, "PatchDmar\n"));
212
213 if (PciRead16 (PCI_LIB_ADDRESS(0, 2, 0, 0)) != 0xFFFF) {
214 PlatformVTdSample = AllocateCopyPool (sizeof(MY_VTD_INFO_PPI), &mPlatformVTdSample);
215 ASSERT(PlatformVTdSample != NULL);
216 PlatformVTdInfoSampleDesc = AllocateCopyPool (sizeof(EFI_PEI_PPI_DESCRIPTOR), &mPlatformVTdInfoSampleDesc);
217 ASSERT(PlatformVTdInfoSampleDesc != NULL);
218 PlatformVTdInfoSampleDesc->Ppi = PlatformVTdSample;
219
220 ///
221 /// Calculate IGD memsize
222 ///
223 IgdMode = ((PciRead16 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_GGC)) & B_SKL_SA_GGC_GMS_MASK) >> N_SKL_SA_GGC_GMS_OFFSET) & 0xFF;
224 if (IgdMode < 0xF0) {
225 IgdMemSize = IgdMode * 32 * (1024) * (1024);
226 } else {
227 IgdMemSize = 4 * (IgdMode - 0xF0 + 1) * (1024) * (1024);
228 }
229
230 ///
231 /// Calculate GTT mem size
232 ///
233 GttMemSize = 0;
234 GttMode = (PciRead16 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_GGC)) & B_SKL_SA_GGC_GGMS_MASK) >> N_SKL_SA_GGC_GGMS_OFFSET;
235 if (GttMode <= V_SKL_SA_GGC_GGMS_8MB) {
236 GttMemSize = (1 << GttMode) * (1024) * (1024);
237 }
238
239 PlatformVTdSample->Rmrr1.ReservedMemoryRegionBaseAddress = (PciRead32 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_TOLUD)) & ~(0x01)) - IgdMemSize - GttMemSize;
240 PlatformVTdSample->Rmrr1.ReservedMemoryRegionLimitAddress = PlatformVTdSample->Rmrr1.ReservedMemoryRegionBaseAddress + IgdMemSize + GttMemSize - 1;
241
242 ///
243 /// Update DRHD structures of DmarTable
244 ///
245 MchBar = PciRead32 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_MCHBAR)) & ~BIT0;
246
247 if ((MmioRead32 (MchBar + R_SA_MCHBAR_VTD1_OFFSET) &~1) != 0) {
248 PlatformVTdSample->Drhd1.RegisterBaseAddress = (MmioRead32 (MchBar + R_SA_MCHBAR_VTD1_OFFSET) &~1);
249 } else {
250 MmioWrite32 (MchBar + R_SA_MCHBAR_VTD1_OFFSET, (UINT32)PlatformVTdSample->Drhd1.RegisterBaseAddress | 1);
251 }
252 DEBUG ((DEBUG_INFO, "VTd1 - %x\n", (MmioRead32 (MchBar + R_SA_MCHBAR_VTD1_OFFSET))));
253
254 if ((MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET) &~1) != 0) {
255 PlatformVTdSample->Drhd2.RegisterBaseAddress = (MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET) &~1);
256 } else {
257 MmioWrite32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET, (UINT32)PlatformVTdSample->Drhd2.RegisterBaseAddress | 1);
258 }
259 DEBUG ((DEBUG_INFO, "VTd2 - %x\n", (MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET))));
260
261 return PlatformVTdInfoSampleDesc;
262 } else {
263 PlatformVTdNoIgdSample = AllocateCopyPool (sizeof(MY_VTD_INFO_NO_IGD_PPI), &mPlatformVTdNoIgdSample);
264 ASSERT(PlatformVTdNoIgdSample != NULL);
265 PlatformVTdNoIgdInfoSampleDesc = AllocateCopyPool (sizeof(EFI_PEI_PPI_DESCRIPTOR), &mPlatformVTdNoIgdInfoSampleDesc);
266 ASSERT(PlatformVTdNoIgdInfoSampleDesc != NULL);
267 PlatformVTdNoIgdInfoSampleDesc->Ppi = PlatformVTdNoIgdSample;
268
269 ///
270 /// Update DRHD structures of DmarTable
271 ///
272 MchBar = PciRead32 (PCI_LIB_ADDRESS(0, 0, 0, R_SA_MCHBAR)) & ~BIT0;
273
274 if ((MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET) &~1) != 0) {
275 PlatformVTdNoIgdSample->Drhd2.RegisterBaseAddress = (MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET) &~1);
276 } else {
277 MmioWrite32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET, (UINT32)PlatformVTdNoIgdSample->Drhd2.RegisterBaseAddress | 1);
278 }
279 DEBUG ((DEBUG_INFO, "VTd2 - %x\n", (MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET))));
280
281 return PlatformVTdNoIgdInfoSampleDesc;
282 }
283 }
284
285 /**
286 The callback function for SiliconInitializedPpi.
287 It reinstalls VTD_INFO_PPI.
288
289 @param[in] PeiServices General purpose services available to every PEIM.
290 @param[in] NotifyDescriptor Notify that this module published.
291 @param[in] Ppi PPI that was installed.
292
293 @retval EFI_SUCCESS The function completed successfully.
294 **/
295 EFI_STATUS
296 EFIAPI
297 SiliconInitializedPpiNotifyCallback (
298 IN CONST EFI_PEI_SERVICES **PeiServices,
299 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
300 IN VOID *Ppi
301 )
302 {
303 EFI_STATUS Status;
304 EFI_PEI_PPI_DESCRIPTOR *PpiDesc;
305
306 PpiDesc = PatchDmar ();
307
308 Status = PeiServicesReInstallPpi (&mPlatformVTdNoIgdInfoSampleDesc, PpiDesc);
309 ASSERT_EFI_ERROR (Status);
310 return EFI_SUCCESS;
311 }
312
313 EFI_PEI_NOTIFY_DESCRIPTOR mSiliconInitializedNotifyList = {
314 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
315 &gEdkiiSiliconInitializedPpiGuid,
316 (EFI_PEIM_NOTIFY_ENTRY_POINT) SiliconInitializedPpiNotifyCallback
317 };
318
319 /**
320 Platform VTd Info sample driver.
321
322 @param[in] FileHandle Handle of the file being invoked.
323 @param[in] PeiServices Describes the list of possible PEI Services.
324
325 @retval EFI_SUCCESS if it completed successfully.
326 **/
327 EFI_STATUS
328 EFIAPI
329 PlatformVTdInfoSampleInitialize (
330 IN EFI_PEI_FILE_HANDLE FileHandle,
331 IN CONST EFI_PEI_SERVICES **PeiServices
332 )
333 {
334 EFI_STATUS Status;
335 BOOLEAN SiliconInitialized;
336 VOID *SiliconInitializedPpi;
337 EFI_PEI_PPI_DESCRIPTOR *PpiDesc;
338
339 SiliconInitialized = FALSE;
340 //
341 // Check if silicon is initialized.
342 //
343 Status = PeiServicesLocatePpi (
344 &gEdkiiSiliconInitializedPpiGuid,
345 0,
346 NULL,
347 &SiliconInitializedPpi
348 );
349 if (!EFI_ERROR(Status)) {
350 SiliconInitialized = TRUE;
351 }
352 DEBUG ((DEBUG_INFO, "SiliconInitialized - %x\n", SiliconInitialized));
353 if (!SiliconInitialized) {
354 Status = PeiServicesNotifyPpi (&mSiliconInitializedNotifyList);
355 InitDmar ();
356
357 Status = PeiServicesInstallPpi (&mPlatformVTdNoIgdInfoSampleDesc);
358 ASSERT_EFI_ERROR (Status);
359 } else {
360 PpiDesc = PatchDmar ();
361
362 Status = PeiServicesInstallPpi (PpiDesc);
363 ASSERT_EFI_ERROR (Status);
364 }
365
366 return Status;
367 }