Coverage Report

Created: 2025-12-05 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/edk2/MdePkg/Library/UefiLib/UefiLib.c
Line
Count
Source
1
/** @file
2
  The UEFI Library provides functions and macros that simplify the development of
3
  UEFI Drivers and UEFI Applications.  These functions and macros help manage EFI
4
  events, build simple locks utilizing EFI Task Priority Levels (TPLs), install
5
  EFI Driver Model related protocols, manage Unicode string tables for UEFI Drivers,
6
  and print messages on the console output and standard error devices.
7
8
  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
9
  SPDX-License-Identifier: BSD-2-Clause-Patent
10
11
**/
12
13
#include "UefiLibInternal.h"
14
15
/**
16
  Empty constructor function that is required to resolve dependencies between
17
  libraries.
18
19
    ** DO NOT REMOVE **
20
21
  @param  ImageHandle   The firmware allocated handle for the EFI image.
22
  @param  SystemTable   A pointer to the EFI System Table.
23
24
  @retval EFI_SUCCESS   The constructor executed correctly.
25
26
**/
27
EFI_STATUS
28
EFIAPI
29
UefiLibConstructor (
30
  IN EFI_HANDLE        ImageHandle,
31
  IN EFI_SYSTEM_TABLE  *SystemTable
32
  )
33
0
{
34
0
  return EFI_SUCCESS;
35
0
}
36
37
/**
38
  Compare whether two names of languages are identical.
39
40
  @param  Language1 Name of language 1.
41
  @param  Language2 Name of language 2.
42
43
  @retval TRUE      Language 1 and language 2 are the same.
44
  @retval FALSE     Language 1 and language 2 are not the same.
45
46
**/
47
BOOLEAN
48
CompareIso639LanguageCode (
49
  IN CONST CHAR8  *Language1,
50
  IN CONST CHAR8  *Language2
51
  )
52
0
{
53
0
  UINT32  Name1;
54
0
  UINT32  Name2;
55
56
0
  Name1 = ReadUnaligned24 ((CONST UINT32 *)Language1);
57
0
  Name2 = ReadUnaligned24 ((CONST UINT32 *)Language2);
58
59
0
  return (BOOLEAN)(Name1 == Name2);
60
0
}
61
62
/**
63
  Retrieves a pointer to the system configuration table from the EFI System Table
64
  based on a specified GUID.
65
66
  This function searches the list of configuration tables stored in the EFI System Table
67
  for a table with a GUID that matches TableGuid.  If a match is found, then a pointer to
68
  the configuration table is returned in Table., and EFI_SUCCESS is returned. If a matching GUID
69
  is not found, then EFI_NOT_FOUND is returned.
70
  If TableGuid is NULL, then ASSERT().
71
  If Table is NULL, then ASSERT().
72
73
  @param  TableGuid       The pointer to table's GUID type.
74
  @param  Table           The pointer to the table associated with TableGuid in the EFI System Table.
75
76
  @retval EFI_SUCCESS     A configuration table matching TableGuid was found.
77
  @retval EFI_NOT_FOUND   A configuration table matching TableGuid could not be found.
78
79
**/
80
EFI_STATUS
81
EFIAPI
82
EfiGetSystemConfigurationTable (
83
  IN  EFI_GUID  *TableGuid,
84
  OUT VOID      **Table
85
  )
86
0
{
87
0
  EFI_SYSTEM_TABLE  *SystemTable;
88
0
  UINTN             Index;
89
90
0
  ASSERT (TableGuid != NULL);
91
0
  ASSERT (Table != NULL);
92
93
0
  SystemTable = gST;
94
0
  *Table      = NULL;
95
0
  for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) {
96
0
    if (CompareGuid (TableGuid, &(SystemTable->ConfigurationTable[Index].VendorGuid))) {
97
0
      *Table = SystemTable->ConfigurationTable[Index].VendorTable;
98
0
      return EFI_SUCCESS;
99
0
    }
100
0
  }
101
102
0
  return EFI_NOT_FOUND;
103
0
}
104
105
/**
106
  Creates and returns a notification event and registers that event with all the protocol
107
  instances specified by ProtocolGuid.
108
109
  This function causes the notification function to be executed for every protocol of type
110
  ProtocolGuid instance that exists in the system when this function is invoked. If there are
111
  no instances of ProtocolGuid in the handle database at the time this function is invoked,
112
  then the notification function is still executed one time. In addition, every time a protocol
113
  of type ProtocolGuid instance is installed or reinstalled, the notification function is also
114
  executed. This function returns the notification event that was created.
115
  If ProtocolGuid is NULL, then ASSERT().
116
  If NotifyTpl is not a legal TPL value, then ASSERT().
117
  If NotifyFunction is NULL, then ASSERT().
118
  If Registration is NULL, then ASSERT().
119
120
121
  @param  ProtocolGuid    Supplies GUID of the protocol upon whose installation the event is fired.
122
  @param  NotifyTpl       Supplies the task priority level of the event notifications.
123
  @param  NotifyFunction  Supplies the function to notify when the event is signaled.
124
  @param  NotifyContext   The context parameter to pass to NotifyFunction.
125
  @param  Registration    A pointer to a memory location to receive the registration value.
126
                          This value is passed to LocateHandle() to obtain new handles that
127
                          have been added that support the ProtocolGuid-specified protocol.
128
129
  @return The notification event that was created.
130
131
**/
132
EFI_EVENT
133
EFIAPI
134
EfiCreateProtocolNotifyEvent (
135
  IN  EFI_GUID          *ProtocolGuid,
136
  IN  EFI_TPL           NotifyTpl,
137
  IN  EFI_EVENT_NOTIFY  NotifyFunction,
138
  IN  VOID              *NotifyContext   OPTIONAL,
139
  OUT VOID              **Registration
140
  )
141
0
{
142
0
  EFI_STATUS  Status;
143
0
  EFI_EVENT   Event;
144
145
0
  ASSERT (ProtocolGuid != NULL);
146
0
  ASSERT (NotifyFunction != NULL);
147
0
  ASSERT (Registration != NULL);
148
149
  //
150
  // Create the event
151
  //
152
153
0
  Status = gBS->CreateEvent (
154
0
                  EVT_NOTIFY_SIGNAL,
155
0
                  NotifyTpl,
156
0
                  NotifyFunction,
157
0
                  NotifyContext,
158
0
                  &Event
159
0
                  );
160
0
  ASSERT_EFI_ERROR (Status);
161
162
  //
163
  // Register for protocol notifications on this event
164
  //
165
166
0
  Status = gBS->RegisterProtocolNotify (
167
0
                  ProtocolGuid,
168
0
                  Event,
169
0
                  Registration
170
0
                  );
171
172
0
  ASSERT_EFI_ERROR (Status);
173
174
  //
175
  // Kick the event so we will perform an initial pass of
176
  // current installed drivers
177
  //
178
179
0
  gBS->SignalEvent (Event);
180
0
  return Event;
181
0
}
182
183
/**
184
  Creates a named event that can be signaled with EfiNamedEventSignal().
185
186
  This function creates an event using NotifyTpl, NoifyFunction, and NotifyContext.
187
  This event is signaled with EfiNamedEventSignal(). This provides the ability for one or more
188
  listeners on the same event named by the GUID specified by Name.
189
  If Name is NULL, then ASSERT().
190
  If NotifyTpl is not a legal TPL value, then ASSERT().
191
  If NotifyFunction is NULL, then ASSERT().
192
193
  @param  Name                  Supplies the GUID name of the event.
194
  @param  NotifyTpl             Supplies the task priority level of the event notifications.
195
  @param  NotifyFunction        Supplies the function to notify when the event is signaled.
196
  @param  NotifyContext         The context parameter to pass to NotifyFunction.
197
  @param  Registration          A pointer to a memory location to receive the registration value.
198
199
  @retval EFI_SUCCESS           A named event was created.
200
  @retval EFI_OUT_OF_RESOURCES  There are not enough resource to create the named event.
201
202
**/
203
EFI_STATUS
204
EFIAPI
205
EfiNamedEventListen (
206
  IN CONST EFI_GUID    *Name,
207
  IN EFI_TPL           NotifyTpl,
208
  IN EFI_EVENT_NOTIFY  NotifyFunction,
209
  IN CONST VOID        *NotifyContext   OPTIONAL,
210
  OUT VOID             *Registration OPTIONAL
211
  )
212
0
{
213
0
  EFI_STATUS  Status;
214
0
  EFI_EVENT   Event;
215
0
  VOID        *RegistrationLocal;
216
217
0
  ASSERT (Name != NULL);
218
0
  ASSERT (NotifyFunction != NULL);
219
0
  ASSERT (NotifyTpl <= TPL_HIGH_LEVEL);
220
221
  //
222
  // Create event
223
  //
224
0
  Status = gBS->CreateEvent (
225
0
                  EVT_NOTIFY_SIGNAL,
226
0
                  NotifyTpl,
227
0
                  NotifyFunction,
228
0
                  (VOID *)NotifyContext,
229
0
                  &Event
230
0
                  );
231
0
  ASSERT_EFI_ERROR (Status);
232
233
  //
234
  // The Registration is not optional to RegisterProtocolNotify().
235
  // To make it optional to EfiNamedEventListen(), may need to substitute with a local.
236
  //
237
0
  if (Registration != NULL) {
238
0
    RegistrationLocal = Registration;
239
0
  } else {
240
0
    RegistrationLocal = &RegistrationLocal;
241
0
  }
242
243
  //
244
  // Register for an installation of protocol interface
245
  //
246
247
0
  Status = gBS->RegisterProtocolNotify (
248
0
                  (EFI_GUID *)Name,
249
0
                  Event,
250
0
                  RegistrationLocal
251
0
                  );
252
0
  ASSERT_EFI_ERROR (Status);
253
254
0
  return Status;
255
0
}
256
257
/**
258
  Signals a named event created with EfiNamedEventListen().
259
260
  This function signals the named event specified by Name. The named event must have been
261
  created with EfiNamedEventListen().
262
  If Name is NULL, then ASSERT().
263
264
  @param  Name                  Supplies the GUID name of the event.
265
266
  @retval EFI_SUCCESS           A named event was signaled.
267
  @retval EFI_OUT_OF_RESOURCES  There are not enough resource to signal the named event.
268
269
**/
270
EFI_STATUS
271
EFIAPI
272
EfiNamedEventSignal (
273
  IN CONST EFI_GUID  *Name
274
  )
