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