1/** @file
2
3  Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
4
5  This program and the accompanying materials
6  are licensed and made available under the terms and conditions of the BSD License
7  which accompanies this distribution.  The full text of the license may be found at
8  http://opensource.org/licenses/bsd-license.php.
9
10  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include <Uefi.h>
16
17#include <Library/MemoryAllocationLib.h>
18#include <Library/UefiBootServicesTableLib.h>
19#include <Library/BaseMemoryLib.h>
20#include <Library/DebugLib.h>
21#include <Library/QemuFwCfgLib.h>
22#include <Protocol/LockBox.h>
23#include <LockBoxLib.h>
24
25/**
26  Allocate memory below 4G memory address.
27
28  This function allocates memory below 4G memory address.
29
30  @param  MemoryType   Memory type of memory to allocate.
31  @param  Size         Size of memory to allocate.
32
33  @return Allocated address for output.
34
35**/
36STATIC
37VOID *
38AllocateMemoryBelow4G (
39  IN EFI_MEMORY_TYPE    MemoryType,
40  IN UINTN              Size
41  )
42{
43  UINTN                 Pages;
44  EFI_PHYSICAL_ADDRESS  Address;
45  EFI_STATUS            Status;
46  VOID*                 Buffer;
47  UINTN                 AllocRemaining;
48
49  Pages = EFI_SIZE_TO_PAGES (Size);
50  Address = 0xffffffff;
51
52  //
53  // Since we need to use gBS->AllocatePages to get a buffer below
54  // 4GB, there is a good chance that space will be wasted for very
55  // small allocation. We keep track of unused portions of the page
56  // allocations, and use these to allocate memory for small buffers.
57  //
58  ASSERT (mLockBoxGlobal->Signature == LOCK_BOX_GLOBAL_SIGNATURE);
59  if ((UINTN) mLockBoxGlobal->SubPageRemaining >= Size) {
60    Buffer = (VOID*)(UINTN) mLockBoxGlobal->SubPageBuffer;
61    mLockBoxGlobal->SubPageBuffer += (UINT32) Size;
62    mLockBoxGlobal->SubPageRemaining -= (UINT32) Size;
63    return Buffer;
64  }
65
66  Status  = gBS->AllocatePages (
67                   AllocateMaxAddress,
68                   MemoryType,
69                   Pages,
70                   &Address
71                   );
72  if (EFI_ERROR (Status)) {
73    return NULL;
74  }
75
76  Buffer = (VOID *) (UINTN) Address;
77  ZeroMem (Buffer, EFI_PAGES_TO_SIZE (Pages));
78
79  AllocRemaining = EFI_PAGES_TO_SIZE (Pages) - Size;
80  if (AllocRemaining > (UINTN) mLockBoxGlobal->SubPageRemaining) {
81    mLockBoxGlobal->SubPageBuffer = (UINT32) (Address + Size);
82    mLockBoxGlobal->SubPageRemaining = (UINT32) AllocRemaining;
83  }
84
85  return Buffer;
86}
87
88
89/**
90  Allocates a buffer of type EfiACPIMemoryNVS.
91
92  Allocates the number bytes specified by AllocationSize of type
93  EfiACPIMemoryNVS and returns a pointer to the allocated buffer.
94  If AllocationSize is 0, then a valid buffer of 0 size is
95  returned.  If there is not enough memory remaining to satisfy
96  the request, then NULL is returned.
97
98  @param  AllocationSize        The number of bytes to allocate.
99
100  @return A pointer to the allocated buffer or NULL if allocation fails.
101
102**/
103VOID *
104EFIAPI
105AllocateAcpiNvsPool (
106  IN UINTN  AllocationSize
107  )
108{
109  return AllocateMemoryBelow4G (EfiACPIMemoryNVS, AllocationSize);
110}
111
112
113EFI_STATUS
114EFIAPI
115LockBoxDxeLibInitialize (
116  IN EFI_HANDLE        ImageHandle,
117  IN EFI_SYSTEM_TABLE  *SystemTable
118  )
119{
120  EFI_STATUS    Status;
121  VOID          *Interface;
122
123  Status = LockBoxLibInitialize ();
124  if (!EFI_ERROR (Status)) {
125    if (QemuFwCfgS3Enabled ()) {
126      //
127      // When S3 enabled, the first driver run with this library linked will
128      // have this library constructor to install LockBox protocol on the
129      // ImageHandle. As other drivers may have gEfiLockBoxProtocolGuid
130      // dependency, the first driver should run before them.
131      //
132      Status = gBS->LocateProtocol (&gEfiLockBoxProtocolGuid, NULL, &Interface);
133      if (EFI_ERROR (Status)) {
134        Status = gBS->InstallProtocolInterface (
135                        &ImageHandle,
136                        &gEfiLockBoxProtocolGuid,
137                        EFI_NATIVE_INTERFACE,
138                        NULL
139                        );
140        ASSERT_EFI_ERROR (Status);
141      }
142    }
143  }
144
145  return Status;
146}
147