275
0
{
276
0
  EFI_STATUS  Status;
277
0
  EFI_HANDLE  Handle;
278
279
0
  ASSERT (Name != NULL);
280
281
0
  Handle = NULL;
282
0
  Status = gBS->InstallProtocolInterface (
283
0
                  &Handle,
284
0
                  (EFI_GUID *)Name,
285
0
                  EFI_NATIVE_INTERFACE,
286
0
                  NULL
287
0
                  );
288
0
  ASSERT_EFI_ERROR (Status);
289
290
0
  Status = gBS->UninstallProtocolInterface (
291
0
                  Handle,
292
0
                  (EFI_GUID *)Name,
293
0
                  NULL
294
0
                  );
295
0
  ASSERT_EFI_ERROR (Status);
296
297
0
  return Status;
298
0
}
299
300
/**
301
  Signals an event group by placing a new event in the group temporarily and
302
  signaling it.
303
304
  @param[in] EventGroup          Supplies the unique identifier of the event
305
                                 group to signal.
306
307
  @retval EFI_SUCCESS            The event group was signaled successfully.
308
  @retval EFI_INVALID_PARAMETER  EventGroup is NULL.
309
  @return                        Error codes that report problems about event
310
                                 creation or signaling.
311
**/
312
EFI_STATUS
313
EFIAPI
314
EfiEventGroupSignal (
315
  IN CONST EFI_GUID  *EventGroup
316
  )
317
0
{
318
0
  EFI_STATUS  Status;
319
0
  EFI_EVENT   Event;
320
321
0
  if (EventGroup == NULL) {
322
0
    return EFI_INVALID_PARAMETER;
323
0
  }
324
325
0
  Status = gBS->CreateEventEx (
326
0
                  EVT_NOTIFY_SIGNAL,
327
0
                  TPL_CALLBACK,
328
0
                  EfiEventEmptyFunction,
329
0
                  NULL,
330
0
                  EventGroup,
331
0
                  &Event
332
0
                  );
333
0
  if (EFI_ERROR (Status)) {
334
0
    return Status;
335
0
  }
336
337
0
  Status = gBS->SignalEvent (Event);
338
0
  gBS->CloseEvent (Event);
339
340
0
  return Status;
341
0
}
342
343
/**
344
  An empty function that can be used as NotifyFunction parameter of
345
  CreateEvent() or CreateEventEx().
346
347
  @param Event              Event whose notification function is being invoked.
348
  @param Context            The pointer to the notification function's context,
349
                            which is implementation-dependent.
350
351
**/
352
VOID
353
EFIAPI
354
EfiEventEmptyFunction (
355
  IN EFI_EVENT  Event,
356
  IN VOID       *Context
357
  )
358
0
{
359
0
}
360
361
/**
362
  Returns the current TPL.
363
364
  This function returns the current TPL.  There is no EFI service to directly
365
  retrieve the current TPL. Instead, the RaiseTPL() function is used to raise
366
  the TPL to TPL_HIGH_LEVEL.  This will return the current TPL.  The TPL level
367
  can then immediately be restored back to the current TPL level with a call
368
  to RestoreTPL().
369
370
  @return The current TPL.
371
372
**/
373
EFI_TPL
374
EFIAPI
375
EfiGetCurrentTpl (
376
  VOID
377
  )
378
0
{
379
0
  EFI_TPL  Tpl;
380
381
0
  Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
382
0
  gBS->RestoreTPL (Tpl);
383
384
0
  return Tpl;
385
0
}
386
387
/**
388
  Initializes a basic mutual exclusion lock.
389
390
  This function initializes a basic mutual exclusion lock to the released state
391
  and returns the lock.  Each lock provides mutual exclusion access at its task
392
  priority level.  Since there is no preemption or multiprocessor support in EFI,
393
  acquiring the lock only consists of raising to the locks TPL.
394
  If Lock is NULL, then ASSERT().
395
  If Priority is not a valid TPL value, then ASSERT().
396
397
  @param  Lock       A pointer to the lock data structure to initialize.
398
  @param  Priority   EFI TPL is associated with the lock.
399
400
  @return The lock.
401
402
**/
403
EFI_LOCK *
404
EFIAPI
405
EfiInitializeLock (
406
  IN OUT EFI_LOCK  *Lock,
407
  IN EFI_TPL       Priority
408
  )
409
0
{
410
0
  ASSERT (Lock != NULL);
411
0
  ASSERT (Priority <= TPL_HIGH_LEVEL);
412
413
0
  Lock->Tpl      = Priority;
414
0
  Lock->OwnerTpl = TPL_APPLICATION;
415
0
  Lock->Lock     = EfiLockReleased;
416
0
  return Lock;
417
0
}
418
419
/**
420
  Acquires ownership of a lock.
421
422
  This function raises the system's current task priority level to the task
423
  priority level of the mutual exclusion lock.  Then, it places the lock in the
424
  acquired state.
425
  If Lock is NULL, then ASSERT().
426
  If Lock is not initialized, then ASSERT().
427
  If Lock is already in the acquired state, then ASSERT().
428
429
  @param  Lock              A pointer to the lock to acquire.
430
431
**/
432
VOID
433
EFIAPI
434
EfiAcquireLock (
435
  IN EFI_LOCK  *Lock
436
  )
437
0
{
438
0
  ASSERT (Lock != NULL);
439
0
  ASSERT (Lock->Lock == EfiLockReleased);
440
441
0
  Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
442
0
  Lock->Lock     = EfiLockAcquired;
443
0
}
444
445
/**
446
  Acquires ownership of a lock.
447
448
  This function raises the system's current task priority level to the task priority
449
  level of the mutual exclusion lock.  Then, it attempts to place the lock in the acquired state.
450
  If the lock is already in the acquired state, then EFI_ACCESS_DENIED is returned.
451
  Otherwise, EFI_SUCCESS is returned.
452
  If Lock is NULL, then ASSERT().
453
  If Lock is not initialized, then ASSERT().
454
455
  @param  Lock              A pointer to the lock to acquire.
456
457
  @retval EFI_SUCCESS       The lock was acquired.
458
  @retval EFI_ACCESS_DENIED The lock could not be acquired because it is already owned.
459
460
**/
461
EFI_STATUS
462
EFIAPI
463
EfiAcquireLockOrFail (
464
  IN EFI_LOCK  *Lock
465
  )
466
0
{
467
0
  ASSERT (Lock != NULL);
468
0
  ASSERT (Lock->Lock != EfiLockUninitialized);
469
470
0
  if (Lock->Lock == EfiLockAcquired) {
471
    //
472
    // Lock is already owned, so bail out
473
    //
474
0
    return EFI_ACCESS_DENIED;
475
0
  }
476
477
0
  Lock->OwnerTpl = gBS->RaiseTPL (Lock->Tpl);
478
479
0
  Lock->Lock = EfiLockAcquired;
480
481
0
  return EFI_SUCCESS;
482
0
}
483
484
/**
485
  Releases ownership of a lock.
486
487
  This function transitions a mutual exclusion lock from the acquired state to
488
  the released state, and restores the system's task priority level to its
489
  previous level.
490
  If Lock is NULL, then ASSERT().
491
  If Lock is not initialized, then ASSERT().
492
  If Lock is already in the released state, then ASSERT().
493
494
  @param  Lock  A pointer to the lock to release.
495
496
**/
497
VOID
498
EFIAPI
499
EfiReleaseLock (
500
  IN EFI_LOCK  *Lock
501
  )
502
0
{
503
0
  EFI_TPL  Tpl;
504
505
0
  ASSERT (Lock != NULL);
506
0
  ASSERT (Lock->Lock == EfiLockAcquired);
507
508
0
  Tpl = Lock->OwnerTpl;
509
510
0
  Lock->Lock = EfiLockReleased;
511
512
0
  gBS->RestoreTPL (Tpl);
513
0
}
514
515
/**
516
  Tests whether a controller handle is being managed by a specific driver.
517
518
  This function tests whether the driver specified by DriverBindingHandle is
519
  currently managing the controller specified by ControllerHandle.  This test
520
  is performed by evaluating if the the protocol specified by ProtocolGuid is
521
  present on ControllerHandle and is was opened by DriverBindingHandle with an
522
  attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
523
  If ProtocolGuid is NULL, then ASSERT().
524
525
  @param  ControllerHandle     A handle for a controller to test.
526
  @param  DriverBindingHandle  Specifies the driver binding handle for the
527
                               driver.
528
  @param  ProtocolGuid         Specifies the protocol that the driver specified
529
                               by DriverBindingHandle opens in its Start()
530
                               function.
531
532
  @retval EFI_SUCCESS          ControllerHandle is managed by the driver
533
                               specified by DriverBindingHandle.
534
  @retval EFI_UNSUPPORTED      ControllerHandle is not managed by the driver
535
                               specified by DriverBindingHandle.
536
537
**/
538
EFI_STATUS
539
EFIAPI
540
EfiTestManagedDevice (
541
  IN CONST EFI_HANDLE  ControllerHandle,
542
  IN CONST EFI_HANDLE  DriverBindingHandle,
543
  IN CONST EFI_GUID    *ProtocolGuid
544
  )
