1 /** @file
2 Copyright (c) 2016, Linaro, Ltd. All rights reserved.<BR>
3
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 **/
13
14 #include <PiDxe.h>
15
16 #include <Guid/NonDiscoverableDevice.h>
17
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/DevicePathLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/NonDiscoverableDeviceRegistrationLib.h>
23 #include <Library/UefiBootServicesTableLib.h>
24
25 #include <Protocol/DevicePath.h>
26 #include <Protocol/NonDiscoverableDevice.h>
27
28 /**
29 Get Guid form the type of non-discoverable device.
30
31 @param[in] Type The type of non-discoverable device.
32
33 @retval Return the Guid.
34
35 **/
36 STATIC
37 CONST EFI_GUID *
GetGuidFromType(IN NON_DISCOVERABLE_DEVICE_TYPE Type)38 GetGuidFromType (
39 IN NON_DISCOVERABLE_DEVICE_TYPE Type
40 )
41 {
42 switch (Type) {
43 case NonDiscoverableDeviceTypeAhci:
44 return &gEdkiiNonDiscoverableAhciDeviceGuid;
45
46 case NonDiscoverableDeviceTypeAmba:
47 return &gEdkiiNonDiscoverableAmbaDeviceGuid;
48
49 case NonDiscoverableDeviceTypeEhci:
50 return &gEdkiiNonDiscoverableEhciDeviceGuid;
51
52 case NonDiscoverableDeviceTypeNvme:
53 return &gEdkiiNonDiscoverableNvmeDeviceGuid;
54
55 case NonDiscoverableDeviceTypeOhci:
56 return &gEdkiiNonDiscoverableOhciDeviceGuid;
57
58 case NonDiscoverableDeviceTypeSdhci:
59 return &gEdkiiNonDiscoverableSdhciDeviceGuid;
60
61 case NonDiscoverableDeviceTypeUfs:
62 return &gEdkiiNonDiscoverableUfsDeviceGuid;
63
64 case NonDiscoverableDeviceTypeUhci:
65 return &gEdkiiNonDiscoverableUhciDeviceGuid;
66
67 case NonDiscoverableDeviceTypeXhci:
68 return &gEdkiiNonDiscoverableXhciDeviceGuid;
69
70 default:
71 return NULL;
72 }
73 }
74
75 #pragma pack (1)
76 typedef struct {
77 VENDOR_DEVICE_PATH Vendor;
78 UINT64 BaseAddress;
79 UINT8 ResourceType;
80 EFI_DEVICE_PATH_PROTOCOL End;
81 } NON_DISCOVERABLE_DEVICE_PATH;
82 #pragma pack ()
83
84 /**
85 Register a non-discoverable MMIO device.
86
87 @param[in] Type The type of non-discoverable device
88 @param[in] DmaType Whether the device is DMA coherent
89 @param[in] InitFunc Initialization routine to be invoked when
90 the device is enabled
91 @param[in,out] Handle The handle onto which to install the
92 non-discoverable device protocol.
93 If Handle is NULL or *Handle is NULL, a
94 new handle will be allocated.
95 @param[in] NumMmioResources The number of UINTN base/size pairs that
96 follow, each describing an MMIO region
97 owned by the device
98 @param[in] ... The variable argument list which contains the
99 info about MmioResources.
100
101 @retval EFI_SUCCESS The registration succeeded.
102 @retval EFI_INVALID_PARAMETER An invalid argument was given
103 @retval Other The registration failed.
104
105 **/
106 EFI_STATUS
107 EFIAPI
RegisterNonDiscoverableMmioDevice(IN NON_DISCOVERABLE_DEVICE_TYPE Type,IN NON_DISCOVERABLE_DEVICE_DMA_TYPE DmaType,IN NON_DISCOVERABLE_DEVICE_INIT InitFunc,IN OUT EFI_HANDLE * Handle OPTIONAL,IN UINTN NumMmioResources,...)108 RegisterNonDiscoverableMmioDevice (
109 IN NON_DISCOVERABLE_DEVICE_TYPE Type,
110 IN NON_DISCOVERABLE_DEVICE_DMA_TYPE DmaType,
111 IN NON_DISCOVERABLE_DEVICE_INIT InitFunc,
112 IN OUT EFI_HANDLE *Handle OPTIONAL,
113 IN UINTN NumMmioResources,
114 ...
115 )
116 {
117 NON_DISCOVERABLE_DEVICE *Device;
118 NON_DISCOVERABLE_DEVICE_PATH *DevicePath;
119 EFI_HANDLE LocalHandle;
120 EFI_STATUS Status;
121 UINTN AllocSize;
122 UINTN Index;
123 VA_LIST Args;
124 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Desc;
125 EFI_ACPI_END_TAG_DESCRIPTOR *End;
126 UINTN Base, Size;
127
128 if (Type >= NonDiscoverableDeviceTypeMax ||
129 DmaType >= NonDiscoverableDeviceDmaTypeMax ||
130 NumMmioResources == 0) {
131 return EFI_INVALID_PARAMETER;
132 }
133
134 if (Handle == NULL) {
135 Handle = &LocalHandle;
136 LocalHandle = NULL;
137 }
138
139 AllocSize = sizeof *Device +
140 NumMmioResources * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) +
141 sizeof (EFI_ACPI_END_TAG_DESCRIPTOR);
142 Device = (NON_DISCOVERABLE_DEVICE *)AllocateZeroPool (AllocSize);
143 if (Device == NULL) {
144 return EFI_OUT_OF_RESOURCES;
145 }
146
147 Device->Type = GetGuidFromType (Type);
148 ASSERT (Device->Type != NULL);
149
150 Device->DmaType = DmaType;
151 Device->Initialize = InitFunc;
152 Device->Resources = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)(Device + 1);
153
154 VA_START (Args, NumMmioResources);
155 for (Index = 0; Index < NumMmioResources; Index++) {
156 Desc = &Device->Resources [Index];
157 Base = VA_ARG (Args, UINTN);
158 Size = VA_ARG (Args, UINTN);
159
160 Desc->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
161 Desc->Len = sizeof *Desc - 3;
162 Desc->AddrRangeMin = Base;
163 Desc->AddrLen = Size;
164 Desc->AddrRangeMax = Base + Size - 1;
165 Desc->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
166 Desc->AddrSpaceGranularity = (Base + Size > SIZE_4GB) ? 64 : 32;
167 Desc->AddrTranslationOffset = 0;
168 }
169 VA_END (Args);
170
171 End = (EFI_ACPI_END_TAG_DESCRIPTOR *)&Device->Resources [NumMmioResources];
172
173 End->Desc = ACPI_END_TAG_DESCRIPTOR;
174 End->Checksum = 0;
175
176 DevicePath = (NON_DISCOVERABLE_DEVICE_PATH *)CreateDeviceNode (
177 HARDWARE_DEVICE_PATH,
178 HW_VENDOR_DP,
179 sizeof (*DevicePath));
180 if (DevicePath == NULL) {
181 Status = EFI_OUT_OF_RESOURCES;
182 goto FreeDevice;
183 }
184
185 CopyGuid (&DevicePath->Vendor.Guid, &gEdkiiNonDiscoverableDeviceProtocolGuid);
186
187 //
188 // Use the base address and type of the first region to
189 // make the device path unique
190 //
191 DevicePath->BaseAddress = Device->Resources [0].AddrRangeMin;
192 DevicePath->ResourceType = Device->Resources [0].ResType;
193
194 SetDevicePathNodeLength (&DevicePath->Vendor,
195 sizeof (*DevicePath) - sizeof (DevicePath->End));
196 SetDevicePathEndNode (&DevicePath->End);
197
198 Status = gBS->InstallMultipleProtocolInterfaces (Handle,
199 &gEdkiiNonDiscoverableDeviceProtocolGuid, Device,
200 &gEfiDevicePathProtocolGuid, DevicePath,
201 NULL);
202 if (EFI_ERROR (Status)) {
203 goto FreeDevicePath;
204 }
205 return EFI_SUCCESS;
206
207 FreeDevicePath:
208 FreePool (DevicePath);
209
210 FreeDevice:
211 FreePool (Device);
212
213 return Status;
214 }
215