• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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