545
0
{
546
0
  EFI_STATUS  Status;
547
0
  VOID        *ManagedInterface;
548
549
0
  ASSERT (ProtocolGuid != NULL);
550
551
0
  Status = gBS->OpenProtocol (
552
0
                  ControllerHandle,
553
0
                  (EFI_GUID *)ProtocolGuid,
554
0
                  &ManagedInterface,
555
0
                  DriverBindingHandle,
556
0
                  ControllerHandle,
557
0
                  EFI_OPEN_PROTOCOL_BY_DRIVER
558
0
                  );
559
0
  if (!EFI_ERROR (Status)) {
560
0
    gBS->CloseProtocol (
561
0
           ControllerHandle,
562
0
           (EFI_GUID *)ProtocolGuid,
563
0
           DriverBindingHandle,
564
0
           ControllerHandle
565
0
           );
566
0
    return EFI_UNSUPPORTED;
567
0
  }
568
569
0
  if (Status != EFI_ALREADY_STARTED) {
570
0
    return EFI_UNSUPPORTED;
571
0
  }
572
573
0
  return EFI_SUCCESS;
574
0
}
575
576
/**
577
  Tests whether a child handle is a child device of the controller.
578
579
  This function tests whether ChildHandle is one of the children of
580
  ControllerHandle.  This test is performed by checking to see if the protocol
581
  specified by ProtocolGuid is present on ControllerHandle and opened by
582
  ChildHandle with an attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
583
  If ProtocolGuid is NULL, then ASSERT().
584
585
  @param  ControllerHandle     A handle for a (parent) controller to test.
586
  @param  ChildHandle          A child handle to test.
587
  @param  ProtocolGuid         Supplies the protocol that the child controller
588
                               opens on its parent controller.
589
590
  @retval EFI_SUCCESS          ChildHandle is a child of the ControllerHandle.
591
  @retval EFI_UNSUPPORTED      ChildHandle is not a child of the
592
                               ControllerHandle.
593
594
**/
595
EFI_STATUS
596
EFIAPI
597
EfiTestChildHandle (
598
  IN CONST EFI_HANDLE  ControllerHandle,
599
  IN CONST EFI_HANDLE  ChildHandle,
600
  IN CONST EFI_GUID    *ProtocolGuid
601
  )
602
0
{
603
0
  EFI_STATUS                           Status;
604
0
  EFI_OPEN_PROTOCOL_INFORMATION_ENTRY  *OpenInfoBuffer;
605
0
  UINTN                                EntryCount;
606
0
  UINTN                                Index;
607
608
0
  ASSERT (ProtocolGuid != NULL);
609
610
  //
611
  // Retrieve the list of agents that are consuming the specific protocol
612
  // on ControllerHandle.
613
  //
614
0
  Status = gBS->OpenProtocolInformation (
615
0
                  ControllerHandle,
616
0
                  (EFI_GUID *)ProtocolGuid,
617
0
                  &OpenInfoBuffer,
618
0
                  &EntryCount
619
0
                  );
620
0
  if (EFI_ERROR (Status)) {
621
0
    return EFI_UNSUPPORTED;
622
0
  }
623
624
  //
625
  // Inspect if ChildHandle is one of the agents.
626
  //
627
0
  Status = EFI_UNSUPPORTED;
628
0
  for (Index = 0; Index < EntryCount; Index++) {
629
0
    if ((OpenInfoBuffer[Index].ControllerHandle == ChildHandle) &&
630
0
        ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0))
631
0
    {
632
0
      Status = EFI_SUCCESS;
633
0
      break;
634
0
    }
635
0
  }
636
637
0
  FreePool (OpenInfoBuffer);
638
0
  return Status;
639
0
}
640
641
/**
642
  This function checks the supported languages list for a target language,
643
  This only supports RFC 4646 Languages.
644
645
  @param  SupportedLanguages  The supported languages
646
  @param  TargetLanguage      The target language
647
648
  @retval Returns EFI_SUCCESS if the language is supported,
649
          EFI_UNSUPPORTED otherwise
650
**/
651
EFI_STATUS
652
EFIAPI
653
IsLanguageSupported (
654
  IN CONST CHAR8  *SupportedLanguages,
655
  IN CONST CHAR8  *TargetLanguage
656
  )
657
0
{
658
0
  UINTN  Index;
659
660
0
  while (*SupportedLanguages != 0) {
661
0
    for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++) {
662
0
    }
663
664
0
    if ((AsciiStrnCmp (SupportedLanguages, TargetLanguage, Index) == 0) && (TargetLanguage[Index] == 0)) {
665
0
      return EFI_SUCCESS;
666
0
    }
667
668
0
    SupportedLanguages += Index;
669
0
    for ( ; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++) {
670
0
    }
671
0
  }
672
673
0
  return EFI_UNSUPPORTED;
674
0
}
675
676
/**
677
  This function looks up a Unicode string in UnicodeStringTable.
678
679
  If Language is a member of SupportedLanguages and a Unicode string is found in
680
  UnicodeStringTable that matches the language code specified by Language, then it
681
  is returned in UnicodeString.
682
683
  @param  Language                A pointer to the ISO 639-2 language code for the
684
                                  Unicode string to look up and return.
685
  @param  SupportedLanguages      A pointer to the set of ISO 639-2 language codes
686
                                  that the Unicode string table supports.  Language
687
                                  must be a member of this set.
688
  @param  UnicodeStringTable      A pointer to the table of Unicode strings.
689
  @param  UnicodeString           A pointer to the Unicode string from UnicodeStringTable
690
                                  that matches the language specified by Language.
691
692
  @retval EFI_SUCCESS             The Unicode string that matches the language
693
                                  specified by Language was found
694
                                  in the table of Unicode strings UnicodeStringTable,
695
                                  and it was returned in UnicodeString.
696
  @retval EFI_INVALID_PARAMETER   Language is NULL.
697
  @retval EFI_INVALID_PARAMETER   UnicodeString is NULL.
698
  @retval EFI_UNSUPPORTED         SupportedLanguages is NULL.
699
  @retval EFI_UNSUPPORTED         UnicodeStringTable is NULL.
700
  @retval EFI_UNSUPPORTED         The language specified by Language is not a
701
                                  member of SupportedLanguages.
702
  @retval EFI_UNSUPPORTED         The language specified by Language is not
703
                                  supported by UnicodeStringTable.
704
705
**/
706
EFI_STATUS
707
EFIAPI
708
LookupUnicodeString (
709
  IN CONST CHAR8                     *Language,
710
  IN CONST CHAR8                     *SupportedLanguages,
711
  IN CONST EFI_UNICODE_STRING_TABLE  *UnicodeStringTable,
712
  OUT CHAR16                         **UnicodeString
713
  )
714
0
{
715
  //
716
  // Make sure the parameters are valid
717
  //
718
0
  if ((Language == NULL) || (UnicodeString == NULL)) {
719
0
    return EFI_INVALID_PARAMETER;
720
0
  }
721
722
  //
723
  // If there are no supported languages, or the Unicode String Table is empty, then the
724
  // Unicode String specified by Language is not supported by this Unicode String Table
725
  //
726
0
  if ((SupportedLanguages == NULL) || (UnicodeStringTable == NULL)) {
727
0
    return EFI_UNSUPPORTED;
728
0
  }
729
730
  //
731
  // Make sure Language is in the set of Supported Languages
732
  //
733
0
  while (*SupportedLanguages != 0) {
734
0
    if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
735
      //
736
      // Search the Unicode String Table for the matching Language specifier
737
      //
738
0
      while (UnicodeStringTable->Language != NULL) {
739
0
        if (CompareIso639LanguageCode (Language, UnicodeStringTable->Language)) {
740
          //
741
          // A matching string was found, so return it
742
          //
743
0
          *UnicodeString = UnicodeStringTable->UnicodeString;
744
0
          return EFI_SUCCESS;
745
0
        }
746
747
0
        UnicodeStringTable++;
748
0
      }
749
750
0
      return EFI_UNSUPPORTED;
751
0
    }
752
753
0
    SupportedLanguages += 3;
754
0
  }
755
756
0
  return EFI_UNSUPPORTED;
