1 /** @file
2   This driver produce a BlockIo protocol instance for a Xen PV block device.
3 
4   This driver support XenBus protocol of type 'vbd'. Every function that
5   comsume XenBus protocol are in BlockFront, which the implementation to access
6   a Xen PV device. The BlockIo implementation is in it's one file and will call
7   BlockFront functions.
8 
9   Copyright (C) 2014, Citrix Ltd.
10 
11   This program and the accompanying materials
12   are licensed and made available under the terms and conditions of the BSD License
13   which accompanies this distribution.  The full text of the license may be found at
14   http://opensource.org/licenses/bsd-license.php
15 
16   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
17   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 
19 **/
20 
21 #include "XenPvBlkDxe.h"
22 
23 #include "BlockFront.h"
24 
25 
26 ///
27 /// Driver Binding Protocol instance
28 ///
29 EFI_DRIVER_BINDING_PROTOCOL gXenPvBlkDxeDriverBinding = {
30   XenPvBlkDxeDriverBindingSupported,
31   XenPvBlkDxeDriverBindingStart,
32   XenPvBlkDxeDriverBindingStop,
33   XEN_PV_BLK_DXE_VERSION,
34   NULL,
35   NULL
36 };
37 
38 
39 /**
40   Unloads an image.
41 
42   @param  ImageHandle           Handle that identifies the image to be unloaded.
43 
44   @retval EFI_SUCCESS           The image has been unloaded.
45   @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
46 
47 **/
48 EFI_STATUS
49 EFIAPI
XenPvBlkDxeUnload(IN EFI_HANDLE ImageHandle)50 XenPvBlkDxeUnload (
51   IN EFI_HANDLE  ImageHandle
52   )
53 {
54   EFI_STATUS  Status;
55 
56   EFI_HANDLE  *HandleBuffer;
57   UINTN       HandleCount;
58   UINTN       Index;
59 
60 
61   //
62   // Retrieve array of all handles in the handle database
63   //
64   Status = gBS->LocateHandleBuffer (
65                   AllHandles,
66                   NULL,
67                   NULL,
68                   &HandleCount,
69                   &HandleBuffer
70                   );
71   if (EFI_ERROR (Status)) {
72     return Status;
73   }
74 
75   //
76   // Disconnect the current driver from handles in the handle database
77   //
78   for (Index = 0; Index < HandleCount; Index++) {
79     gBS->DisconnectController (HandleBuffer[Index], gImageHandle, NULL);
80   }
81 
82   //
83   // Free the array of handles
84   //
85   FreePool (HandleBuffer);
86 
87 
88   //
89   // Uninstall protocols installed in the driver entry point
90   //
91   Status = gBS->UninstallMultipleProtocolInterfaces (
92                   ImageHandle,
93                   &gEfiDriverBindingProtocolGuid, &gXenPvBlkDxeDriverBinding,
94                   &gEfiComponentNameProtocolGuid,  &gXenPvBlkDxeComponentName,
95                   &gEfiComponentName2ProtocolGuid, &gXenPvBlkDxeComponentName2,
96                   NULL
97                   );
98   if (EFI_ERROR (Status)) {
99     return Status;
100   }
101 
102   return EFI_SUCCESS;
103 }
104 
105 /**
106   This is the declaration of an EFI image entry point. This entry point is
107   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
108   both device drivers and bus drivers.
109 
110   @param  ImageHandle           The firmware allocated handle for the UEFI image.
111   @param  SystemTable           A pointer to the EFI System Table.
112 
113   @retval EFI_SUCCESS           The operation completed successfully.
114   @retval Others                An unexpected error occurred.
115 **/
116 EFI_STATUS
117 EFIAPI
XenPvBlkDxeDriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)118 XenPvBlkDxeDriverEntryPoint (
119   IN EFI_HANDLE        ImageHandle,
120   IN EFI_SYSTEM_TABLE  *SystemTable
121   )
122 {
123   EFI_STATUS  Status;
124 
125   //
126   // Install UEFI Driver Model protocol(s).
127   //
128   Status = EfiLibInstallDriverBindingComponentName2 (
129              ImageHandle,
130              SystemTable,
131              &gXenPvBlkDxeDriverBinding,
132              ImageHandle,
133              &gXenPvBlkDxeComponentName,
134              &gXenPvBlkDxeComponentName2
135              );
136   ASSERT_EFI_ERROR (Status);
137 
138   return Status;
139 }
140 
141 
142 /**
143   Tests to see if this driver supports a given controller. If a child device is provided,
144   it further tests to see if this driver supports creating a handle for the specified child device.
145 
146   This function checks to see if the driver specified by This supports the device specified by
147   ControllerHandle. Drivers will typically use the device path attached to
148   ControllerHandle and/or the services from the bus I/O abstraction attached to
149   ControllerHandle to determine if the driver supports ControllerHandle. This function
150   may be called many times during platform initialization. In order to reduce boot times, the tests
151   performed by this function must be very small, and take as little time as possible to execute. This
152   function must not change the state of any hardware devices, and this function must be aware that the
153   device specified by ControllerHandle may already be managed by the same driver or a
154   different driver. This function must match its calls to AllocatePages() with FreePages(),
155   AllocatePool() with FreePool(), and OpenProtocol() with CloseProtocol().
156   Because ControllerHandle may have been previously started by the same driver, if a protocol is
157   already in the opened state, then it must not be closed with CloseProtocol(). This is required
158   to guarantee the state of ControllerHandle is not modified by this function.
159 
160   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
161   @param[in]  ControllerHandle     The handle of the controller to test. This handle
162                                    must support a protocol interface that supplies
163                                    an I/O abstraction to the driver.
164   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
165                                    parameter is ignored by device drivers, and is optional for bus
166                                    drivers. For bus drivers, if this parameter is not NULL, then
167                                    the bus driver must determine if the bus controller specified
168                                    by ControllerHandle and the child controller specified
169                                    by RemainingDevicePath are both supported by this
170                                    bus driver.
171 
172   @retval EFI_SUCCESS              The device specified by ControllerHandle and
173                                    RemainingDevicePath is supported by the driver specified by This.
174   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
175                                    RemainingDevicePath is already being managed by the driver
176                                    specified by This.
177   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
178                                    RemainingDevicePath is already being managed by a different
179                                    driver or an application that requires exclusive access.
180                                    Currently not implemented.
181   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
182                                    RemainingDevicePath is not supported by the driver specified by This.
183 **/
184 EFI_STATUS
185 EFIAPI
XenPvBlkDxeDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)186 XenPvBlkDxeDriverBindingSupported (
187   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
188   IN EFI_HANDLE                   ControllerHandle,
189   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
190   )
191 {
192   EFI_STATUS Status;
193   XENBUS_PROTOCOL *XenBusIo;
194 
195   Status = gBS->OpenProtocol (
196                 ControllerHandle,
197                 &gXenBusProtocolGuid,
198                 (VOID **)&XenBusIo,
199                 This->DriverBindingHandle,
200                 ControllerHandle,
201                 EFI_OPEN_PROTOCOL_BY_DRIVER
202                 );
203   if (EFI_ERROR (Status)) {
204     return Status;
205   }
206   if (AsciiStrCmp (XenBusIo->Type, "vbd") == 0) {
207     Status = EFI_SUCCESS;
208   } else {
209     Status = EFI_UNSUPPORTED;
210   }
211 
212   gBS->CloseProtocol (ControllerHandle, &gXenBusProtocolGuid,
213                       This->DriverBindingHandle, ControllerHandle);
214 
215   return Status;
216 }
217 
218 /**
219   Starts a device controller.
220 
221   The Start() function is designed to be invoked from the EFI boot service ConnectController().
222   As a result, much of the error checking on the parameters to Start() has been moved into this
223   common boot service. It is legal to call Start() from other locations,
224   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
225   1. ControllerHandle must be a valid EFI_HANDLE.
226   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
227      EFI_DEVICE_PATH_PROTOCOL.
228   3. Prior to calling Start(), the Supported() function for the driver specified by This must
229      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
230 
231   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
232   @param[in]  ControllerHandle     The handle of the controller to start. This handle
233                                    must support a protocol interface that supplies
234                                    an I/O abstraction to the driver.
235   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
236                                    parameter is ignored by device drivers, and is optional for bus
237                                    drivers. For a bus driver, if this parameter is NULL, then handles
238                                    for all the children of Controller are created by this driver.
239                                    If this parameter is not NULL and the first Device Path Node is
240                                    not the End of Device Path Node, then only the handle for the
241                                    child device specified by the first Device Path Node of
242                                    RemainingDevicePath is created by this driver.
243                                    If the first Device Path Node of RemainingDevicePath is
244                                    the End of Device Path Node, no child handle is created by this
245                                    driver.
246 
247   @retval EFI_SUCCESS              The device was started.
248   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
249   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
250   @retval Others                   The driver failded to start the device.
251 
252 **/
253 EFI_STATUS
254 EFIAPI
XenPvBlkDxeDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)255 XenPvBlkDxeDriverBindingStart (
256   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
257   IN EFI_HANDLE                   ControllerHandle,
258   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
259   )
260 {
261   EFI_STATUS Status;
262   XENBUS_PROTOCOL *XenBusIo;
263   XEN_BLOCK_FRONT_DEVICE *Dev;
264   EFI_BLOCK_IO_MEDIA *Media;
265 
266   Status = gBS->OpenProtocol (
267                 ControllerHandle,
268                 &gXenBusProtocolGuid,
269                 (VOID **)&XenBusIo,
270                 This->DriverBindingHandle,
271                 ControllerHandle,
272                 EFI_OPEN_PROTOCOL_BY_DRIVER
273                 );
274   if (EFI_ERROR (Status)) {
275     return Status;
276   }
277 
278   Status = XenPvBlockFrontInitialization (XenBusIo, XenBusIo->Node, &Dev);
279   if (EFI_ERROR (Status)) {
280     goto CloseProtocol;
281   }
282 
283   CopyMem (&Dev->BlockIo, &gXenPvBlkDxeBlockIo, sizeof (EFI_BLOCK_IO_PROTOCOL));
284   Media = AllocateCopyPool (sizeof (EFI_BLOCK_IO_MEDIA),
285                             &gXenPvBlkDxeBlockIoMedia);
286   if (Dev->MediaInfo.VDiskInfo & VDISK_REMOVABLE) {
287     Media->RemovableMedia = TRUE;
288   }
289   Media->MediaPresent = TRUE;
290   Media->ReadOnly = !Dev->MediaInfo.ReadWrite;
291   if (Dev->MediaInfo.CdRom) {
292     //
293     // If it's a cdrom, the blocksize value need to be 2048 for OVMF to
294     // recognize it as a cdrom:
295     //    MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c
296     //
297     Media->BlockSize = 2048;
298     Media->LastBlock = DivU64x32 (Dev->MediaInfo.Sectors,
299                                   Media->BlockSize / Dev->MediaInfo.SectorSize) - 1;
300   } else {
301     Media->BlockSize = Dev->MediaInfo.SectorSize;
302     Media->LastBlock = Dev->MediaInfo.Sectors - 1;
303   }
304   ASSERT (Media->BlockSize % 512 == 0);
305   Dev->BlockIo.Media = Media;
306 
307   Status = gBS->InstallMultipleProtocolInterfaces (
308                     &ControllerHandle,
309                     &gEfiBlockIoProtocolGuid, &Dev->BlockIo,
310                     NULL
311                     );
312   if (EFI_ERROR (Status)) {
313     DEBUG ((EFI_D_ERROR, "XenPvBlk: install protocol fail: %r\n", Status));
314     goto UninitBlockFront;
315   }
316 
317   return EFI_SUCCESS;
318 
319 UninitBlockFront:
320   FreePool (Media);
321   XenPvBlockFrontShutdown (Dev);
322 CloseProtocol:
323   gBS->CloseProtocol (ControllerHandle, &gXenBusProtocolGuid,
324                       This->DriverBindingHandle, ControllerHandle);
325   return Status;
326 }
327 
328 /**
329   Stops a device controller.
330 
331   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
332   As a result, much of the error checking on the parameters to Stop() has been moved
333   into this common boot service. It is legal to call Stop() from other locations,
334   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
335   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
336      same driver's Start() function.
337   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
338      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
339      Start() function, and the Start() function must have called OpenProtocol() on
340      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
341 
342   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
343   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
344                                 support a bus specific I/O protocol for the driver
345                                 to use to stop the device.
346   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
347   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
348                                 if NumberOfChildren is 0.
349 
350   @retval EFI_SUCCESS           The device was stopped.
351   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
352 
353 **/
354 EFI_STATUS
355 EFIAPI
XenPvBlkDxeDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)356 XenPvBlkDxeDriverBindingStop (
357   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
358   IN EFI_HANDLE                   ControllerHandle,
359   IN UINTN                        NumberOfChildren,
360   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
361   )
362 {
363   EFI_BLOCK_IO_PROTOCOL *BlockIo;
364   XEN_BLOCK_FRONT_DEVICE *Dev;
365   EFI_BLOCK_IO_MEDIA *Media;
366   EFI_STATUS Status;
367 
368   Status = gBS->OpenProtocol (
369                   ControllerHandle, &gEfiBlockIoProtocolGuid,
370                   (VOID **)&BlockIo,
371                   This->DriverBindingHandle, ControllerHandle,
372                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
373                   );
374   if (EFI_ERROR (Status)) {
375     return Status;
376   }
377 
378   Status = gBS->UninstallProtocolInterface (ControllerHandle,
379                   &gEfiBlockIoProtocolGuid, BlockIo);
380   if (EFI_ERROR (Status)) {
381     return Status;
382   }
383 
384   Media = BlockIo->Media;
385   Dev = XEN_BLOCK_FRONT_FROM_BLOCK_IO (BlockIo);
386   XenPvBlockFrontShutdown (Dev);
387 
388   FreePool (Media);
389 
390   gBS->CloseProtocol (ControllerHandle, &gXenBusProtocolGuid,
391          This->DriverBindingHandle, ControllerHandle);
392 
393   return EFI_SUCCESS;
394 }
395