1/** @file
2  Firmware Volume Block Driver for Lakeport Platform.
3
4  Firmware volume block driver for FWH or SPI device.
5  It depends on which Flash Device Library to be linked with this driver.
6
7Copyright (c) 2006  - 2014, Intel Corporation. All rights reserved.<BR>
8
9
10  This program and the accompanying materials are licensed and made available under
11
12  the terms and conditions of the BSD License that accompanies this distribution.
13
14  The full text of the license may be found at
15
16  http://opensource.org/licenses/bsd-license.php.
17
18
19
20  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
21
22  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23
24
25
26
27**/
28
29#include <PiDxe.h>
30#include <Library/UefiRuntimeLib.h>
31#include "FvbService.h"
32
33extern FWB_GLOBAL              mFvbModuleGlobal;
34
35/**
36  Call back function on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
37
38  Fixup internal data so that the driver is callable in EFI runtime
39  in virtual mode. Convert the mFvbModuleGlobal date items to there
40  virtual address.
41
42  @param  Event     Event whose notification function is being invoked.
43  @param  Context   The context of the Notification context. Not used in
44                    this call back function.
45
46**/
47VOID
48EFIAPI
49FvbVirtualddressChangeEvent (
50  IN EFI_EVENT                          Event,
51  IN VOID                               *Context
52  )
53{
54  EFI_FW_VOL_INSTANCE                   *FwhInstance;
55  UINTN                                 Index;
56
57  //
58  // Convert the base address of all the instances.
59  //
60  for (Index = 0; Index < mFvbModuleGlobal.NumFv; Index++) {
61    FwhInstance = GetFvbInstance (Index);
62    EfiConvertPointer (0, (VOID **) &FwhInstance->FvBase);
63  }
64
65  EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal.FvInstance);
66}
67
68
69/**
70  The function installs EFI_FIRMWARE_VOLUME_BLOCK protocol
71  for each FV in the system.
72
73  @param[in]  FwhInstance   The pointer to a FW volume instance structure,
74                            which contains the information about one FV.
75  @param[in]  InstanceNum   The instance number which can be used as a ID
76                            to locate this FwhInstance in other functions.
77
78  @retval     VOID
79
80**/
81VOID
82InstallFvbProtocol (
83  IN  EFI_FW_VOL_INSTANCE               *FwhInstance,
84  IN  UINTN                             InstanceNum
85  )
86{
87  EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;
88  EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
89  EFI_STATUS                            Status;
90  EFI_HANDLE                            FwbHandle;
91  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *OldFwbInterface;
92
93  FvbDevice = (EFI_FW_VOL_BLOCK_DEVICE *) AllocateRuntimeCopyPool (
94                                            sizeof (EFI_FW_VOL_BLOCK_DEVICE),
95                                            &mFvbDeviceTemplate
96                                            );
97  ASSERT (FvbDevice != NULL);
98
99  FvbDevice->Instance = InstanceNum;
100  FwVolHeader = &FwhInstance->VolumeHeader;
101
102  //
103  // Set up the devicepath.
104  //
105  DEBUG ((EFI_D_INFO, "FwBlockService.c: Setting up DevicePath for 0x%lx:\n", FwhInstance->FvBase));
106  if (FwVolHeader->ExtHeaderOffset == 0) {
107    //
108    // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH.
109    //
110    FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
111    ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = FwhInstance->FvBase;
112    ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.EndingAddress   = FwhInstance->FvBase + FwVolHeader->FvLength - 1;
113  } else {
114    FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
115    CopyGuid (
116      &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName,
117      (GUID *)(UINTN)(FwhInstance->FvBase + FwVolHeader->ExtHeaderOffset)
118      );
119  }
120
121  //
122  // Find a handle with a matching device path that has supports FW Block protocol.
123  //
124  Status = gBS->LocateDevicePath (
125                  &gEfiFirmwareVolumeBlockProtocolGuid,
126                  &FvbDevice->DevicePath,
127                  &FwbHandle
128                  );
129  if (EFI_ERROR (Status) ) {
130    //
131    // LocateDevicePath fails so install a new interface and device path.
132    //
133    DEBUG ((EFI_D_INFO, "FwBlockService.c: LocateDevicePath failed, install new interface 0x%lx:\n", FwhInstance->FvBase));
134    FwbHandle = NULL;
135    Status =  gBS->InstallMultipleProtocolInterfaces (
136                     &FwbHandle,
137                     &gEfiFirmwareVolumeBlockProtocolGuid,
138                     &FvbDevice->FwVolBlockInstance,
139                     &gEfiDevicePathProtocolGuid,
140                     FvbDevice->DevicePath,
141                     NULL
142                     );
143    ASSERT_EFI_ERROR (Status);
144    DEBUG ((EFI_D_INFO, "FwBlockService.c: IMPI FirmwareVolBlockProt, DevPath 0x%lx: %r\n", FwhInstance->FvBase, Status));
145
146  } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {
147    //
148    // Device allready exists, so reinstall the FVB protocol.
149    //
150    DEBUG ((EFI_D_ERROR, "FwBlockService.c: LocateDevicePath succeeded, reinstall interface 0x%lx:\n", FwhInstance->FvBase));
151    Status = gBS->HandleProtocol (
152                    FwbHandle,
153                    &gEfiFirmwareVolumeBlockProtocolGuid,
154                    (VOID **) &OldFwbInterface
155                    );
156    ASSERT_EFI_ERROR (Status);
157
158    Status =  gBS->ReinstallProtocolInterface (
159                     FwbHandle,
160                     &gEfiFirmwareVolumeBlockProtocolGuid,
161                     OldFwbInterface,
162                     &FvbDevice->FwVolBlockInstance
163                     );
164    ASSERT_EFI_ERROR (Status);
165
166  } else {
167    //
168    // There was a FVB protocol on an End Device Path node.
169    //
170    ASSERT (FALSE);
171  }
172
173}
174
175
176/**
177  The driver entry point for Firmware Volume Block Driver.
178
179  The function does the necessary initialization work for
180  Firmware Volume Block Driver.
181
182  @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.
183  @param[in]  SystemTable       A pointer to the EFI system table.
184
185  @retval     EFI_SUCCESS       This funtion always return EFI_SUCCESS.
186                                It will ASSERT on errors.
187
188**/
189EFI_STATUS
190EFIAPI
191DxeFvbInitialize (
192  IN EFI_HANDLE                         ImageHandle,
193  IN EFI_SYSTEM_TABLE                   *SystemTable
194  )
195{
196  EFI_STATUS                            Status;
197  EFI_EVENT                             Event;
198
199  Status = gBS->CreateEventEx (
200                  EVT_NOTIFY_SIGNAL,
201                  TPL_NOTIFY,
202                  FvbVirtualddressChangeEvent,
203                  NULL,
204                  &gEfiEventVirtualAddressChangeGuid,
205                  &Event
206                  );
207  ASSERT_EFI_ERROR (Status);
208
209  FvbInitialize ();
210
211  return EFI_SUCCESS;
212}
213
214