1 /** @file
2 *
3 * Copyright (c) 2015, Hisilicon Limited. All rights reserved.
4 * Copyright (c) 2015, Linaro Limited. All rights reserved.
5 *
6 * This program and the accompanying materials
7 * are 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 <Uefi.h>
17 #include <Library/BaseLib.h>
18 #include <libfdt.h>
19 #include <Library/IoLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/UefiBootServicesTableLib.h>
22 #include <Library/FdtUpdateLib.h>
23 #include <Protocol/HisiBoardNicProtocol.h>
24 #include <Library/MemoryAllocationLib.h>
25
26 MAC_ADDRESS gMacAddress[1];
27
28 CHAR8 *EthName[8]=
29 {
30 "ethernet@0","ethernet@1",
31 "ethernet@2","ethernet@3",
32 "ethernet@4","ethernet@5",
33 "ethernet@6","ethernet@7"
34 };
35
36 CHAR8 *MacName[4]=
37 {
38 "ethernet-mac@c7040000",
39 "ethernet-mac@c7044000",
40 "ethernet-mac@c7048000",
41 "ethernet-mac@c704c000"
42 };
43
44 STATIC
45 BOOLEAN
IsMemMapRegion(IN EFI_MEMORY_TYPE MemoryType)46 IsMemMapRegion (
47 IN EFI_MEMORY_TYPE MemoryType
48 )
49 {
50 switch(MemoryType)
51 {
52 case EfiRuntimeServicesCode:
53 case EfiRuntimeServicesData:
54 case EfiConventionalMemory:
55 case EfiACPIReclaimMemory:
56 case EfiACPIMemoryNVS:
57 case EfiLoaderCode:
58 case EfiLoaderData:
59 case EfiBootServicesCode:
60 case EfiBootServicesData:
61 case EfiPalCode:
62 return TRUE;
63 default:
64 return FALSE;
65 }
66 }
67
68 EFI_STATUS
GetMacAddress(UINT32 Port)69 GetMacAddress (UINT32 Port)
70 {
71 EFI_MAC_ADDRESS Mac;
72 EFI_STATUS Status;
73 HISI_BOARD_NIC_PROTOCOL *OemNic = NULL;
74
75 Status = gBS->LocateProtocol(&gHisiBoardNicProtocolGuid, NULL, (VOID **)&OemNic);
76 if(EFI_ERROR(Status))
77 {
78 DEBUG((EFI_D_ERROR, "[%a]:[%dL] LocateProtocol failed %r\n", __FUNCTION__, __LINE__, Status));
79 return Status;
80 }
81
82 Status = OemNic->GetMac(&Mac, Port);
83 if(EFI_ERROR(Status))
84 {
85 DEBUG((EFI_D_ERROR, "[%a]:[%dL] GetMac failed %r\n", __FUNCTION__, __LINE__, Status));
86 return Status;
87 }
88
89 gMacAddress[0].data0=Mac.Addr[0];
90 gMacAddress[0].data1=Mac.Addr[1];
91 gMacAddress[0].data2=Mac.Addr[2];
92 gMacAddress[0].data3=Mac.Addr[3];
93 gMacAddress[0].data4=Mac.Addr[4];
94 gMacAddress[0].data5=Mac.Addr[5];
95 DEBUG((EFI_D_ERROR, "Port%d:0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
96 Port,gMacAddress[0].data0,gMacAddress[0].data1,gMacAddress[0].data2,
97 gMacAddress[0].data3,gMacAddress[0].data4,gMacAddress[0].data5));
98
99 return EFI_SUCCESS;
100 }
101
102 STATIC
103 EFI_STATUS
DelPhyhandleUpdateMacAddress(IN VOID * Fdt)104 DelPhyhandleUpdateMacAddress(IN VOID* Fdt)
105 {
106 UINT8 port;
107 INTN ethernetnode;
108 INTN node;
109 INTN Error;
110 struct fdt_property *m_prop;
111 int m_oldlen;
112 EFI_STATUS Status = EFI_SUCCESS;
113
114 node = fdt_subnode_offset(Fdt, 0, "soc");
115 if (node < 0)
116 {
117 DEBUG ((EFI_D_ERROR, "can not find soc root node\n"));
118 return EFI_INVALID_PARAMETER;
119 }
120 else
121 {
122 for( port=0; port<8; port++ )
123 {
124 (VOID) GetMacAddress(port);
125 ethernetnode=fdt_subnode_offset(Fdt, node,EthName[port]);
126 if (ethernetnode < 0)
127 {
128 DEBUG ((EFI_D_ERROR, "can not find ethernet@ %d node\n",port));
129 }
130 m_prop = fdt_get_property_w(Fdt, ethernetnode, "local-mac-address", &m_oldlen);
131 if(m_prop)
132 {
133 Error = fdt_delprop(Fdt, ethernetnode, "local-mac-address");
134 if (Error)
135 {
136 DEBUG ((EFI_D_ERROR, "ERROR:fdt_delprop() Local-mac-address: %a\n", fdt_strerror (Error)));
137 Status = EFI_INVALID_PARAMETER;
138 }
139 Error = fdt_setprop(Fdt, ethernetnode, "local-mac-address",gMacAddress,sizeof(MAC_ADDRESS));
140 if (Error)
141 {
142 DEBUG ((EFI_D_ERROR, "ERROR:fdt_setprop():local-mac-address %a\n", fdt_strerror (Error)));
143 Status = EFI_INVALID_PARAMETER;
144 }
145 }
146 }
147 }
148 return Status;
149 }
150
UpdateMemoryNode(VOID * Fdt)151 EFI_STATUS UpdateMemoryNode(VOID* Fdt)
152 {
153 INTN Error = 0;
154 EFI_STATUS Status = EFI_SUCCESS;
155 UINT32 Index = 0;
156 UINT32 MemIndex;
157 INTN node;
158 struct fdt_property *m_prop;
159 int m_oldlen;
160 EFI_MEMORY_DESCRIPTOR *MemoryMap;
161 EFI_MEMORY_DESCRIPTOR *MemoryMapPtr;
162 EFI_MEMORY_DESCRIPTOR *MemoryMapPtrCurrent;
163 UINTN MemoryMapSize;
164 UINTN Pages0 = 0;
165 UINTN Pages1 = 0;
166 UINTN MapKey;
167 UINTN DescriptorSize;
168 UINT32 DescriptorVersion;
169 PHY_MEM_REGION *mRegion;
170 UINTN MemoryMapLastEndAddress ;
171 UINTN MemoryMapcontinuousStartAddress ;
172 UINTN MemoryMapCurrentStartAddress;
173 BOOLEAN FindMemoryRegionFlag = FALSE;
174 node = fdt_subnode_offset(Fdt, 0, "memory");
175 if (node < 0)
176 {
177 // Create the memory node
178 node = fdt_add_subnode(Fdt, 0, "memory");
179 if(node < 0)
180 {
181 DEBUG((EFI_D_INFO, "[%a]:[%dL] fdt add subnode error\n", __FUNCTION__, __LINE__));
182 }
183 }
184 //find the memory node property
185 m_prop = fdt_get_property_w(Fdt, node, "memory", &m_oldlen);
186 if(m_prop)
187 Error=fdt_delprop(Fdt, node, "reg");
188 if (Error)
189 {
190 DEBUG ((EFI_D_ERROR, "ERROR:fdt_delprop(): %a\n", fdt_strerror (Error)));
191 Status = EFI_INVALID_PARAMETER;
192 return Status;
193 }
194
195 MemoryMap = NULL;
196 MemoryMapSize = 0;
197 MemIndex = 0;
198
199 Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);
200 if (Status == EFI_BUFFER_TOO_SMALL)
201 {
202 // The UEFI specification advises to allocate more memory for the MemoryMap buffer between successive
203 // calls to GetMemoryMap(), since allocation of the new buffer may potentially increase memory map size.
204 //DEBUG ((EFI_D_ERROR, "MemoryMapsize: 0x%lx\n",MemoryMapSize));
205 Pages0 = EFI_SIZE_TO_PAGES (MemoryMapSize) + 1;
206 MemoryMap = AllocatePages (Pages0);
207 if (MemoryMap == NULL)
208 {
209 Status = EFI_OUT_OF_RESOURCES;
210 return Status;
211 }
212 Status = gBS->GetMemoryMap (&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion);
213 }
214
215 if(MemoryMap == NULL)
216 {
217 Status = EFI_OUT_OF_RESOURCES;
218 //goto EXIT;
219 return Status;
220 }
221
222 mRegion = NULL;
223 Pages1 = EFI_SIZE_TO_PAGES (sizeof(PHY_MEM_REGION) *( MemoryMapSize / DescriptorSize));
224 mRegion = (PHY_MEM_REGION*)AllocatePages(Pages1);
225 if (mRegion == NULL)
226 {
227 Status = EFI_OUT_OF_RESOURCES;
228 return Status;
229 }
230
231 if (!EFI_ERROR(Status))
232 {
233 MemoryMapPtr = MemoryMap;
234 MemoryMapPtrCurrent = MemoryMapPtr;
235 MemoryMapLastEndAddress = 0;
236 MemoryMapcontinuousStartAddress = 0;
237 MemoryMapCurrentStartAddress = 0;
238 for ( Index = 0; Index < (MemoryMapSize / DescriptorSize); Index++)
239 {
240 MemoryMapPtrCurrent = (EFI_MEMORY_DESCRIPTOR*)((UINTN)MemoryMapPtr + Index*DescriptorSize);
241 MemoryMapCurrentStartAddress = (UINTN)MemoryMapPtrCurrent->PhysicalStart;
242
243 if (!IsMemMapRegion ((EFI_MEMORY_TYPE)MemoryMapPtrCurrent->Type))
244 {
245 continue;
246 }
247 else
248 {
249 FindMemoryRegionFlag = TRUE;
250 if(MemoryMapCurrentStartAddress != MemoryMapLastEndAddress)
251 {
252 mRegion[MemIndex].BaseHigh= cpu_to_fdt32(MemoryMapcontinuousStartAddress>>32);
253 mRegion[MemIndex].BaseLow=cpu_to_fdt32(MemoryMapcontinuousStartAddress);
254 mRegion[MemIndex].LengthHigh= cpu_to_fdt32((MemoryMapLastEndAddress-MemoryMapcontinuousStartAddress)>>32);
255 mRegion[MemIndex].LengthLow=cpu_to_fdt32(MemoryMapLastEndAddress-MemoryMapcontinuousStartAddress);
256 MemIndex+=1;
257 MemoryMapcontinuousStartAddress=MemoryMapCurrentStartAddress;
258 }
259 }
260 MemoryMapLastEndAddress = (UINTN)(MemoryMapPtrCurrent->PhysicalStart + MemoryMapPtrCurrent->NumberOfPages * EFI_PAGE_SIZE);
261 }
262 if (FindMemoryRegionFlag)
263 {
264 mRegion[MemIndex].BaseHigh = cpu_to_fdt32(MemoryMapcontinuousStartAddress>>32);
265 mRegion[MemIndex].BaseLow = cpu_to_fdt32(MemoryMapcontinuousStartAddress);
266 mRegion[MemIndex].LengthHigh = cpu_to_fdt32((MemoryMapLastEndAddress-MemoryMapcontinuousStartAddress)>>32);
267 mRegion[MemIndex].LengthLow = cpu_to_fdt32(MemoryMapLastEndAddress-MemoryMapcontinuousStartAddress);
268 }
269 }
270 Error = fdt_setprop(Fdt, node, "reg",mRegion,sizeof(PHY_MEM_REGION) *(MemIndex+1));
271 FreePages (mRegion, Pages1);
272 FreePages (MemoryMap, Pages0);
273 if (Error)
274 {
275 DEBUG ((EFI_D_ERROR, "ERROR:fdt_setprop(): %a\n", fdt_strerror (Error)));
276 Status = EFI_INVALID_PARAMETER;
277 return Status;
278 }
279 return Status;
280 }
281
282 /*
283 * Entry point for fdtupdate lib.
284 */
285
EFIFdtUpdate(UINTN FdtFileAddr)286 EFI_STATUS EFIFdtUpdate(UINTN FdtFileAddr)
287 {
288 INTN Error;
289 VOID* Fdt;
290 UINT32 Size;
291 UINTN NewFdtBlobSize;
292 UINTN NewFdtBlobBase;
293 EFI_STATUS Status = EFI_SUCCESS;
294
295 Error = fdt_check_header ((VOID*)(UINTN)(FdtFileAddr));
296 if (Error != 0)
297 {
298 DEBUG ((EFI_D_ERROR,"ERROR: Device Tree header not valid (%a)\n", fdt_strerror(Error)));
299 return EFI_INVALID_PARAMETER;
300 }
301
302 Size = (UINTN)fdt_totalsize ((VOID*)(UINTN)(FdtFileAddr));
303 NewFdtBlobSize = Size + ADD_FILE_LENGTH;
304 Fdt = (VOID*)(UINTN)FdtFileAddr;
305
306 Status = gBS->AllocatePages (AllocateAnyPages, EfiBootServicesData, EFI_SIZE_TO_PAGES(NewFdtBlobSize), &NewFdtBlobBase);
307 if (EFI_ERROR (Status))
308 {
309 return EFI_OUT_OF_RESOURCES;
310 }
311
312
313 Error = fdt_open_into(Fdt,(VOID*)(UINTN)(NewFdtBlobBase), (NewFdtBlobSize));
314 if (Error) {
315 DEBUG ((EFI_D_ERROR, "ERROR:fdt_open_into(): %a\n", fdt_strerror (Error)));
316 Status = EFI_INVALID_PARAMETER;
317 goto EXIT;
318 }
319
320 Fdt = (VOID*)(UINTN)NewFdtBlobBase;
321
322 Status = DelPhyhandleUpdateMacAddress(Fdt);
323 if (EFI_ERROR (Status))
324 {
325 DEBUG ((EFI_D_ERROR, "DelPhyhandleUpdateMacAddress fail:\n"));
326 Status = EFI_SUCCESS;
327 }
328
329 Status = UpdateMemoryNode(Fdt);
330 if (EFI_ERROR (Status))
331 {
332 goto EXIT;
333 }
334
335 gBS->CopyMem(((VOID*)(UINTN)(FdtFileAddr)),((VOID*)(UINTN)(NewFdtBlobBase)),NewFdtBlobSize);
336
337 EXIT:
338 gBS->FreePages(NewFdtBlobBase,EFI_SIZE_TO_PAGES(NewFdtBlobSize));
339
340 return Status;
341 }
342