1 /*++
2 
3 Copyright (c) 2006  - 2014, Intel Corporation. All rights reserved.<BR>
4 
5 
6   This program and the accompanying materials are licensed and made available under
7 
8   the terms and conditions of the BSD License that accompanies this distribution.
9 
10   The full text of the license may be found at
11 
12   http://opensource.org/licenses/bsd-license.php.
13 
14 
15 
16   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17 
18   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 
20 
21 
22 
23 
24 Module Name:
25 
26   MiscMemoryDeviceFunction.c
27 
28 Abstract:
29 
30    Memory Device
31    Misc. subclass type 17.
32    SMBIOS type 17.
33 
34 --*/
35 
36 
37 #include "CommonHeader.h"
38 #include "MiscSubclassDriver.h"
39 #include <Protocol/DataHub.h>
40 #include <Guid/DataHubRecords.h>
41 #include <Protocol/MemInfo.h>
42 
43 
44 #define FREQ_800           0x00
45 #define FREQ_1066          0x01
46 #define FREQ_1333          0x02
47 #define FREQ_1600          0x03
48 
49 #define MAX_SOCKETS  2
50 #define EfiMemoryTypeDdr3  0x18
51 
52 enum {
53     DDRType_DDR3 = 0,
54     DDRType_DDR3L = 1,
55     DDRType_DDR3U = 2,
56     DDRType_DDR3All = 3,
57     DDRType_LPDDR2 = 4,
58     DDRType_LPDDR3 = 5,
59     DDRType_DDR4 = 6
60 };
61 
62 
63 typedef struct {
64   EFI_PHYSICAL_ADDRESS        MemoryArrayStartAddress;
65   EFI_PHYSICAL_ADDRESS        MemoryArrayEndAddress;
66   EFI_INTER_LINK_DATA         PhysicalMemoryArrayLink;
67   UINT16                      MemoryArrayPartitionWidth;
68 } EFI_MEMORY_ARRAY_START_ADDRESS;
69 
70 /**
71   This function makes boot time changes to the contents of the
72   MiscBiosVendor (Type 0).
GetType16Hndl(IN EFI_SMBIOS_PROTOCOL * Smbios,OUT EFI_SMBIOS_HANDLE * Handle)73 
74   @param  RecordData                 Pointer to copy of RecordData from the Data Table.
75 
76   @retval EFI_SUCCESS                All parameters were valid.
77   @retval EFI_UNSUPPORTED            Unexpected RecordType value.
78   @retval EFI_INVALID_PARAMETER      Invalid parameter was found.
79 
80 **/
81 VOID
82 GetType16Hndl (
83   IN  EFI_SMBIOS_PROTOCOL      *Smbios,
84   OUT  EFI_SMBIOS_HANDLE       *Handle
85   )
86 {
87   EFI_STATUS                 Status;
88   EFI_SMBIOS_TYPE            RecordType;
89   EFI_SMBIOS_TABLE_HEADER    *Buffer;
90 
91   *Handle = 0;
92    RecordType = EFI_SMBIOS_TYPE_PHYSICAL_MEMORY_ARRAY;
93 
94     Status = Smbios->GetNext (
95                        Smbios,
96                        Handle,
97                        &RecordType,
98                        &Buffer,
99                        NULL
100                        );
101     if (!EFI_ERROR(Status)) {
102         return;
103       }
104   *Handle = 0xFFFF;
105 }
106 
107 MISC_SMBIOS_TABLE_FUNCTION( MiscMemoryDevice )
108 {
109     CHAR8                           *OptionalStrStart;
110     UINTN                           MemDeviceStrLen;
111     UINTN                           MemBankLocatorStrLen;
112     UINTN                           MemManufacturerStrLen;
113     UINTN                           MemSerialNumberStrLen;
114     UINTN                           MemAssetTagStrLen;
115     UINTN                           MemPartNumberStrLen;
116     CHAR16                          *MemDevice;
117     CHAR16                          *MemBankLocator;
118     CHAR16                          *MemManufacturer;
119     CHAR16                          *MemSerialNumber;
120     CHAR16                          *MemAssetTag;
121     CHAR16                          *MemPartNumber;
122     EFI_STATUS                      Status;
123     STRING_REF                      TokenToGet;
124     SMBIOS_TABLE_TYPE17             *SmbiosRecord;
125     EFI_SMBIOS_HANDLE               SmbiosHandle;
126     EFI_MEMORY_ARRAY_LINK_DATA      *ForType17InputData;
127     UINT16                          DdrFreq=0;
128     UINT16                          Type16Handle=0;
129     MEM_INFO_PROTOCOL               *MemInfoHob;
130     UINT8                           MemoryType;
131 
132     UINT8                           Dimm;
133     UINT8                           NumSlots;
134     STRING_REF                      DevLocator[] = {
135       STRING_TOKEN(STR_MISC_MEM_DEV_LOCATOR0), STRING_TOKEN(STR_MISC_MEM_DEV_LOCATOR1)
136     };
137     STRING_REF                      BankLocator[] = {
138       STRING_TOKEN(STR_MISC_MEM_BANK_LOCATOR0), STRING_TOKEN(STR_MISC_MEM_BANK_LOCATOR1)
139     };
140 
141     //
142     // First check for invalid parameters.
143     //
144     if (RecordData == NULL) {
145         return EFI_INVALID_PARAMETER;
146     }
147     ForType17InputData        = (EFI_MEMORY_ARRAY_LINK_DATA *)RecordData;
148 
149     //
150     // Get Memory size parameters for each rank from the chipset registers
151     //
152     Status = gBS->LocateProtocol (
153                     &gMemInfoProtocolGuid,
154                     NULL,
155                     (void **)&MemInfoHob
156                     );
157     ASSERT_EFI_ERROR (Status);
158 
159     NumSlots = (UINT8)(MAX_SOCKETS);
160 
161     //
162     // Memory Freq
163     //
164     switch (MemInfoHob->MemInfoData.ddrFreq){
165         case FREQ_800:
166           DdrFreq = 800;
167           break;
168         case FREQ_1066:
169           DdrFreq = 1066;
170           break;
171         case FREQ_1333:
172           DdrFreq = 1333;
173           break;
174         case FREQ_1600:
175           DdrFreq = 1600;
176           break;
177         default:
178           DdrFreq = 0;
179           break;
180     }
181 
182     //
183     // Memory Type
184     //
185     switch  (MemInfoHob->MemInfoData.ddrType) {
186         case DDRType_LPDDR2:
187           MemoryType  = EfiMemoryTypeDdr2;
188           break;
189         case DDRType_DDR3:
190         case DDRType_DDR3L:
191         case DDRType_DDR3U:
192         case DDRType_LPDDR3:
193           MemoryType = EfiMemoryTypeDdr3;
194           break;
195         default:
196           MemoryType = EfiMemoryTypeUnknown;
197           break;
198     }
199 
200     for (Dimm = 0; Dimm < NumSlots; Dimm++) {
201     //
202     // Memory Device Locator
203     //
204     TokenToGet = DevLocator[Dimm];
205     MemDevice = SmbiosMiscGetString (TokenToGet);
206     MemDeviceStrLen = StrLen(MemDevice);
207     if (MemDeviceStrLen > SMBIOS_STRING_MAX_LENGTH) {
208       return EFI_UNSUPPORTED;
209     }
210 
211     TokenToGet = DevLocator[Dimm];
212     MemDevice = SmbiosMiscGetString (TokenToGet);
213     MemDeviceStrLen = StrLen(MemDevice);
214     if (MemDeviceStrLen > SMBIOS_STRING_MAX_LENGTH) {
215       return EFI_UNSUPPORTED;
216     }
217 
218     //
219     // Memory Bank Locator
220     //
221     TokenToGet = BankLocator[Dimm];
222     MemBankLocator = SmbiosMiscGetString (TokenToGet);
223     MemBankLocatorStrLen = StrLen(MemBankLocator);
224     if (MemBankLocatorStrLen > SMBIOS_STRING_MAX_LENGTH) {
225       return EFI_UNSUPPORTED;
226     }
227 
228     //
229     // Memory Manufacturer
230     //
231     TokenToGet = STRING_TOKEN (STR_MISC_MEM_MANUFACTURER);
232     MemManufacturer = SmbiosMiscGetString (TokenToGet);
233     MemManufacturerStrLen = StrLen(MemManufacturer);
234     if (MemManufacturerStrLen > SMBIOS_STRING_MAX_LENGTH) {
235       return EFI_UNSUPPORTED;
236     }
237 
238     //
239     // Memory Serial Number
240     //
241     TokenToGet = STRING_TOKEN (STR_MISC_MEM_SERIAL_NO);
242     MemSerialNumber = SmbiosMiscGetString (TokenToGet);
243     MemSerialNumberStrLen = StrLen(MemSerialNumber);
244     if (MemSerialNumberStrLen > SMBIOS_STRING_MAX_LENGTH) {
245       return EFI_UNSUPPORTED;
246     }
247 
248     //
249     // Memory Asset Tag Number
250     //
251     TokenToGet = STRING_TOKEN (STR_MISC_MEM_ASSET_TAG);
252     MemAssetTag = SmbiosMiscGetString (TokenToGet);
253     MemAssetTagStrLen = StrLen(MemAssetTag);
254     if (MemAssetTagStrLen > SMBIOS_STRING_MAX_LENGTH) {
255       return EFI_UNSUPPORTED;
256     }
257 
258     //
259     // Memory Part Number
260     //
261     TokenToGet = STRING_TOKEN (STR_MISC_MEM_PART_NUMBER);
262     MemPartNumber = SmbiosMiscGetString (TokenToGet);
263     MemPartNumberStrLen = StrLen(MemPartNumber);
264     if (MemPartNumberStrLen > SMBIOS_STRING_MAX_LENGTH) {
265       return EFI_UNSUPPORTED;
266     }
267 
268     //
269     // Two zeros following the last string.
270     //
271     SmbiosRecord = AllocatePool(sizeof (SMBIOS_TABLE_TYPE17) + MemDeviceStrLen + 1 + MemBankLocatorStrLen + 1 + MemManufacturerStrLen + 1 + MemSerialNumberStrLen + 1 + MemAssetTagStrLen+1 + MemPartNumberStrLen + 1 + 1);
272     ZeroMem(SmbiosRecord, sizeof (SMBIOS_TABLE_TYPE17) +  MemDeviceStrLen + 1 + MemBankLocatorStrLen + 1 + MemManufacturerStrLen + 1 + MemSerialNumberStrLen + 1 + MemAssetTagStrLen+1 + MemPartNumberStrLen + 1 + 1);
273 
274     SmbiosRecord->Hdr.Type = EFI_SMBIOS_TYPE_MEMORY_DEVICE;
275     SmbiosRecord->Hdr.Length = sizeof (SMBIOS_TABLE_TYPE17);
276 
277     //
278     // Make handle chosen by smbios protocol.add automatically.
279     //
280     SmbiosRecord->Hdr.Handle = 0;
281 
282     //
283     // Memory Array Handle will be the 3rd optional string following the formatted structure.
284     //
285     GetType16Hndl( Smbios, &Type16Handle);
286     SmbiosRecord->MemoryArrayHandle = Type16Handle;
287 
288     //
289     // Memory Size
290     //
291     if ((MemInfoHob->MemInfoData.dimmSize[Dimm])!=0){
292     SmbiosRecord->TotalWidth = 32;
293     SmbiosRecord->DataWidth = 32;
294     SmbiosRecord->Size = MemInfoHob->MemInfoData.dimmSize[Dimm];
295     SmbiosRecord->Speed = DdrFreq;
296     SmbiosRecord->ConfiguredMemoryClockSpeed = DdrFreq;
297     SmbiosRecord->FormFactor = EfiMemoryFormFactorDimm;
298     }
299 
300     SmbiosRecord->DeviceSet =(UINT8) ForType17InputData->MemoryDeviceSet;
301     SmbiosRecord->DeviceLocator= 1;
302     SmbiosRecord->BankLocator = 2;
303 
304 
305     SmbiosRecord->Manufacturer = 3;
306     SmbiosRecord->SerialNumber= 4;
307     SmbiosRecord->AssetTag= 5;
308     SmbiosRecord->PartNumber= 6;
309     SmbiosRecord->Attributes = (UINT8) ForType17InputData->MemoryState;
310     SmbiosRecord->MemoryType = MemoryType;
311 
312     OptionalStrStart = (CHAR8 *)(SmbiosRecord + 1);
313     UnicodeStrToAsciiStr(MemDevice, OptionalStrStart);
314     UnicodeStrToAsciiStr(MemBankLocator, OptionalStrStart + MemDeviceStrLen + 1);
315     UnicodeStrToAsciiStr(MemManufacturer, OptionalStrStart + MemDeviceStrLen + 1 + MemBankLocatorStrLen + 1);
316     UnicodeStrToAsciiStr(MemSerialNumber, OptionalStrStart + MemDeviceStrLen + 1 + MemBankLocatorStrLen + 1 + MemManufacturerStrLen + 1);
317     UnicodeStrToAsciiStr(MemAssetTag, OptionalStrStart + MemDeviceStrLen + 1 + MemBankLocatorStrLen + 1 + MemManufacturerStrLen + 1 + MemSerialNumberStrLen + 1);
318     UnicodeStrToAsciiStr(MemPartNumber, OptionalStrStart + MemDeviceStrLen + 1 + MemBankLocatorStrLen + 1 + MemManufacturerStrLen + 1 + MemSerialNumberStrLen + 1+ MemAssetTagStrLen+1 );
319 
320     //
321     // Now we have got the full smbios record, call smbios protocol to add this record.
322     //
323     SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
324     Status = Smbios-> Add(
325                         Smbios,
326                         NULL,
327                         &SmbiosHandle,
328                         (EFI_SMBIOS_TABLE_HEADER *) SmbiosRecord
329                         );
330     FreePool(SmbiosRecord);
331     }
332     return Status;
333 }
334