757
0
}
758
759
/**
760
  This function looks up a Unicode string in UnicodeStringTable.
761
762
  If Language is a member of SupportedLanguages and a Unicode string is found in
763
  UnicodeStringTable that matches the language code specified by Language, then
764
  it is returned in UnicodeString.
765
766
  @param  Language             A pointer to an ASCII string containing the ISO 639-2 or the
767
                               RFC 4646 language code for the Unicode string to look up and
768
                               return. If Iso639Language is TRUE, then this ASCII string is
769
                               not assumed to be Null-terminated, and only the first three
770
                               characters are used. If Iso639Language is FALSE, then this ASCII
771
                               string must be Null-terminated.
772
  @param  SupportedLanguages   A pointer to a Null-terminated ASCII string that contains a
773
                               set of ISO 639-2 or RFC 4646 language codes that the Unicode
774
                               string table supports.  Language must be a member of this set.
775
                               If Iso639Language is TRUE, then this string contains one or more
776
                               ISO 639-2 language codes with no separator characters. If Iso639Language
777
                               is FALSE, then is string contains one or more RFC 4646 language
778
                               codes separated by ';'.
779
  @param  UnicodeStringTable   A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
780
                               is defined in "Related Definitions".
781
  @param  UnicodeString        A pointer to the Null-terminated Unicode string from UnicodeStringTable
782
                               that matches the language specified by Language.
783
  @param  Iso639Language       Specifies the supported language code format. If it is TRUE, then
784
                               Language and SupportedLanguages follow ISO 639-2 language code format.
785
                               Otherwise, they follow RFC 4646 language code format.
786
787
788
  @retval  EFI_SUCCESS            The Unicode string that matches the language specified by Language
789
                                  was found in the table of Unicode strings UnicodeStringTable, and
790
                                  it was returned in UnicodeString.
791
  @retval  EFI_INVALID_PARAMETER  Language is NULL.
792
  @retval  EFI_INVALID_PARAMETER  UnicodeString is NULL.
793
  @retval  EFI_UNSUPPORTED        SupportedLanguages is NULL.
794
  @retval  EFI_UNSUPPORTED        UnicodeStringTable is NULL.
795
  @retval  EFI_UNSUPPORTED        The language specified by Language is not a member of SupportedLanguages.
796
  @retval  EFI_UNSUPPORTED        The language specified by Language is not supported by UnicodeStringTable.
797
798
**/
799
EFI_STATUS
800
EFIAPI
801
LookupUnicodeString2 (
802
  IN CONST CHAR8                     *Language,
803
  IN CONST CHAR8                     *SupportedLanguages,
804
  IN CONST EFI_UNICODE_STRING_TABLE  *UnicodeStringTable,
805
  OUT CHAR16                         **UnicodeString,
806
  IN BOOLEAN                         Iso639Language
807
  )
808
0
{
809
0
  BOOLEAN  Found;
810
0
  UINTN    Index;
811
0
  CHAR8    *LanguageString;
812
813
  //
814
  // Make sure the parameters are valid
815
  //
816
0
  if ((Language == NULL) || (UnicodeString == NULL)) {
817
0
    return EFI_INVALID_PARAMETER;
818
0
  }
819
820
  //
821
  // If there are no supported languages, or the Unicode String Table is empty, then the
822
  // Unicode String specified by Language is not supported by this Unicode String Table
823
  //
824
0
  if ((SupportedLanguages == NULL) || (UnicodeStringTable == NULL)) {
825
0
    return EFI_UNSUPPORTED;
826
0
  }
827
828
  //
829
  // Make sure Language is in the set of Supported Languages
830
  //
831
0
  Found = FALSE;
832
0
  if (Iso639Language) {
833
0
    while (*SupportedLanguages != 0) {
834
0
      if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
835
0
        Found = TRUE;
836
0
        break;
837
0
      }
838
839
0
      SupportedLanguages += 3;
840
0
    }
841
0
  } else {
842
0
    Found = !IsLanguageSupported (SupportedLanguages, Language);
843
0
  }
844
845
  //
846
  // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
847
  //
848
0
  if (!Found) {
849
0
    return EFI_UNSUPPORTED;
850
0
  }
851
852
  //
853
  // Search the Unicode String Table for the matching Language specifier
854
  //
855
0
  while (UnicodeStringTable->Language != NULL) {
856
0
    LanguageString = UnicodeStringTable->Language;
857
0
    while (0 != *LanguageString) {
858
0
      for (Index = 0; LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++) {
859
0
      }
860
861
0
      if (AsciiStrnCmp (LanguageString, Language, Index) == 0) {
862
0
        *UnicodeString = UnicodeStringTable->UnicodeString;
863
0
        return EFI_SUCCESS;
864
0
      }
865
866
0
      LanguageString += Index;
867
0
      for (Index = 0; LanguageString[Index] != 0 && LanguageString[Index] == ';'; Index++) {
868
0
      }
869
0
    }
870
871
0
    UnicodeStringTable++;
872
0
  }
873
874
0
  return EFI_UNSUPPORTED;
875
0
}
876
877
/**
878
  This function adds a Unicode string to UnicodeStringTable.
879
880
  If Language is a member of SupportedLanguages then UnicodeString is added to
881
  UnicodeStringTable.  New buffers are allocated for both Language and
882
  UnicodeString.  The contents of Language and UnicodeString are copied into
883
  these new buffers.  These buffers are automatically freed when
884
  FreeUnicodeStringTable() is called.
885
886
  @param  Language                A pointer to the ISO 639-2 language code for the Unicode
887
                                  string to add.
888
  @param  SupportedLanguages      A pointer to the set of ISO 639-2 language codes
889
                                  that the Unicode string table supports.
890
                                  Language must be a member of this set.
891
  @param  UnicodeStringTable      A pointer to the table of Unicode strings.
892
  @param  UnicodeString           A pointer to the Unicode string to add.
893
894
  @retval EFI_SUCCESS             The Unicode string that matches the language
895
                                  specified by Language was found in the table of
896
                                  Unicode strings UnicodeStringTable, and it was
897
                                  returned in UnicodeString.
898
  @retval EFI_INVALID_PARAMETER   Language is NULL.
899
  @retval EFI_INVALID_PARAMETER   UnicodeString is NULL.
900
  @retval EFI_INVALID_PARAMETER   UnicodeString is an empty string.
901
  @retval EFI_UNSUPPORTED         SupportedLanguages is NULL.
902
  @retval EFI_ALREADY_STARTED     A Unicode string with language Language is
903
                                  already present in UnicodeStringTable.
904
  @retval EFI_OUT_OF_RESOURCES    There is not enough memory to add another
905
                                  Unicode string to UnicodeStringTable.
906
  @retval EFI_UNSUPPORTED         The language specified by Language is not a
907
                                  member of SupportedLanguages.
908
909
**/
910
EFI_STATUS
911
EFIAPI
912
AddUnicodeString (
913
  IN     CONST CHAR8               *Language,
914
  IN     CONST CHAR8               *SupportedLanguages,
915
  IN OUT EFI_UNICODE_STRING_TABLE  **UnicodeStringTable,
916
  IN     CONST CHAR16              *UnicodeString
917
  )
918
0
{
919
0
  UINTN                     NumberOfEntries;
920
0
  EFI_UNICODE_STRING_TABLE  *OldUnicodeStringTable;
921
0
  EFI_UNICODE_STRING_TABLE  *NewUnicodeStringTable;
922
0
  UINTN                     UnicodeStringLength;
923
924
  //
925
  // Make sure the parameter are valid
926
  //
927
0
  if ((Language == NULL) || (UnicodeString == NULL) || (UnicodeStringTable == NULL)) {
928
0
    return EFI_INVALID_PARAMETER;
929
0
  }
930
931
  //
932
  // If there are no supported languages, then a Unicode String can not be added
933
  //
934
0
  if (SupportedLanguages == NULL) {
935
0
    return EFI_UNSUPPORTED;
936
0
  }
937
938
  //
939
  // If the Unicode String is empty, then a Unicode String can not be added
940
  //
941
0
  if (UnicodeString[0] == 0) {
942
0
    return EFI_INVALID_PARAMETER;
943
0
  }
944
945
  //
946
  // Make sure Language is a member of SupportedLanguages
947
  //
948
0
  while (*SupportedLanguages != 0) {
949
0
    if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
950
      //
951
      // Determine the size of the Unicode String Table by looking for a NULL Language entry
952
      //
953
0
      NumberOfEntries = 0;
954
0
      if (*UnicodeStringTable != NULL) {
955
0
        OldUnicodeStringTable = *UnicodeStringTable;
956
0
        while (OldUnicodeStringTable->Language != NULL) {
957
0
          if (CompareIso639LanguageCode (Language, OldUnicodeStringTable->Language)) {
958
0
            return EFI_ALREADY_STARTED;
959
0
          }
960
961
0
          OldUnicodeStringTable++;
962
0
          NumberOfEntries++;
963
0
        }
964
0
      }
965
966
      //
967
      // Allocate space for a new Unicode String Table.  It must hold the current number of
968
      // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
969
      // marker
970
      //
971
0
      NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
972
0
      if (NewUnicodeStringTable == NULL) {
973
0
        return EFI_OUT_OF_RESOURCES;
974
0
      }
975
976
      //
977
      // If the current Unicode String Table contains any entries, then copy them to the
978
      // newly allocated Unicode String Table.
979
      //
980
0
      if (*UnicodeStringTable != NULL) {
981
0
        CopyMem (
982
0
          NewUnicodeStringTable,
983
0
          *UnicodeStringTable,
984
0
          NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
985
0
          );
986
0
      }
987
988
      //
989
      // Allocate space for a copy of the Language specifier
990
      //
991
0
      NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (3, Language);
992
0
      if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
993
0
        FreePool (NewUnicodeStringTable);
994
0
        return EFI_OUT_OF_RESOURCES;
995
0
      }
996
997
      //
998
      // Compute the length of the Unicode String
999
      //
1000
0
      for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++) {
1001
0
      }
1002
1003
      //
1004
      // Allocate space for a copy of the Unicode String
1005
      //
1006
0
      NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (
1007
0
                                                               (UnicodeStringLength + 1) * sizeof (CHAR16),
1008
0
                                                               UnicodeString
1009
0
                                                               );
1010
0
      if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
1011
0
        FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
