1 /*++
2 
3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
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 Module Name:
13 
14   EfiDriverLib.c
15 
16 Abstract:
17 
18   Light weight lib to support EFI drivers.
19 
20 --*/
21 
22 #include "Tiano.h"
23 #include "EfiDriverLib.h"
24 #include EFI_ARCH_PROTOCOL_DEFINITION (StatusCode)
25 
26 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
27 
28 VOID
29 EFIAPI
30 OnStatusCodeInstall (
31   IN EFI_EVENT        Event,
32   IN VOID             *Context
33   );
34 
35 #endif
36 
37 //
38 // Global Interface for Debug Mask Protocol
39 //
40 EFI_DEBUG_MASK_PROTOCOL *gDebugMaskInterface = NULL;
41 
42 EFI_STATUS
EfiInitializeDriverLib(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)43 EfiInitializeDriverLib (
44   IN EFI_HANDLE           ImageHandle,
45   IN EFI_SYSTEM_TABLE     *SystemTable
46   )
47 /*++
48 
49 Routine Description:
50 
51   Intialize Driver Lib if it has not yet been initialized.
52 
53 Arguments:
54 
55   ImageHandle     - Standard EFI Image entry parameter
56 
57   SystemTable     - Standard EFI Image entry parameter
58 
59 Returns:
60 
61   EFI_STATUS always returns EFI_SUCCESS
62 
63 --*/
64 {
65 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
66   VOID *Registration;
67 #endif
68 
69   gST = SystemTable;
70 
71   ASSERT (gST != NULL);
72 
73   gBS = gST->BootServices;
74   gRT = gST->RuntimeServices;
75 
76   ASSERT (gBS != NULL);
77   ASSERT (gRT != NULL);
78 
79   //
80   // Get driver debug mask protocol interface
81   //
82 #ifdef EFI_DEBUG
83   gBS->HandleProtocol (
84         ImageHandle,
85         &gEfiDebugMaskProtocolGuid,
86         (VOID *) &gDebugMaskInterface
87         );
88 #endif
89 
90 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
91   //
92   // Register EFI_STATUS_CODE_PROTOCOL notify function
93   //
94   EfiLibCreateProtocolNotifyEvent (
95     &gEfiStatusCodeRuntimeProtocolGuid,
96     EFI_TPL_CALLBACK,
97     OnStatusCodeInstall,
98     NULL,
99     &Registration
100     );
101 
102 #endif
103 
104   //
105   // Should be at EFI_D_INFO, but lets us know things are running
106   //
107   DEBUG ((EFI_D_INFO, "EfiInitializeDriverLib: Started\n"));
108 
109   return EFI_SUCCESS;
110 }
111 
112 STATIC
113 BOOLEAN
IsIso639LanguageCode(IN CHAR8 * Languages)114 IsIso639LanguageCode (
115   IN CHAR8                *Languages
116   )
117 /*++
118 
119 Routine Description:
120 
121   Tests whether a language code has format of ISO639-2.
122 
123 Arguments:
124 
125   Languages - The language code to be tested.
126 
127 Returns:
128 
129   TRUE      - Language code format is ISO 639-2.
130   FALSE     - Language code format is not ISO 639-2.
131 
132 --*/
133 {
134   UINTN  Index;
135 
136   //
137   // Find out format of Languages
138   //
139   for (Index = 0; Languages[Index] != 0 && Languages[Index] != ';' && Languages[Index] != '-'; Index++);
140   if (Languages[Index] != 0) {
141     //
142     // RFC4646 language code
143     //
144     return FALSE;
145   }
146 
147   //
148   // No ';' and '-', it's either ISO639-2 code (list) or single RFC4646 code
149   //
150   if (Index == 2) {
151     //
152     // Single RFC4646 language code without country code, e.g. "en"
153     //
154     return FALSE;
155   }
156 
157   //
158   // Languages in format of ISO639-2
159   //
160   return TRUE;
161 }
162 
163 BOOLEAN
EfiLibCompareLanguage(IN CHAR8 * Language1,IN CHAR8 * Language2)164 EfiLibCompareLanguage (
165   IN  CHAR8               *Language1,
166   IN  CHAR8               *Language2
167   )
168 /*++
169 
170 Routine Description:
171 
172   Compare the first language instance of two language codes, either could be a
173   single language code or a language code list. This function assume Language1
174   and Language2 has the same language code format, i.e. either ISO639-2 or RFC4646.
175 
176 Arguments:
177 
178   Language1 - The first language code to be tested.
179   Language2 - The second language code to be tested.
180 
181 Returns:
182 
183   TRUE      - Language code match.
184   FALSE     - Language code mismatch.
185 
186 --*/
187 {
188   UINTN Index;
189 
190   //
191   // Compare first two bytes of language tag
192   //
193   if ((Language1[0] != Language2[0]) || (Language1[1] != Language2[1])) {
194     return FALSE;
195   }
196 
197   if (IsIso639LanguageCode (Language1)) {
198     //
199     // ISO639-2 language code, compare the third byte of language tag
200     //
201     return (BOOLEAN) ((Language1[2] == Language2[2]) ? TRUE : FALSE);
202   }
203 
204   //
205   // RFC4646 language code
206   //
207   for (Index = 0; Language1[Index] != 0 && Language1[Index] != ';'; Index++);
208   if ((EfiAsciiStrnCmp (Language1, Language2, Index) == 0) && (Language2[Index] == 0 || Language2[Index] == ';')) {
209     return TRUE;
210   }
211 
212   return FALSE;
213 }
214 
215 STATIC
216 CHAR8 *
NextSupportedLanguage(IN CHAR8 * Languages)217 NextSupportedLanguage (
218   IN CHAR8                *Languages
219   )
220 /*++
221 
222 Routine Description:
223 
224   Step to next language code of a language code list.
225 
226 Arguments:
227 
228   Languages - The language code list to traverse.
229 
230 Returns:
231 
232   Pointer to next language code or NULL terminator if it's the last one.
233 
234 --*/
235 {
236   UINTN    Index;
237 
238   if (IsIso639LanguageCode (Languages)) {
239     //
240     // ISO639-2 language code
241     //
242     return (Languages + 3);
243   }
244 
245   //
246   // Search in RFC4646 language code list
247   //
248   for (Index = 0; Languages[Index] != 0 && Languages[Index] != ';'; Index++);
249   if (Languages[Index] == ';') {
250     Index++;
251   }
252   return (Languages + Index);
253 }
254 
255 EFI_STATUS
EfiLibLookupUnicodeString(IN CHAR8 * Language,IN CHAR8 * SupportedLanguages,IN EFI_UNICODE_STRING_TABLE * UnicodeStringTable,OUT CHAR16 ** UnicodeString)256 EfiLibLookupUnicodeString (
257   IN  CHAR8                     *Language,
258   IN  CHAR8                     *SupportedLanguages,
259   IN  EFI_UNICODE_STRING_TABLE  *UnicodeStringTable,
260   OUT CHAR16                    **UnicodeString
261   )
262 /*++
263 
264 Routine Description:
265 
266   Translate a unicode string to a specified language if supported.
267 
268 Arguments:
269 
270   Language              - The name of language to translate to
271   SupportedLanguages    - Supported languages set
272   UnicodeStringTable    - Pointer of one item in translation dictionary
273   UnicodeString         - The translated string
274 
275 Returns:
276 
277   EFI_INVALID_PARAMETER - Invalid parameter
278   EFI_UNSUPPORTED       - System not supported this language or this string translation
279   EFI_SUCCESS           - String successfully translated
280 
281 --*/
282 {
283   //
284   // Make sure the parameters are valid
285   //
286   if (Language == NULL || UnicodeString == NULL) {
287     return EFI_INVALID_PARAMETER;
288   }
289 
290   //
291   // If there are no supported languages, or the Unicode String Table is empty, then the
292   // Unicode String specified by Language is not supported by this Unicode String Table
293   //
294   if (SupportedLanguages == NULL || UnicodeStringTable == NULL) {
295     return EFI_UNSUPPORTED;
296   }
297 
298   //
299   // Make sure Language is in the set of Supported Languages
300   //
301   while (*SupportedLanguages != 0) {
302     if (EfiLibCompareLanguage (Language, SupportedLanguages)) {
303 
304       //
305       // Search the Unicode String Table for the matching Language specifier
306       //
307       while (UnicodeStringTable->Language != NULL) {
308         if (EfiLibCompareLanguage (Language, UnicodeStringTable->Language)) {
309 
310           //
311           // A matching string was found, so return it
312           //
313           *UnicodeString = UnicodeStringTable->UnicodeString;
314           return EFI_SUCCESS;
315         }
316 
317         UnicodeStringTable++;
318       }
319 
320       return EFI_UNSUPPORTED;
321     }
322 
323     SupportedLanguages = NextSupportedLanguage (SupportedLanguages);
324   }
325 
326   return EFI_UNSUPPORTED;
327 }
328 
329 EFI_STATUS
EfiLibAddUnicodeString(IN CHAR8 * Language,IN CHAR8 * SupportedLanguages,IN OUT EFI_UNICODE_STRING_TABLE ** UnicodeStringTable,IN CHAR16 * UnicodeString)330 EfiLibAddUnicodeString (
331   IN      CHAR8                     *Language,
332   IN      CHAR8                     *SupportedLanguages,
333   IN OUT  EFI_UNICODE_STRING_TABLE  **UnicodeStringTable,
334   IN      CHAR16                    *UnicodeString
335   )
336 /*++
337 
338 Routine Description:
339 
340   Add an translation to the dictionary if this language if supported.
341 
342 Arguments:
343 
344   Language              - The name of language to translate to
345   SupportedLanguages    - Supported languages set
346   UnicodeStringTable    - Translation dictionary
347   UnicodeString         - The corresponding string for the language to be translated to
348 
349 Returns:
350 
351   EFI_INVALID_PARAMETER - Invalid parameter
352   EFI_UNSUPPORTED       - System not supported this language
353   EFI_ALREADY_STARTED   - Already has a translation item of this language
354   EFI_OUT_OF_RESOURCES  - No enough buffer to be allocated
355   EFI_SUCCESS           - String successfully translated
356 
357 --*/
358 {
359   UINTN                     NumberOfEntries;
360   EFI_UNICODE_STRING_TABLE  *OldUnicodeStringTable;
361   EFI_UNICODE_STRING_TABLE  *NewUnicodeStringTable;
362   UINTN                     UnicodeStringLength;
363 
364   //
365   // Make sure the parameter are valid
366   //
367   if (Language == NULL || UnicodeString == NULL || UnicodeStringTable == NULL) {
368     return EFI_INVALID_PARAMETER;
369   }
370 
371   //
372   // If there are no supported languages, then a Unicode String can not be added
373   //
374   if (SupportedLanguages == NULL) {
375     return EFI_UNSUPPORTED;
376   }
377 
378   //
379   // If the Unicode String is empty, then a Unicode String can not be added
380   //
381   if (UnicodeString[0] == 0) {
382     return EFI_INVALID_PARAMETER;
383   }
384 
385   //
386   // Make sure Language is a member of SupportedLanguages
387   //
388   while (*SupportedLanguages != 0) {
389     if (EfiLibCompareLanguage (Language, SupportedLanguages)) {
390 
391       //
392       // Determine the size of the Unicode String Table by looking for a NULL Language entry
393       //
394       NumberOfEntries = 0;
395       if (*UnicodeStringTable != NULL) {
396         OldUnicodeStringTable = *UnicodeStringTable;
397         while (OldUnicodeStringTable->Language != NULL) {
398           if (EfiLibCompareLanguage (Language, OldUnicodeStringTable->Language)) {
399             return EFI_ALREADY_STARTED;
400           }
401 
402           OldUnicodeStringTable++;
403           NumberOfEntries++;
404         }
405       }
406 
407       //
408       // Allocate space for a new Unicode String Table.  It must hold the current number of
409       // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
410       // marker
411       //
412       NewUnicodeStringTable = EfiLibAllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
413       if (NewUnicodeStringTable == NULL) {
414         return EFI_OUT_OF_RESOURCES;
415       }
416 
417       //
418       // If the current Unicode String Table contains any entries, then copy them to the
419       // newly allocated Unicode String Table.
420       //
421       if (*UnicodeStringTable != NULL) {
422         EfiCopyMem (
423           NewUnicodeStringTable,
424           *UnicodeStringTable,
425           NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
426           );
427       }
428 
429       //
430       // Allocate space for a copy of the Language specifier
431       //
432       NewUnicodeStringTable[NumberOfEntries].Language = EfiLibAllocateCopyPool (EfiAsciiStrSize (Language), Language);
433       if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
434         gBS->FreePool (NewUnicodeStringTable);
435         return EFI_OUT_OF_RESOURCES;
436       }
437 
438       //
439       // Compute the length of the Unicode String
440       //
441       for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++)
442         ;
443 
444       //
445       // Allocate space for a copy of the Unicode String
446       //
447       NewUnicodeStringTable[NumberOfEntries].UnicodeString = EfiLibAllocateCopyPool (
448                                                               (UnicodeStringLength + 1) * sizeof (CHAR16),
449                                                               UnicodeString
450                                                               );
451       if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
452         gBS->FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
453         gBS->FreePool (NewUnicodeStringTable);
454         return EFI_OUT_OF_RESOURCES;
455       }
456 
457       //
458       // Mark the end of the Unicode String Table
459       //
460       NewUnicodeStringTable[NumberOfEntries + 1].Language       = NULL;
461       NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString  = NULL;
462 
463       //
464       // Free the old Unicode String Table
465       //
466       if (*UnicodeStringTable != NULL) {
467         gBS->FreePool (*UnicodeStringTable);
468       }
469 
470       //
471       // Point UnicodeStringTable at the newly allocated Unicode String Table
472       //
473       *UnicodeStringTable = NewUnicodeStringTable;
474 
475       return EFI_SUCCESS;
476     }
477 
478     SupportedLanguages = NextSupportedLanguage (SupportedLanguages);
479   }
480 
481   return EFI_UNSUPPORTED;
482 }
483 
484 EFI_STATUS
EfiLibFreeUnicodeStringTable(IN OUT EFI_UNICODE_STRING_TABLE * UnicodeStringTable)485 EfiLibFreeUnicodeStringTable (
486   IN OUT  EFI_UNICODE_STRING_TABLE  *UnicodeStringTable
487   )
488 /*++
489 
490 Routine Description:
491 
492   Free a string table.
493 
494 Arguments:
495 
496   UnicodeStringTable      - The string table to be freed.
497 
498 Returns:
499 
500   EFI_SUCCESS       - The table successfully freed.
501 
502 --*/
503 {
504   UINTN Index;
505 
506   //
507   // If the Unicode String Table is NULL, then it is already freed
508   //
509   if (UnicodeStringTable == NULL) {
510     return EFI_SUCCESS;
511   }
512 
513   //
514   // Loop through the Unicode String Table until we reach the end of table marker
515   //
516   for (Index = 0; UnicodeStringTable[Index].Language != NULL; Index++) {
517 
518     //
519     // Free the Language string from the Unicode String Table
520     //
521     gBS->FreePool (UnicodeStringTable[Index].Language);
522 
523     //
524     // Free the Unicode String from the Unicode String Table
525     //
526     if (UnicodeStringTable[Index].UnicodeString != NULL) {
527       gBS->FreePool (UnicodeStringTable[Index].UnicodeString);
528     }
529   }
530 
531   //
532   // Free the Unicode String Table itself
533   //
534   gBS->FreePool (UnicodeStringTable);
535 
536   return EFI_SUCCESS;
537 }
538