]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/ArmVirtualizationPkg/VirtFdtDxe/VirtFdtDxe.c
ArmPkg: allow HYP timer interrupt to be omitted
[mirror_edk2.git] / ArmPlatformPkg / ArmVirtualizationPkg / VirtFdtDxe / VirtFdtDxe.c
1 /** @file
2 * Device tree enumeration DXE driver for ARM Virtual Machines
3 *
4 * Copyright (c) 2014, Linaro Ltd. All rights reserved.<BR>
5 *
6 * This program and the accompanying materials are
7 * licensed and made available under the terms and conditions of the BSD License
8 * which accompanies this distribution. The full text of the license may be found at
9 * http://opensource.org/licenses/bsd-license.php
10 *
11 * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 *
14 **/
15
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/UefiLib.h>
19 #include <Library/BaseMemoryLib.h>
20 #include <Library/UefiDriverEntryPoint.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/VirtioMmioDeviceLib.h>
24 #include <Library/DevicePathLib.h>
25 #include <Library/PcdLib.h>
26 #include <Library/DxeServicesLib.h>
27 #include <libfdt.h>
28
29 #include <Guid/Fdt.h>
30 #include <Guid/VirtioMmioTransport.h>
31
32 #pragma pack (1)
33 typedef struct {
34 VENDOR_DEVICE_PATH Vendor;
35 UINT64 PhysBase;
36 EFI_DEVICE_PATH_PROTOCOL End;
37 } VIRTIO_TRANSPORT_DEVICE_PATH;
38 #pragma pack ()
39
40 typedef enum {
41 PropertyTypeUnknown,
42 PropertyTypeGic,
43 PropertyTypeRtc,
44 PropertyTypeVirtio,
45 PropertyTypeUart,
46 PropertyTypeTimer,
47 PropertyTypePsci,
48 PropertyTypeFwCfg,
49 PropertyTypePciHost,
50 } PROPERTY_TYPE;
51
52 typedef struct {
53 PROPERTY_TYPE Type;
54 CHAR8 Compatible[32];
55 } PROPERTY;
56
57 STATIC CONST PROPERTY CompatibleProperties[] = {
58 { PropertyTypeGic, "arm,cortex-a15-gic" },
59 { PropertyTypeRtc, "arm,pl031" },
60 { PropertyTypeVirtio, "virtio,mmio" },
61 { PropertyTypeUart, "arm,pl011" },
62 { PropertyTypeTimer, "arm,armv7-timer" },
63 { PropertyTypeTimer, "arm,armv8-timer" },
64 { PropertyTypePsci, "arm,psci-0.2" },
65 { PropertyTypeFwCfg, "qemu,fw-cfg-mmio" },
66 { PropertyTypePciHost, "pci-host-ecam-generic" },
67 { PropertyTypeUnknown, "" }
68 };
69
70 typedef struct {
71 UINT32 Type;
72 UINT32 Number;
73 UINT32 Flags;
74 } INTERRUPT_PROPERTY;
75
76 STATIC
77 PROPERTY_TYPE
78 GetTypeFromNode (
79 IN CONST CHAR8 *NodeType,
80 IN UINTN Size
81 )
82 {
83 CONST CHAR8 *Compatible;
84 CONST PROPERTY *CompatibleProperty;
85
86 //
87 // A 'compatible' node may contain a sequence of NULL terminated
88 // compatible strings so check each one
89 //
90 for (Compatible = NodeType; Compatible < NodeType + Size && *Compatible;
91 Compatible += 1 + AsciiStrLen (Compatible)) {
92 for (CompatibleProperty = CompatibleProperties; CompatibleProperty->Compatible[0]; CompatibleProperty++) {
93 if (AsciiStrCmp (CompatibleProperty->Compatible, Compatible) == 0) {
94 return CompatibleProperty->Type;
95 }
96 }
97 }
98 return PropertyTypeUnknown;
99 }
100
101 //
102 // We expect the "ranges" property of "pci-host-ecam-generic" to consist of
103 // records like this.
104 //
105 #pragma pack (1)
106 typedef struct {
107 UINT32 Type;
108 UINT64 ChildBase;
109 UINT64 CpuBase;
110 UINT64 Size;
111 } DTB_PCI_HOST_RANGE_RECORD;
112 #pragma pack ()
113
114 #define DTB_PCI_HOST_RANGE_RELOCATABLE BIT31
115 #define DTB_PCI_HOST_RANGE_PREFETCHABLE BIT30
116 #define DTB_PCI_HOST_RANGE_ALIASED BIT29
117 #define DTB_PCI_HOST_RANGE_MMIO32 BIT25
118 #define DTB_PCI_HOST_RANGE_MMIO64 (BIT25 | BIT24)
119 #define DTB_PCI_HOST_RANGE_IO BIT24
120 #define DTB_PCI_HOST_RANGE_TYPEMASK (BIT31 | BIT30 | BIT29 | BIT25 | BIT24)
121
122 /**
123 Process the device tree node describing the generic PCI host controller.
124
125 param[in] DeviceTreeBase Pointer to the device tree.
126
127 param[in] Node Offset of the device tree node whose "compatible"
128 property is "pci-host-ecam-generic".
129
130 param[in] RegProp Pointer to the "reg" property of Node. The caller
131 is responsible for ensuring that the size of the
132 property is 4 UINT32 cells.
133
134 @retval EFI_SUCCESS Parsing successful, properties parsed from Node
135 have been stored in dynamic PCDs.
136
137 @retval EFI_PROTOCOL_ERROR Parsing failed. PCDs are left unchanged.
138 **/
139 STATIC
140 EFI_STATUS
141 EFIAPI
142 ProcessPciHost (
143 IN CONST VOID *DeviceTreeBase,
144 IN INT32 Node,
145 IN CONST VOID *RegProp
146 )
147 {
148 UINT64 ConfigBase, ConfigSize;
149 CONST VOID *Prop;
150 INT32 Len;
151 UINT32 BusMin, BusMax;
152 UINT32 RecordIdx;
153 UINT64 IoBase, IoSize, IoTranslation;
154 UINT64 MmioBase, MmioSize, MmioTranslation;
155
156 //
157 // Fetch the ECAM window.
158 //
159 ConfigBase = fdt64_to_cpu (((CONST UINT64 *)RegProp)[0]);
160 ConfigSize = fdt64_to_cpu (((CONST UINT64 *)RegProp)[1]);
161
162 //
163 // Fetch the bus range (note: inclusive).
164 //
165 Prop = fdt_getprop (DeviceTreeBase, Node, "bus-range", &Len);
166 if (Prop == NULL || Len != 2 * sizeof(UINT32)) {
167 DEBUG ((EFI_D_ERROR, "%a: 'bus-range' not found or invalid\n",
168 __FUNCTION__));
169 return EFI_PROTOCOL_ERROR;
170 }
171 BusMin = fdt32_to_cpu (((CONST UINT32 *)Prop)[0]);
172 BusMax = fdt32_to_cpu (((CONST UINT32 *)Prop)[1]);
173
174 //
175 // Sanity check: the config space must accommodate all 4K register bytes of
176 // all 8 functions of all 32 devices of all buses.
177 //
178 if (BusMax < BusMin || BusMax - BusMin == MAX_UINT32 ||
179 DivU64x32 (ConfigSize, SIZE_4KB * 8 * 32) < BusMax - BusMin + 1) {
180 DEBUG ((EFI_D_ERROR, "%a: invalid 'bus-range' and/or 'reg'\n",
181 __FUNCTION__));
182 return EFI_PROTOCOL_ERROR;
183 }
184
185 //
186 // Iterate over "ranges".
187 //
188 Prop = fdt_getprop (DeviceTreeBase, Node, "ranges", &Len);
189 if (Prop == NULL || Len == 0 ||
190 Len % sizeof (DTB_PCI_HOST_RANGE_RECORD) != 0) {
191 DEBUG ((EFI_D_ERROR, "%a: 'ranges' not found or invalid\n", __FUNCTION__));
192 return EFI_PROTOCOL_ERROR;
193 }
194
195 //
196 // IoBase, IoTranslation, MmioBase and MmioTranslation are initialized only
197 // in order to suppress '-Werror=maybe-uninitialized' warnings *incorrectly*
198 // emitted by some gcc versions.
199 //
200 IoBase = 0;
201 IoTranslation = 0;
202 MmioBase = 0;
203 MmioTranslation = 0;
204
205 //
206 // IoSize and MmioSize are initialized to zero because the logic below
207 // requires it.
208 //
209 IoSize = 0;
210 MmioSize = 0;
211 for (RecordIdx = 0; RecordIdx < Len / sizeof (DTB_PCI_HOST_RANGE_RECORD);
212 ++RecordIdx) {
213 CONST DTB_PCI_HOST_RANGE_RECORD *Record;
214
215 Record = (CONST DTB_PCI_HOST_RANGE_RECORD *)Prop + RecordIdx;
216 switch (fdt32_to_cpu (Record->Type) & DTB_PCI_HOST_RANGE_TYPEMASK) {
217 case DTB_PCI_HOST_RANGE_IO:
218 IoBase = fdt64_to_cpu (Record->ChildBase);
219 IoSize = fdt64_to_cpu (Record->Size);
220 IoTranslation = fdt64_to_cpu (Record->CpuBase) - IoBase;
221 break;
222
223 case DTB_PCI_HOST_RANGE_MMIO32:
224 MmioBase = fdt64_to_cpu (Record->ChildBase);
225 MmioSize = fdt64_to_cpu (Record->Size);
226 MmioTranslation = fdt64_to_cpu (Record->CpuBase) - MmioBase;
227
228 if (MmioBase > MAX_UINT32 || MmioSize > MAX_UINT32 ||
229 MmioBase + MmioSize > SIZE_4GB) {
230 DEBUG ((EFI_D_ERROR, "%a: MMIO32 space invalid\n", __FUNCTION__));
231 return EFI_PROTOCOL_ERROR;
232 }
233
234 if (MmioTranslation != 0) {
235 DEBUG ((EFI_D_ERROR, "%a: unsupported nonzero MMIO32 translation "
236 "0x%Lx\n", __FUNCTION__, MmioTranslation));
237 return EFI_UNSUPPORTED;
238 }
239
240 break;
241 }
242 }
243 if (IoSize == 0 || MmioSize == 0) {
244 DEBUG ((EFI_D_ERROR, "%a: %a space empty\n", __FUNCTION__,
245 (IoSize == 0) ? "IO" : "MMIO32"));
246 return EFI_PROTOCOL_ERROR;
247 }
248
249 PcdSet64 (PcdPciExpressBaseAddress, ConfigBase);
250
251 PcdSet32 (PcdPciBusMin, BusMin);
252 PcdSet32 (PcdPciBusMax, BusMax);
253
254 PcdSet64 (PcdPciIoBase, IoBase);
255 PcdSet64 (PcdPciIoSize, IoSize);
256 PcdSet64 (PcdPciIoTranslation, IoTranslation);
257
258 PcdSet32 (PcdPciMmio32Base, (UINT32)MmioBase);
259 PcdSet32 (PcdPciMmio32Size, (UINT32)MmioSize);
260
261 PcdSetBool (PcdPciDisableBusEnumeration, FALSE);
262
263 DEBUG ((EFI_D_INFO, "%a: Config[0x%Lx+0x%Lx) Bus[0x%x..0x%x] "
264 "Io[0x%Lx+0x%Lx)@0x%Lx Mem[0x%Lx+0x%Lx)@0x%Lx\n", __FUNCTION__, ConfigBase,
265 ConfigSize, BusMin, BusMax, IoBase, IoSize, IoTranslation, MmioBase,
266 MmioSize, MmioTranslation));
267 return EFI_SUCCESS;
268 }
269
270
271 EFI_STATUS
272 EFIAPI
273 InitializeVirtFdtDxe (
274 IN EFI_HANDLE ImageHandle,
275 IN EFI_SYSTEM_TABLE *SystemTable
276 )
277 {
278 VOID *DeviceTreeBase;
279 INT32 Node, Prev;
280 INT32 RtcNode;
281 EFI_STATUS Status;
282 CONST CHAR8 *Type;
283 INT32 Len;
284 PROPERTY_TYPE PropType;
285 CONST VOID *RegProp;
286 VIRTIO_TRANSPORT_DEVICE_PATH *DevicePath;
287 EFI_HANDLE Handle;
288 UINT64 RegBase;
289 UINT64 DistBase, CpuBase;
290 CONST INTERRUPT_PROPERTY *InterruptProp;
291 INT32 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum;
292 CONST CHAR8 *PsciMethod;
293 UINT64 FwCfgSelectorAddress;
294 UINT64 FwCfgSelectorSize;
295 UINT64 FwCfgDataAddress;
296 UINT64 FwCfgDataSize;
297
298 DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeBaseAddress);
299 ASSERT (DeviceTreeBase != NULL);
300
301 if (fdt_check_header (DeviceTreeBase) != 0) {
302 DEBUG ((EFI_D_ERROR, "%a: No DTB found @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
303 return EFI_NOT_FOUND;
304 }
305
306 Status = gBS->InstallConfigurationTable (&gFdtTableGuid, DeviceTreeBase);
307 ASSERT_EFI_ERROR (Status);
308
309 DEBUG ((EFI_D_INFO, "%a: DTB @ 0x%p\n", __FUNCTION__, DeviceTreeBase));
310
311 RtcNode = -1;
312 //
313 // Now enumerate the nodes and install peripherals that we are interested in,
314 // i.e., GIC, RTC and virtio MMIO nodes
315 //
316 for (Prev = 0;; Prev = Node) {
317 Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
318 if (Node < 0) {
319 break;
320 }
321
322 Type = fdt_getprop (DeviceTreeBase, Node, "compatible", &Len);
323 if (Type == NULL) {
324 continue;
325 }
326
327 PropType = GetTypeFromNode (Type, Len);
328 if (PropType == PropertyTypeUnknown) {
329 continue;
330 }
331
332 //
333 // Get the 'reg' property of this node. For now, we will assume
334 // 8 byte quantities for base and size, respectively.
335 // TODO use #cells root properties instead
336 //
337 RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
338 ASSERT ((RegProp != NULL) || (PropType == PropertyTypeTimer) ||
339 (PropType == PropertyTypePsci));
340
341 switch (PropType) {
342 case PropertyTypePciHost:
343 ASSERT (Len == 2 * sizeof (UINT64));
344 Status = ProcessPciHost (DeviceTreeBase, Node, RegProp);
345 ASSERT_EFI_ERROR (Status);
346 break;
347
348 case PropertyTypeFwCfg:
349 ASSERT (Len == 2 * sizeof (UINT64));
350
351 FwCfgDataAddress = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
352 FwCfgDataSize = 8;
353 FwCfgSelectorAddress = FwCfgDataAddress + FwCfgDataSize;
354 FwCfgSelectorSize = 2;
355
356 //
357 // The following ASSERT()s express
358 //
359 // Address + Size - 1 <= MAX_UINTN
360 //
361 // for both registers, that is, that the last byte in each MMIO range is
362 // expressible as a MAX_UINTN. The form below is mathematically
363 // equivalent, and it also prevents any unsigned overflow before the
364 // comparison.
365 //
366 ASSERT (FwCfgSelectorAddress <= MAX_UINTN - FwCfgSelectorSize + 1);
367 ASSERT (FwCfgDataAddress <= MAX_UINTN - FwCfgDataSize + 1);
368
369 PcdSet64 (PcdFwCfgSelectorAddress, FwCfgSelectorAddress);
370 PcdSet64 (PcdFwCfgDataAddress, FwCfgDataAddress);
371
372 DEBUG ((EFI_D_INFO, "Found FwCfg @ 0x%Lx/0x%Lx\n", FwCfgSelectorAddress,
373 FwCfgDataAddress));
374 break;
375
376 case PropertyTypeVirtio:
377 ASSERT (Len == 16);
378 //
379 // Create a unique device path for this transport on the fly
380 //
381 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
382 DevicePath = (VIRTIO_TRANSPORT_DEVICE_PATH *)CreateDeviceNode (
383 HARDWARE_DEVICE_PATH,
384 HW_VENDOR_DP,
385 sizeof (VIRTIO_TRANSPORT_DEVICE_PATH));
386 if (DevicePath == NULL) {
387 DEBUG ((EFI_D_ERROR, "%a: Out of memory\n", __FUNCTION__));
388 break;
389 }
390
391 CopyMem (&DevicePath->Vendor.Guid, &gVirtioMmioTransportGuid,
392 sizeof (EFI_GUID));
393 DevicePath->PhysBase = RegBase;
394 SetDevicePathNodeLength (&DevicePath->Vendor,
395 sizeof (*DevicePath) - sizeof (DevicePath->End));
396 SetDevicePathEndNode (&DevicePath->End);
397
398 Handle = NULL;
399 Status = gBS->InstallProtocolInterface (&Handle,
400 &gEfiDevicePathProtocolGuid, EFI_NATIVE_INTERFACE,
401 DevicePath);
402 if (EFI_ERROR (Status)) {
403 DEBUG ((EFI_D_ERROR, "%a: Failed to install the EFI_DEVICE_PATH "
404 "protocol on a new handle (Status == %r)\n",
405 __FUNCTION__, Status));
406 FreePool (DevicePath);
407 break;
408 }
409
410 Status = VirtioMmioInstallDevice (RegBase, Handle);
411 if (EFI_ERROR (Status)) {
412 DEBUG ((EFI_D_ERROR, "%a: Failed to install VirtIO transport @ 0x%Lx "
413 "on handle %p (Status == %r)\n", __FUNCTION__, RegBase,
414 Handle, Status));
415
416 Status = gBS->UninstallProtocolInterface (Handle,
417 &gEfiDevicePathProtocolGuid, DevicePath);
418 ASSERT_EFI_ERROR (Status);
419 FreePool (DevicePath);
420 }
421 break;
422
423 case PropertyTypeGic:
424 ASSERT (Len == 32);
425
426 DistBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
427 CpuBase = fdt64_to_cpu (((UINT64 *)RegProp)[2]);
428 ASSERT (DistBase < MAX_UINT32);
429 ASSERT (CpuBase < MAX_UINT32);
430
431 PcdSet32 (PcdGicDistributorBase, (UINT32)DistBase);
432 PcdSet32 (PcdGicInterruptInterfaceBase, (UINT32)CpuBase);
433
434 DEBUG ((EFI_D_INFO, "Found GIC @ 0x%Lx/0x%Lx\n", DistBase, CpuBase));
435 break;
436
437 case PropertyTypeRtc:
438 ASSERT (Len == 16);
439
440 RegBase = fdt64_to_cpu (((UINT64 *)RegProp)[0]);
441 ASSERT (RegBase < MAX_UINT32);
442
443 PcdSet32 (PcdPL031RtcBase, (UINT32)RegBase);
444
445 DEBUG ((EFI_D_INFO, "Found PL031 RTC @ 0x%Lx\n", RegBase));
446 RtcNode = Node;
447 break;
448
449 case PropertyTypeTimer:
450 //
451 // - interrupts : Interrupt list for secure, non-secure, virtual and
452 // hypervisor timers, in that order.
453 //
454 InterruptProp = fdt_getprop (DeviceTreeBase, Node, "interrupts", &Len);
455 ASSERT (Len == 36 || Len == 48);
456
457 SecIntrNum = fdt32_to_cpu (InterruptProp[0].Number)
458 + (InterruptProp[0].Type ? 16 : 0);
459 IntrNum = fdt32_to_cpu (InterruptProp[1].Number)
460 + (InterruptProp[1].Type ? 16 : 0);
461 VirtIntrNum = fdt32_to_cpu (InterruptProp[2].Number)
462 + (InterruptProp[2].Type ? 16 : 0);
463 HypIntrNum = Len < 48 ? 0 : fdt32_to_cpu (InterruptProp[3].Number)
464 + (InterruptProp[3].Type ? 16 : 0);
465
466 DEBUG ((EFI_D_INFO, "Found Timer interrupts %d, %d, %d, %d\n",
467 SecIntrNum, IntrNum, VirtIntrNum, HypIntrNum));
468
469 PcdSet32 (PcdArmArchTimerSecIntrNum, SecIntrNum);
470 PcdSet32 (PcdArmArchTimerIntrNum, IntrNum);
471 PcdSet32 (PcdArmArchTimerVirtIntrNum, VirtIntrNum);
472 PcdSet32 (PcdArmArchTimerHypIntrNum, HypIntrNum);
473 break;
474
475 case PropertyTypePsci:
476 PsciMethod = fdt_getprop (DeviceTreeBase, Node, "method", &Len);
477
478 if (PsciMethod && AsciiStrnCmp (PsciMethod, "hvc", 3) == 0) {
479 PcdSet32 (PcdArmPsciMethod, 1);
480 } else if (PsciMethod && AsciiStrnCmp (PsciMethod, "smc", 3) == 0) {
481 PcdSet32 (PcdArmPsciMethod, 2);
482 } else {
483 DEBUG ((EFI_D_ERROR, "%a: Unknown PSCI method \"%a\"\n", __FUNCTION__,
484 PsciMethod));
485 }
486 break;
487
488 default:
489 break;
490 }
491 }
492
493 //
494 // UEFI takes ownership of the RTC hardware, and exposes its functionality
495 // through the UEFI Runtime Services GetTime, SetTime, etc. This means we
496 // need to disable it in the device tree to prevent the OS from attaching its
497 // device driver as well.
498 //
499 if ((RtcNode != -1) &&
500 fdt_setprop_string (DeviceTreeBase, RtcNode, "status",
501 "disabled") != 0) {
502 DEBUG ((EFI_D_WARN, "Failed to set PL031 status to 'disabled'\n"));
503 }
504 return EFI_SUCCESS;
505 }