]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/AcpiPlatformDxe/Qemu.c
OvmfPkg: scan memory space map and populate FWDT (32-bit fields only)
[mirror_edk2.git] / OvmfPkg / AcpiPlatformDxe / Qemu.c
1 /** @file
2 OVMF ACPI QEMU support
3
4 Copyright (c) 2008 - 2012, 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 "AcpiPlatform.h"
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/QemuFwCfgLib.h>
19 #include <Library/DxeServicesTableLib.h>
20
21
22 BOOLEAN
23 QemuDetected (
24 VOID
25 )
26 {
27 if (!QemuFwCfgIsAvailable ()) {
28 return FALSE;
29 }
30
31 return TRUE;
32 }
33
34
35 STATIC
36 EFI_STATUS
37 EFIAPI
38 QemuInstallAcpiMadtTable (
39 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
40 IN VOID *AcpiTableBuffer,
41 IN UINTN AcpiTableBufferSize,
42 OUT UINTN *TableKey
43 )
44 {
45 EFI_STATUS Status;
46 UINTN Count;
47 UINTN Loop;
48 EFI_ACPI_DESCRIPTION_HEADER *Hdr;
49 UINTN NewBufferSize;
50 EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic;
51
52 QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount);
53 Count = (UINTN) QemuFwCfgRead16 ();
54 ASSERT (Count >= 1);
55
56 if (Count == 1) {
57 //
58 // The pre-built MADT table covers the single CPU case
59 //
60 return InstallAcpiTable (
61 AcpiProtocol,
62 AcpiTableBuffer,
63 AcpiTableBufferSize,
64 TableKey
65 );
66 }
67
68 //
69 // We need to add additional Local APIC entries to the MADT
70 //
71 NewBufferSize = AcpiTableBufferSize + ((Count - 1) * sizeof (*LocalApic));
72 Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AllocatePool (NewBufferSize);
73 ASSERT (Hdr != NULL);
74
75 CopyMem (Hdr, AcpiTableBuffer, AcpiTableBufferSize);
76
77 LocalApic = (EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE*)
78 (((UINT8*) Hdr) + AcpiTableBufferSize);
79
80 //
81 // Add Local APIC entries for the APs to the MADT
82 //
83 for (Loop = 1; Loop < Count; Loop++) {
84 LocalApic->Type = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC;
85 LocalApic->Length = sizeof (*LocalApic);
86 LocalApic->AcpiProcessorId = (UINT8) Loop;
87 LocalApic->ApicId = (UINT8) Loop;
88 LocalApic->Flags = 1;
89 LocalApic++;
90 }
91
92 Hdr->Length = (UINT32) NewBufferSize;
93
94 Status = InstallAcpiTable (AcpiProtocol, Hdr, NewBufferSize, TableKey);
95
96 FreePool (Hdr);
97
98 return Status;
99 }
100
101
102 #pragma pack(1)
103
104 typedef struct {
105 UINT64 Base;
106 UINT64 End;
107 UINT64 Length;
108 } PCI_WINDOW;
109
110 typedef struct {
111 PCI_WINDOW PciWindow32;
112 PCI_WINDOW PciWindow64;
113 } FIRMWARE_DATA;
114
115 #pragma pack()
116
117
118 STATIC
119 EFI_STATUS
120 EFIAPI
121 PopulateFwData(
122 OUT FIRMWARE_DATA *FwData
123 )
124 {
125 EFI_STATUS Status;
126 UINTN NumDesc;
127 EFI_GCD_MEMORY_SPACE_DESCRIPTOR *AllDesc;
128
129 Status = gDS->GetMemorySpaceMap (&NumDesc, &AllDesc);
130 if (Status == EFI_SUCCESS) {
131 UINT64 NonMmio32MaxExclTop;
132 UINT64 Mmio32MinBase;
133 UINT64 Mmio32MaxExclTop;
134 UINTN CurDesc;
135
136 Status = EFI_UNSUPPORTED;
137
138 NonMmio32MaxExclTop = 0;
139 Mmio32MinBase = BASE_4GB;
140 Mmio32MaxExclTop = 0;
141
142 for (CurDesc = 0; CurDesc < NumDesc; ++CurDesc) {
143 CONST EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
144 UINT64 ExclTop;
145
146 Desc = &AllDesc[CurDesc];
147 ExclTop = Desc->BaseAddress + Desc->Length;
148
149 if (ExclTop <= BASE_4GB) {
150 switch (Desc->GcdMemoryType) {
151 case EfiGcdMemoryTypeNonExistent:
152 break;
153
154 case EfiGcdMemoryTypeReserved:
155 case EfiGcdMemoryTypeSystemMemory:
156 if (NonMmio32MaxExclTop < ExclTop) {
157 NonMmio32MaxExclTop = ExclTop;
158 }
159 break;
160
161 case EfiGcdMemoryTypeMemoryMappedIo:
162 if (Mmio32MinBase > Desc->BaseAddress) {
163 Mmio32MinBase = Desc->BaseAddress;
164 }
165 if (Mmio32MaxExclTop < ExclTop) {
166 Mmio32MaxExclTop = ExclTop;
167 }
168 break;
169
170 default:
171 ASSERT(0);
172 }
173 }
174 }
175
176 if (Mmio32MinBase < NonMmio32MaxExclTop) {
177 Mmio32MinBase = NonMmio32MaxExclTop;
178 }
179
180 if (Mmio32MinBase < Mmio32MaxExclTop) {
181 FwData->PciWindow32.Base = Mmio32MinBase;
182 FwData->PciWindow32.End = Mmio32MaxExclTop - 1;
183 FwData->PciWindow32.Length = Mmio32MaxExclTop - Mmio32MinBase;
184
185 FwData->PciWindow64.Base = 0;
186 FwData->PciWindow64.End = 0;
187 FwData->PciWindow64.Length = 0;
188
189 Status = EFI_SUCCESS;
190 }
191
192 FreePool (AllDesc);
193 }
194
195 DEBUG ((
196 DEBUG_INFO,
197 "ACPI PciWindow32: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
198 FwData->PciWindow32.Base,
199 FwData->PciWindow32.End,
200 FwData->PciWindow32.Length
201 ));
202 DEBUG ((
203 DEBUG_INFO,
204 "ACPI PciWindow64: Base=0x%08lx End=0x%08lx Length=0x%08lx\n",
205 FwData->PciWindow64.Base,
206 FwData->PciWindow64.End,
207 FwData->PciWindow64.Length
208 ));
209
210 return Status;
211 }
212
213
214 STATIC
215 EFI_STATUS
216 EFIAPI
217 QemuInstallAcpiSsdtTable (
218 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
219 IN VOID *AcpiTableBuffer,
220 IN UINTN AcpiTableBufferSize,
221 OUT UINTN *TableKey
222 )
223 {
224 EFI_STATUS Status;
225 FIRMWARE_DATA *FwData;
226
227 Status = EFI_OUT_OF_RESOURCES;
228
229 FwData = AllocateReservedPool (sizeof (*FwData));
230 if (FwData != NULL) {
231 UINTN SsdtSize;
232 UINT8 *Ssdt;
233
234 SsdtSize = AcpiTableBufferSize + 17;
235 Ssdt = AllocatePool (SsdtSize);
236
237 if (Ssdt != NULL) {
238 Status = PopulateFwData (FwData);
239
240 if (Status == EFI_SUCCESS) {
241 UINT8 *SsdtPtr;
242
243 SsdtPtr = Ssdt;
244
245 CopyMem (SsdtPtr, AcpiTableBuffer, AcpiTableBufferSize);
246 SsdtPtr += AcpiTableBufferSize;
247
248 //
249 // build "OperationRegion(FWDT, SystemMemory, 0x12345678, 0x87654321)"
250 //
251 *(SsdtPtr++) = 0x5B; // ExtOpPrefix
252 *(SsdtPtr++) = 0x80; // OpRegionOp
253 *(SsdtPtr++) = 'F';
254 *(SsdtPtr++) = 'W';
255 *(SsdtPtr++) = 'D';
256 *(SsdtPtr++) = 'T';
257 *(SsdtPtr++) = 0x00; // SystemMemory
258 *(SsdtPtr++) = 0x0C; // DWordPrefix
259
260 //
261 // no virtual addressing yet, take the four least significant bytes
262 //
263 CopyMem(SsdtPtr, &FwData, 4);
264 SsdtPtr += 4;
265
266 *(SsdtPtr++) = 0x0C; // DWordPrefix
267
268 *(UINT32*) SsdtPtr = sizeof (*FwData);
269 SsdtPtr += 4;
270
271 ASSERT(SsdtPtr - Ssdt == SsdtSize);
272 ((EFI_ACPI_DESCRIPTION_HEADER *) Ssdt)->Length = SsdtSize;
273 Status = InstallAcpiTable (AcpiProtocol, Ssdt, SsdtSize, TableKey);
274 }
275
276 FreePool(Ssdt);
277 }
278
279 if (Status != EFI_SUCCESS) {
280 FreePool(FwData);
281 }
282 }
283
284 return Status;
285 }
286
287
288 EFI_STATUS
289 EFIAPI
290 QemuInstallAcpiTable (
291 IN EFI_ACPI_TABLE_PROTOCOL *AcpiProtocol,
292 IN VOID *AcpiTableBuffer,
293 IN UINTN AcpiTableBufferSize,
294 OUT UINTN *TableKey
295 )
296 {
297 EFI_ACPI_DESCRIPTION_HEADER *Hdr;
298 EFI_ACPI_TABLE_INSTALL_ACPI_TABLE TableInstallFunction;
299
300 Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AcpiTableBuffer;
301 switch (Hdr->Signature) {
302 case EFI_ACPI_1_0_APIC_SIGNATURE:
303 TableInstallFunction = QemuInstallAcpiMadtTable;
304 break;
305 case EFI_ACPI_1_0_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
306 TableInstallFunction = QemuInstallAcpiSsdtTable;
307 break;
308 default:
309 TableInstallFunction = InstallAcpiTable;
310 }
311
312 return TableInstallFunction (
313 AcpiProtocol,
314 AcpiTableBuffer,
315 AcpiTableBufferSize,
316 TableKey
317 );
318 }
319