1012
0
        FreePool (NewUnicodeStringTable);
1013
0
        return EFI_OUT_OF_RESOURCES;
1014
0
      }
1015
1016
      //
1017
      // Mark the end of the Unicode String Table
1018
      //
1019
0
      NewUnicodeStringTable[NumberOfEntries + 1].Language      = NULL;
1020
0
      NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL;
1021
1022
      //
1023
      // Free the old Unicode String Table
1024
      //
1025
0
      if (*UnicodeStringTable != NULL) {
1026
0
        FreePool (*UnicodeStringTable);
1027
0
      }
1028
1029
      //
1030
      // Point UnicodeStringTable at the newly allocated Unicode String Table
1031
      //
1032
0
      *UnicodeStringTable = NewUnicodeStringTable;
1033
1034
0
      return EFI_SUCCESS;
1035
0
    }
1036
1037
0
    SupportedLanguages += 3;
1038
0
  }
1039
1040
0
  return EFI_UNSUPPORTED;
1041
0
}
1042
1043
/**
1044
  This function adds the Null-terminated Unicode string specified by UnicodeString
1045
  to UnicodeStringTable.
1046
1047
  If Language is a member of SupportedLanguages then UnicodeString is added to
1048
  UnicodeStringTable.  New buffers are allocated for both Language and UnicodeString.
1049
  The contents of Language and UnicodeString are copied into these new buffers.
1050
  These buffers are automatically freed when EfiLibFreeUnicodeStringTable() is called.
1051
1052
  @param  Language            A pointer to an ASCII string containing the ISO 639-2 or
1053
                              the RFC 4646 language code for the Unicode string to add.
1054
                              If Iso639Language is TRUE, then this ASCII string is not
1055
                              assumed to be Null-terminated, and only the first three
1056
                              chacters are used. If Iso639Language is FALSE, then this
1057
                              ASCII string must be Null-terminated.
1058
  @param  SupportedLanguages  A pointer to a Null-terminated ASCII string that contains
1059
                              a set of ISO 639-2 or RFC 4646 language codes that the Unicode
1060
                              string table supports.  Language must be a member of this set.
1061
                              If Iso639Language is TRUE, then this string contains one or more
1062
                              ISO 639-2 language codes with no separator characters.
1063
                              If Iso639Language is FALSE, then is string contains one or more
1064
                              RFC 4646 language codes separated by ';'.
1065
  @param  UnicodeStringTable  A pointer to the table of Unicode strings. Type EFI_UNICODE_STRING_TABLE
1066
                              is defined in "Related Definitions".
1067
  @param  UnicodeString       A pointer to the Unicode string to add.
1068
  @param  Iso639Language      Specifies the supported language code format. If it is TRUE,
1069
                              then Language and SupportedLanguages follow ISO 639-2 language code format.
1070
                              Otherwise, they follow RFC 4646 language code format.
1071
1072
  @retval EFI_SUCCESS            The Unicode string that matches the language specified by
1073
                                 Language was found in the table of Unicode strings UnicodeStringTable,
1074
                                 and it was returned in UnicodeString.
1075
  @retval EFI_INVALID_PARAMETER  Language is NULL.
1076
  @retval EFI_INVALID_PARAMETER  UnicodeString is NULL.
1077
  @retval EFI_INVALID_PARAMETER  UnicodeString is an empty string.
1078
  @retval EFI_UNSUPPORTED        SupportedLanguages is NULL.
1079
  @retval EFI_ALREADY_STARTED    A Unicode string with language Language is already present in
1080
                                 UnicodeStringTable.
1081
  @retval EFI_OUT_OF_RESOURCES   There is not enough memory to add another Unicode string UnicodeStringTable.
1082
  @retval EFI_UNSUPPORTED        The language specified by Language is not a member of SupportedLanguages.
1083
1084
**/
1085
EFI_STATUS
1086
EFIAPI
1087
AddUnicodeString2 (
1088
  IN     CONST CHAR8               *Language,
1089
  IN     CONST CHAR8               *SupportedLanguages,
1090
  IN OUT EFI_UNICODE_STRING_TABLE  **UnicodeStringTable,
1091
  IN     CONST CHAR16              *UnicodeString,
1092
  IN     BOOLEAN                   Iso639Language
1093
  )
1094
0
{
1095
0
  UINTN                     NumberOfEntries;
1096
0
  EFI_UNICODE_STRING_TABLE  *OldUnicodeStringTable;
1097
0
  EFI_UNICODE_STRING_TABLE  *NewUnicodeStringTable;
1098
0
  UINTN                     UnicodeStringLength;
1099
0
  BOOLEAN                   Found;
1100
0
  UINTN                     Index;
1101
0
  CHAR8                     *LanguageString;
1102
1103
  //
1104
  // Make sure the parameter are valid
1105
  //
1106
0
  if ((Language == NULL) || (UnicodeString == NULL) || (UnicodeStringTable == NULL)) {
1107
0
    return EFI_INVALID_PARAMETER;
1108
0
  }
1109
1110
  //
1111
  // If there are no supported languages, then a Unicode String can not be added
1112
  //
1113
0
  if (SupportedLanguages == NULL) {
1114
0
    return EFI_UNSUPPORTED;
1115
0
  }
1116
1117
  //
1118
  // If the Unicode String is empty, then a Unicode String can not be added
1119
  //
1120
0
  if (UnicodeString[0] == 0) {
1121
0
    return EFI_INVALID_PARAMETER;
1122
0
  }
1123
1124
  //
1125
  // Make sure Language is a member of SupportedLanguages
1126
  //
1127
0
  Found = FALSE;
1128
0
  if (Iso639Language) {
1129
0
    while (*SupportedLanguages != 0) {
1130
0
      if (CompareIso639LanguageCode (Language, SupportedLanguages)) {
1131
0
        Found = TRUE;
1132
0
        break;
1133
0
      }
1134
1135
0
      SupportedLanguages += 3;
1136
0
    }
1137
0
  } else {
1138
0
    Found = !IsLanguageSupported (SupportedLanguages, Language);
1139
0
  }
1140
1141
  //
1142
  // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
1143
  //
1144
0
  if (!Found) {
1145
0
    return EFI_UNSUPPORTED;
1146
0
  }
1147
1148
  //
1149
  // Determine the size of the Unicode String Table by looking for a NULL Language entry
1150
  //
1151
0
  NumberOfEntries = 0;
1152
0
  if (*UnicodeStringTable != NULL) {
1153
0
    OldUnicodeStringTable = *UnicodeStringTable;
1154
0
    while (OldUnicodeStringTable->Language != NULL) {
1155
0
      LanguageString = OldUnicodeStringTable->Language;
1156
1157
0
      while (*LanguageString != 0) {
1158
0
        for (Index = 0; LanguageString[Index] != 0 && LanguageString[Index] != ';'; Index++) {
1159
0
        }
1160
1161
0
        if (AsciiStrnCmp (Language, LanguageString, Index) == 0) {
1162
0
          return EFI_ALREADY_STARTED;
1163
0
        }
1164
1165
0
        LanguageString += Index;
1166
0
        for ( ; *LanguageString != 0 && *LanguageString == ';'; LanguageString++) {
1167
0
        }
1168
0
      }
1169
1170
0
      OldUnicodeStringTable++;
1171
0
      NumberOfEntries++;
1172
0
    }
1173
0
  }
1174
1175
  //
1176
  // Allocate space for a new Unicode String Table.  It must hold the current number of
1177
  // entries, plus 1 entry for the new Unicode String, plus 1 entry for the end of table
1178
  // marker
1179
  //
1180
0
  NewUnicodeStringTable = AllocatePool ((NumberOfEntries + 2) * sizeof (EFI_UNICODE_STRING_TABLE));
1181
0
  if (NewUnicodeStringTable == NULL) {
1182
0
    return EFI_OUT_OF_RESOURCES;
1183
0
  }
1184
1185
  //
1186
  // If the current Unicode String Table contains any entries, then copy them to the
1187
  // newly allocated Unicode String Table.
1188
  //
1189
0
  if (*UnicodeStringTable != NULL) {
1190
0
    CopyMem (
1191
0
      NewUnicodeStringTable,
1192
0
      *UnicodeStringTable,
1193
0
      NumberOfEntries * sizeof (EFI_UNICODE_STRING_TABLE)
1194
0
      );
1195
0
  }
1196
1197
  //
1198
  // Allocate space for a copy of the Language specifier
1199
  //
1200
0
  NewUnicodeStringTable[NumberOfEntries].Language = AllocateCopyPool (AsciiStrSize (Language), Language);
1201
0
  if (NewUnicodeStringTable[NumberOfEntries].Language == NULL) {
1202
0
    FreePool (NewUnicodeStringTable);
1203
0
    return EFI_OUT_OF_RESOURCES;
1204
0
  }
1205
1206
  //
1207
  // Compute the length of the Unicode String
1208
  //
1209
0
  for (UnicodeStringLength = 0; UnicodeString[UnicodeStringLength] != 0; UnicodeStringLength++) {
1210
0
  }
1211
1212
  //
1213
  // Allocate space for a copy of the Unicode String
1214
  //
1215
0
  NewUnicodeStringTable[NumberOfEntries].UnicodeString = AllocateCopyPool (StrSize (UnicodeString), UnicodeString);
1216
0
  if (NewUnicodeStringTable[NumberOfEntries].UnicodeString == NULL) {
1217
0
    FreePool (NewUnicodeStringTable[NumberOfEntries].Language);
1218
0
    FreePool (NewUnicodeStringTable);
1219
0
    return EFI_OUT_OF_RESOURCES;
1220
0
  }
1221
1222
  //
1223
  // Mark the end of the Unicode String Table
1224
  //
1225
0
  NewUnicodeStringTable[NumberOfEntries + 1].Language      = NULL;
1226
0
  NewUnicodeStringTable[NumberOfEntries + 1].UnicodeString = NULL;
1227
1228
  //
1229
  // Free the old Unicode String Table
1230
  //
1231
0
  if (*UnicodeStringTable != NULL) {
1232
0
    FreePool (*UnicodeStringTable);
1233
0
  }
1234
1235
  //
1236
  // Point UnicodeStringTable at the newly allocated Unicode String Table
1237
  //
1238
0
  *UnicodeStringTable = NewUnicodeStringTable;
1239
1240
0
  return EFI_SUCCESS;
1241
0
}
1242
1243
/**
1244
  This function frees the table of Unicode strings in UnicodeStringTable.
1245
1246
  If UnicodeStringTable is NULL, then EFI_SUCCESS is returned.
1247
  Otherwise, each language code, and each Unicode string in the Unicode string
1248
  table are freed, and EFI_SUCCESS is returned.
1249
1250
  @param  UnicodeStringTable  A pointer to the table of Unicode strings.
1251
1252
  @retval EFI_SUCCESS         The Unicode string table was freed.
1253
1254
**/
1255
EFI_STATUS
1256
EFIAPI
1257
FreeUnicodeStringTable (
1258
  IN EFI_UNICODE_STRING_TABLE  *UnicodeStringTable
1259
  )
