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