1260
0
{
1261
0
  UINTN  Index;
1262
1263
  //
1264
  // If the Unicode String Table is NULL, then it is already freed
1265
  //
1266
0
  if (UnicodeStringTable == NULL) {
1267
0
    return EFI_SUCCESS;
1268
0
  }
1269
1270
  //
1271
  // Loop through the Unicode String Table until we reach the end of table marker
1272
  //
1273
0
  for (Index = 0; UnicodeStringTable[Index].Language != NULL; Index++) {
1274
    //
1275
    // Free the Language string from the Unicode String Table
1276
    //
1277
0
    FreePool (UnicodeStringTable[Index].Language);
1278
1279
    //
1280
    // Free the Unicode String from the Unicode String Table
1281
    //
1282
0
    if (UnicodeStringTable[Index].UnicodeString != NULL) {
1283
0
      FreePool (UnicodeStringTable[Index].UnicodeString);
1284
0
    }
1285
0
  }
1286
1287
  //
1288
  // Free the Unicode String Table itself
1289
  //
1290
0
  FreePool (UnicodeStringTable);
1291
1292
0
  return EFI_SUCCESS;
1293
0
}
1294
1295
/**
1296
  Returns the status whether get the variable success. The function retrieves
1297
  variable  through the UEFI Runtime Service GetVariable().  The
1298
  returned buffer is allocated using AllocatePool().  The caller is responsible
1299
  for freeing this buffer with FreePool().
1300
1301
  If Name  is NULL, then ASSERT().
1302
  If Guid  is NULL, then ASSERT().
1303
  If Value is NULL, then ASSERT().
1304
1305
  @param[in]  Name  The pointer to a Null-terminated Unicode string.
1306
  @param[in]  Guid  The pointer to an EFI_GUID structure
1307
  @param[out] Value The buffer point saved the variable info.
1308
  @param[out] Size  The buffer size of the variable.
1309
1310
  @return EFI_OUT_OF_RESOURCES      Allocate buffer failed.
1311
  @return EFI_SUCCESS               Find the specified variable.
1312
  @return Others Errors             Return errors from call to gRT->GetVariable.
1313
1314
**/
1315
EFI_STATUS
1316
EFIAPI
1317
GetVariable2 (
1318
  IN CONST CHAR16    *Name,
1319
  IN CONST EFI_GUID  *Guid,
1320
  OUT VOID           **Value,
1321
  OUT UINTN          *Size OPTIONAL
1322
  )
1323
0
{
1324
0
  EFI_STATUS  Status;
1325
0
  UINTN       BufferSize;
1326
1327
0
  ASSERT (Name != NULL && Guid != NULL && Value != NULL);
1328
1329
  //
1330
  // Try to get the variable size.
1331
  //
1332
0
  BufferSize = 0;
1333
0
  *Value     = NULL;
1334
0
  if (Size != NULL) {
1335
0
    *Size = 0;
1336
0
  }
1337
1338
0
  Status = gRT->GetVariable ((CHAR16 *)Name, (EFI_GUID *)Guid, NULL, &BufferSize, *Value);
1339
0
  if (Status != EFI_BUFFER_TOO_SMALL) {
1340
0
    return Status;
1341
0
  }
1342
1343
  //
1344
  // Allocate buffer to get the variable.
1345
  //
1346
0
  *Value = AllocatePool (BufferSize);
1347
0
  ASSERT (*Value != NULL);
1348
0
  if (*Value == NULL) {
1349
0
    return EFI_OUT_OF_RESOURCES;
1350
0
  }
1351
1352
  //
1353
  // Get the variable data.
1354
  //
1355
0
  Status = gRT->GetVariable ((CHAR16 *)Name, (EFI_GUID *)Guid, NULL, &BufferSize, *Value);
1356
0
  if (EFI_ERROR (Status)) {
1357
0
    FreePool (*Value);
1358
0
    *Value = NULL;
1359
0
  }
1360
1361
0
  if (Size != NULL) {
1362
0
    *Size = BufferSize;
1363
0
  }
1364
1365
0
  return Status;
1366
0
}
1367
1368
/** Return the attributes of the variable.
1369
1370
  Returns the status whether get the variable success. The function retrieves
1371
  variable  through the UEFI Runtime Service GetVariable().  The
1372
  returned buffer is allocated using AllocatePool().  The caller is responsible
1373
  for freeing this buffer with FreePool().  The attributes are returned if
1374
  the caller provides a valid Attribute parameter.
1375
1376
  If Name  is NULL, then ASSERT().
1377
  If Guid  is NULL, then ASSERT().
1378
  If Value is NULL, then ASSERT().
1379
1380
  @param[in]  Name  The pointer to a Null-terminated Unicode string.
1381
  @param[in]  Guid  The pointer to an EFI_GUID structure
1382
  @param[out] Value The buffer point saved the variable info.
1383
  @param[out] Size  The buffer size of the variable.
1384
  @param[out] Attr  The pointer to the variable attributes as found in var store
1385
1386
  @retval EFI_OUT_OF_RESOURCES      Allocate buffer failed.
1387
  @retval EFI_SUCCESS               Find the specified variable.
1388
  @retval Others Errors             Return errors from call to gRT->GetVariable.
1389
1390
**/
1391
EFI_STATUS
1392
EFIAPI
1393
GetVariable3 (
1394
  IN CONST CHAR16    *Name,
1395
  IN CONST EFI_GUID  *Guid,
1396
  OUT VOID           **Value,
1397
  OUT UINTN          *Size OPTIONAL,
1398
  OUT UINT32         *Attr OPTIONAL
1399
  )
1400
0
{
1401
0
  EFI_STATUS  Status;
1402
0
  UINTN       BufferSize;
1403
1404
0
  ASSERT (Name != NULL && Guid != NULL && Value != NULL);
1405
1406
  //
1407
  // Try to get the variable size.
1408
  //
1409
0
  BufferSize = 0;
1410
0
  *Value     = NULL;
1411
0
  if (Size != NULL) {
1412
0
    *Size = 0;
1413
0
  }
1414
1415
0
  if (Attr != NULL) {
1416
0
    *Attr = 0;
1417
0
  }
1418
1419
0
  Status = gRT->GetVariable ((CHAR16 *)Name, (EFI_GUID *)Guid, Attr, &BufferSize, *Value);
1420
0
  if (Status != EFI_BUFFER_TOO_SMALL) {
1421
0
    return Status;
1422
0
  }
1423
1424
  //
1425
  // Allocate buffer to get the variable.
1426
  //
1427
0
  *Value = AllocatePool (BufferSize);
1428
0
  ASSERT (*Value != NULL);
1429
0
  if (*Value == NULL) {
1430
0
    return EFI_OUT_OF_RESOURCES;
1431
0
  }
1432
1433
  //
1434
  // Get the variable data.
1435
  //
1436
0
  Status = gRT->GetVariable ((CHAR16 *)Name, (EFI_GUID *)Guid, Attr, &BufferSize, *Value);
1437
0
  if (EFI_ERROR (Status)) {
1438
0
    FreePool (*Value);
1439
0
    *Value = NULL;
1440
0
  }
1441
1442
0
  if (Size != NULL) {
1443
0
    *Size = BufferSize;
1444
0
  }
1445
1446
0
  return Status;
1447
0
}
1448
1449
/**
1450
  Returns a pointer to an allocated buffer that contains the contents of a
1451
  variable retrieved through the UEFI Runtime Service GetVariable().  This
1452
  function always uses the EFI_GLOBAL_VARIABLE GUID to retrieve variables.
1453
  The returned buffer is allocated using AllocatePool().  The caller is
1454
  responsible for freeing this buffer with FreePool().
1455
1456
  If Name is NULL, then ASSERT().
1457
  If Value is NULL, then ASSERT().
1458
1459
  @param[in]  Name  The pointer to a Null-terminated Unicode string.
1460
  @param[out] Value The buffer point saved the variable info.
1461
  @param[out] Size  The buffer size of the variable.
1462
1463
  @return EFI_OUT_OF_RESOURCES      Allocate buffer failed.
1464
  @return EFI_SUCCESS               Find the specified variable.
1465
  @return Others Errors             Return errors from call to gRT->GetVariable.
1466
1467
**/
1468
EFI_STATUS
1469
EFIAPI
1470
GetEfiGlobalVariable2 (
1471
  IN CONST CHAR16  *Name,
1472
  OUT VOID         **Value,
1473
  OUT UINTN        *Size OPTIONAL
1474
  )
1475
0
{
1476
0
  return GetVariable2 (Name, &gEfiGlobalVariableGuid, Value, Size);
1477
0
}
1478
1479
/**
1480
  Returns a pointer to an allocated buffer that contains the best matching language
1481
  from a set of supported languages.
1482
1483
  This function supports both ISO 639-2 and RFC 4646 language codes, but language
1484
  code types may not be mixed in a single call to this function.  The language
1485
  code returned is allocated using AllocatePool().  The caller is responsible for
1486
  freeing the allocated buffer using FreePool().  This function supports a variable
1487
  argument list that allows the caller to pass in a prioritized list of language
1488
  codes to test against all the language codes in SupportedLanguages.
1489
1490
  If SupportedLanguages is NULL, then ASSERT().
1491
1492
  @param[in]  SupportedLanguages  A pointer to a Null-terminated ASCII string that
1493
                                  contains a set of language codes in the format
1494
                                  specified by Iso639Language.
1495
  @param[in]  Iso639Language      If not zero, then all language codes are assumed to be
1496
                                  in ISO 639-2 format.  If zero, then all language
1497
                                  codes are assumed to be in RFC 4646 language format
1498
  @param[in]  ...                 A variable argument list that contains pointers to
1499
                                  Null-terminated ASCII strings that contain one or more
1500
                                  language codes in the format specified by Iso639Language.
1501
                                  The first language code from each of these language
1502
                                  code lists is used to determine if it is an exact or
1503
                                  close match to any of the language codes in
1504
                                  SupportedLanguages.  Close matches only apply to RFC 4646
1505
                                  language codes, and the matching algorithm from RFC 4647
1506
                                  is used to determine if a close match is present.  If
1507
                                  an exact or close match is found, then the matching
1508
                                  language code from SupportedLanguages is returned.  If
1509
                                  no matches are found, then the next variable argument
1510
                                  parameter is evaluated.  The variable argument list
1511
                                  is terminated by a NULL.
1512
1513
  @retval NULL   The best matching language could not be found in SupportedLanguages.
1514
  @retval NULL   There are not enough resources available to return the best matching
1515
                 language.
1516
  @retval Other  A pointer to a Null-terminated ASCII string that is the best matching
1517
                 language in SupportedLanguages.
1518
1519
**/
1520
CHAR8 *
1521
EFIAPI
1522
GetBestLanguage (
1523
  IN CONST CHAR8  *SupportedLanguages,
1524
  IN UINTN        Iso639Language,
1525
  ...
1526
  )
1527
0
{
1528
0
  VA_LIST      Args;
1529
0
  CHAR8        *Language;
1530
0
  UINTN        CompareLength;
1531
0
  UINTN        LanguageLength;
1532
0
  CONST CHAR8  *Supported;
1533
0
  CHAR8        *BestLanguage;
1534
1535
0
  ASSERT (SupportedLanguages != NULL);
1536
1537
0
  VA_START (Args, Iso639Language);
1538
0
  while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
1539
    //
1540
    // Default to ISO 639-2 mode
1541
    //
1542
0
    CompareLength  = 3;
1543
0
    LanguageLength = MIN (3, AsciiStrLen (Language));
1544
1545
    //
1546
    // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1547
    //
1548
0
    if (Iso639Language == 0) {
1549
0
      for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++) {
1550
0
      }
1551
0
    }
1552
1553
    //
1554
    // Trim back the length of Language used until it is empty
1555
    //
1556
0
    while (LanguageLength > 0) {
1557
      //
1558
      // Loop through all language codes in SupportedLanguages
1559
      //
1560
0
      for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
1561
        //
1562
        // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1563
        //
1564
0
        if (Iso639Language == 0) {
1565
          //
1566
          // Skip ';' characters in Supported
1567
          //
1568
0
          for ( ; *Supported != '\0' && *Supported == ';'; Supported++) {
1569
0
          }
1570
1571
          //
1572
          // Determine the length of the next language code in Supported
1573
          //
1574
0
          for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++) {
1575
0
          }
1576
1577
          //
1578
          // If Language is longer than the Supported, then skip to the next language
1579
          //
1580
0
          if (LanguageLength > CompareLength) {
1581
0
            continue;
1582
0
          }
1583
0
        }
1584
1585
        //
1586
        // See if the first LanguageLength characters in Supported match Language
1587
        //
1588
0
        if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
1589
0
          VA_END (Args);
1590
          //
1591
          // Allocate, copy, and return the best matching language code from SupportedLanguages
1592
          //
1593
0
          BestLanguage = AllocateZeroPool (CompareLength + 1);
1594
0
          if (BestLanguage == NULL) {
1595
0
            return NULL;
1596
0
          }
1597
1598
0
          return CopyMem (BestLanguage, Supported, CompareLength);
1599
0
        }
1600
0
      }
1601
1602
0
      if (Iso639Language != 0) {
1603
        //
1604
        // If ISO 639 mode, then each language can only be tested once
1605
        //
1606
0
        LanguageLength = 0;
1607
0
      } else {
1608
        //
1609
        // If RFC 4646 mode, then trim Language from the right to the next '-' character
1610
        //
1611
0
        for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--) {
1612
0
        }
1613
0
      }
1614
0
    }
1615
0
  }
1616
1617
0
  VA_END (Args);
1618
1619
  //
1620
  // No matches were found
1621
  //
1622
0
  return NULL;
1623
0
}
1624
1625
/**
1626
  Returns an array of protocol instance that matches the given protocol.
1627
1628
  @param[in]  Protocol      Provides the protocol to search for.
1629
  @param[out] NoProtocols   The number of protocols returned in Buffer.
1630
  @param[out] Buffer        A pointer to the buffer to return the requested
1631
                            array of protocol instances that match Protocol.
1632
                            The returned buffer is allocated using
1633
                            EFI_BOOT_SERVICES.AllocatePool().  The caller is
1634
                            responsible for freeing this buffer with
1635
                            EFI_BOOT_SERVICES.FreePool().
1636
1637
  @retval EFI_SUCCESS            The array of protocols was returned in Buffer,
1638
                                 and the number of protocols in Buffer was
1639
                                 returned in NoProtocols.
1640
  @retval EFI_NOT_FOUND          No protocols found.
1641
  @retval EFI_OUT_OF_RESOURCES   There is not enough pool memory to store the
1642
                                 matching results.
1643
  @retval EFI_INVALID_PARAMETER  Protocol is NULL.
1644
  @retval EFI_INVALID_PARAMETER  NoProtocols is NULL.
1645
  @retval EFI_INVALID_PARAMETER  Buffer is NULL.
1646
1647
**/
1648
EFI_STATUS
1649
EFIAPI
1650
EfiLocateProtocolBuffer (
1651
  IN  EFI_GUID  *Protocol,
1652
  OUT UINTN     *NoProtocols,
1653
  OUT VOID      ***Buffer
1654
  )
1655
0
{
1656
0
  EFI_STATUS  Status;
1657
0
  UINTN       NoHandles;
1658
0
  EFI_HANDLE  *HandleBuffer;
1659
0
  UINTN       Index;
1660
1661
  //
1662
  // Check input parameters
1663
  //
1664
0
  if ((Protocol == NULL) || (NoProtocols == NULL) || (Buffer == NULL)) {
1665
0
    return EFI_INVALID_PARAMETER;
1666
0
  }
1667
1668
  //
1669
  // Initialze output parameters
1670
  //
1671
0
  *NoProtocols = 0;
1672
0
  *Buffer      = NULL;
1673
1674
  //
1675
  // Retrieve the array of handles that support Protocol
1676
  //
1677
0
  Status = gBS->LocateHandleBuffer (
1678
0
                  ByProtocol,
1679
0
                  Protocol,
1680
0
                  NULL,
1681
0
                  &NoHandles,
1682
0
                  &HandleBuffer
1683
0
                  );
1684
0
  if (EFI_ERROR (Status)) {
1685
0
    return Status;
1686
0
  }
1687
1688
  //
1689
  // Allocate array of protocol instances
1690
  //
1691
0
  Status = gBS->AllocatePool (
1692
0
                  EfiBootServicesData,
1693
0
                  NoHandles * sizeof (VOID *),
1694
0
                  (VOID **)Buffer
1695
0
                  );
1696
0
  if (EFI_ERROR (Status)) {
1697
    //
1698
    // Free the handle buffer
1699
    //
1700
0
    gBS->FreePool (HandleBuffer);
1701
0
    return EFI_OUT_OF_RESOURCES;
1702
0
  }
1703
1704
0
  ZeroMem (*Buffer, NoHandles * sizeof (VOID *));
1705
1706
  //
1707
  // Lookup Protocol on each handle in HandleBuffer to fill in the array of
1708
  // protocol instances.  Handle case where protocol instance was present when
1709
  // LocateHandleBuffer() was called, but is not present when HandleProtocol()
1710
  // is called.
1711
  //
1712
0
  for (Index = 0, *NoProtocols = 0; Index < NoHandles; Index++) {
1713
0
    Status = gBS->HandleProtocol (
1714
0
                    HandleBuffer[Index],
1715
0
                    Protocol,
1716
0
                    &((*Buffer)[*NoProtocols])
1717
0
                    );
1718
0
    if (!EFI_ERROR (Status)) {
1719
0
      (*NoProtocols)++;
1720
0
    }
1721
0
  }
1722
1723
  //
1724
  // Free the handle buffer
1725
  //
1726
0
  gBS->FreePool (HandleBuffer);
1727
1728
  //
1729
  // Make sure at least one protocol instance was found
1730
  //
1731
0
  if (*NoProtocols == 0) {
1732
0
    gBS->FreePool (*Buffer);
1733
0
    *Buffer = NULL;
1734
0
    return EFI_NOT_FOUND;
1735
0
  }
1736
1737
0
  return EFI_SUCCESS;
1738
0
}
1739
1740
/**
1741
  Open or create a file or directory, possibly creating the chain of
1742
  directories leading up to the directory.
1743
1744
  EfiOpenFileByDevicePath() first locates EFI_SIMPLE_FILE_SYSTEM_PROTOCOL on
1745
  FilePath, and opens the root directory of that filesystem with
1746
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume().
1747
1748
  On the remaining device path, the longest initial sequence of
1749
  FILEPATH_DEVICE_PATH nodes is node-wise traversed with
1750
  EFI_FILE_PROTOCOL.Open().
1751
1752
  (As a consequence, if OpenMode includes EFI_FILE_MODE_CREATE, and Attributes
1753
  includes EFI_FILE_DIRECTORY, and each FILEPATH_DEVICE_PATH specifies a single
1754
  pathname component, then EfiOpenFileByDevicePath() ensures that the specified
1755
  series of subdirectories exist on return.)
1756
1757
  The EFI_FILE_PROTOCOL identified by the last FILEPATH_DEVICE_PATH node is
1758
  output to the caller; intermediate EFI_FILE_PROTOCOL instances are closed. If
1759
  there are no FILEPATH_DEVICE_PATH nodes past the node that identifies the
1760
  filesystem, then the EFI_FILE_PROTOCOL of the root directory of the
1761
  filesystem is output to the caller. If a device path node that is different
1762
  from FILEPATH_DEVICE_PATH is encountered relative to the filesystem, the
1763
  traversal is stopped with an error, and a NULL EFI_FILE_PROTOCOL is output.
1764
1765
  @param[in,out] FilePath  On input, the device path to the file or directory
1766
                           to open or create. The caller is responsible for
1767
                           ensuring that the device path pointed-to by FilePath
1768
                           is well-formed. On output, FilePath points one past
1769
                           the last node in the original device path that has
1770
                           been successfully processed. FilePath is set on
1771
                           output even if EfiOpenFileByDevicePath() returns an
1772
                           error.
1773
1774
  @param[out] File         On error, File is set to NULL. On success, File is
1775
                           set to the EFI_FILE_PROTOCOL of the root directory
1776
                           of the filesystem, if there are no
1777
                           FILEPATH_DEVICE_PATH nodes in FilePath; otherwise,
1778
                           File is set to the EFI_FILE_PROTOCOL identified by
1779
                           the last node in FilePath.
1780
1781
  @param[in] OpenMode      The OpenMode parameter to pass to
1782
                           EFI_FILE_PROTOCOL.Open().
1783
1784
  @param[in] Attributes    The Attributes parameter to pass to
1785
                           EFI_FILE_PROTOCOL.Open().
1786
1787
  @retval EFI_SUCCESS            The file or directory has been opened or
1788
                                 created.
1789
1790
  @retval EFI_INVALID_PARAMETER  FilePath is NULL; or File is NULL; or FilePath
1791
                                 contains a device path node, past the node
1792
                                 that identifies
1793
                                 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, that is not a
1794
                                 FILEPATH_DEVICE_PATH node.
1795
1796
  @retval EFI_OUT_OF_RESOURCES   Memory allocation failed.
1797
1798
  @return                        Error codes propagated from the
1799
                                 LocateDevicePath() and OpenProtocol() boot
1800
                                 services, and from the
1801
                                 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume()
1802
                                 and EFI_FILE_PROTOCOL.Open() member functions.
1803
**/
1804
EFI_STATUS
1805
EFIAPI
1806
EfiOpenFileByDevicePath (
1807
  IN OUT EFI_DEVICE_PATH_PROTOCOL  **FilePath,
1808
  OUT    EFI_FILE_PROTOCOL         **File,
1809
  IN     UINT64                    OpenMode,
1810
  IN     UINT64                    Attributes
1811
  )
1812
0
{
1813
0
  EFI_STATUS                       Status;
1814
0
  EFI_HANDLE                       FileSystemHandle;
1815
0
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *FileSystem;
1816
0
  EFI_FILE_PROTOCOL                *LastFile;
1817
0
  FILEPATH_DEVICE_PATH             *FilePathNode;
1818
0
  CHAR16                           *AlignedPathName;
1819
0
  CHAR16                           *PathName;
1820
0
  EFI_FILE_PROTOCOL                *NextFile;
1821
1822
0
  if (File == NULL) {
1823
0
    return EFI_INVALID_PARAMETER;
1824
0
  }
1825
1826
0
  *File = NULL;
1827
1828
0
  if (FilePath == NULL) {
1829
0
    return EFI_INVALID_PARAMETER;
1830
0
  }
1831
1832
  //
1833
  // Look up the filesystem.
1834
  //
1835
0
  Status = gBS->LocateDevicePath (
1836
0
                  &gEfiSimpleFileSystemProtocolGuid,
1837
0
                  FilePath,
1838
0
                  &FileSystemHandle
1839
0
                  );
1840
0
  if (EFI_ERROR (Status)) {
1841
0
    return Status;
1842
0
  }
1843
1844
0
  Status = gBS->OpenProtocol (
1845
0
                  FileSystemHandle,
1846
0
                  &gEfiSimpleFileSystemProtocolGuid,
1847
0
                  (VOID **)&FileSystem,
1848
0
                  gImageHandle,
1849
0
                  NULL,
1850
0
                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
1851
0
                  );
1852
0
  if (EFI_ERROR (Status)) {
1853
0
    return Status;
1854
0
  }
1855
1856
  //
1857
  // Open the root directory of the filesystem. After this operation succeeds,
1858
  // we have to release LastFile on error.
1859
  //
1860
0
  Status = FileSystem->OpenVolume (FileSystem, &LastFile);
1861
0
  if (EFI_ERROR (Status)) {
1862
0
    return Status;
1863
0
  }
1864
1865
  //
1866
  // Traverse the device path nodes relative to the filesystem.
1867
  //
1868
0
  while (!IsDevicePathEnd (*FilePath)) {
1869
0
    if ((DevicePathType (*FilePath) != MEDIA_DEVICE_PATH) ||
1870
0
        (DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP))
1871
0
    {
1872
0
      Status = EFI_INVALID_PARAMETER;
1873
0
      goto CloseLastFile;
1874
0
    }
1875
1876
0
    FilePathNode = (FILEPATH_DEVICE_PATH *)*FilePath;
1877
1878
    //
1879
    // FilePathNode->PathName may be unaligned, and the UEFI specification
1880
    // requires pointers that are passed to protocol member functions to be
1881
    // aligned. Create an aligned copy of the pathname if necessary.
1882
    //
1883
0
    if ((UINTN)FilePathNode->PathName % sizeof *FilePathNode->PathName == 0) {
1884
0
      AlignedPathName = NULL;
1885
0
      PathName        = FilePathNode->PathName;
1886
0
    } else {
1887
0
      AlignedPathName = AllocateCopyPool (
1888
0
                          (DevicePathNodeLength (FilePathNode) -
1889
0
                           SIZE_OF_FILEPATH_DEVICE_PATH),
1890
0
                          FilePathNode->PathName
1891
0
                          );
1892
0
      if (AlignedPathName == NULL) {
1893
0
        Status = EFI_OUT_OF_RESOURCES;
1894
0
        goto CloseLastFile;
1895
0
      }
1896
1897
0
      PathName = AlignedPathName;
1898
0
    }
1899
1900
    //
1901
    // Open or create the file corresponding to the next pathname fragment.
1902
    //
1903
0
    Status = LastFile->Open (
1904
0
                         LastFile,
1905
0
                         &NextFile,
1906
0
                         PathName,
1907
0
                         OpenMode,
1908
0
                         Attributes
1909
0
                         );
1910
1911
    //
1912
    // Release any AlignedPathName on both error and success paths; PathName is
1913
    // no longer needed.
1914
    //
1915
0
    if (AlignedPathName != NULL) {
1916
0
      FreePool (AlignedPathName);
1917
0
    }
1918
1919
0
    if (EFI_ERROR (Status)) {
1920
0
      goto CloseLastFile;
1921
0
    }
1922
1923
    //
1924
    // Advance to the next device path node.
1925
    //
1926
0
    LastFile->Close (LastFile);
1927
0
    LastFile  = NextFile;
1928
0
    *FilePath = NextDevicePathNode (FilePathNode);
1929
0
  }
1930
1931
0
  *File = LastFile;
1932
0
  return EFI_SUCCESS;
1933
1934
0
CloseLastFile:
1935
0
  LastFile->Close (LastFile);
1936
1937
  //
1938
  // We are on the error path; we must have set an error Status for returning
1939
  // to the caller.
1940
  //
1941
0
  ASSERT (EFI_ERROR (Status));
1942
0
  return Status;
1943
0
}