1 /** @file
2   Produce EFI_BLOCK_IO_PROTOCOL on a RAM disk device.
3 
4   Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
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 "RamDiskImpl.h"
16 
17 //
18 // The EFI_BLOCK_IO_PROTOCOL instances that is installed onto the handle
19 // for newly registered RAM disks
20 //
21 EFI_BLOCK_IO_PROTOCOL  mRamDiskBlockIoTemplate = {
22   EFI_BLOCK_IO_PROTOCOL_REVISION,
23   (EFI_BLOCK_IO_MEDIA *) 0,
24   RamDiskBlkIoReset,
25   RamDiskBlkIoReadBlocks,
26   RamDiskBlkIoWriteBlocks,
27   RamDiskBlkIoFlushBlocks
28 };
29 
30 //
31 // The EFI_BLOCK_IO_PROTOCOL2 instances that is installed onto the handle
32 // for newly registered RAM disks
33 //
34 EFI_BLOCK_IO2_PROTOCOL  mRamDiskBlockIo2Template = {
35   (EFI_BLOCK_IO_MEDIA *) 0,
36   RamDiskBlkIo2Reset,
37   RamDiskBlkIo2ReadBlocksEx,
38   RamDiskBlkIo2WriteBlocksEx,
39   RamDiskBlkIo2FlushBlocksEx
40 };
41 
42 
43 /**
44   Initialize the BlockIO & BlockIO2 protocol of a RAM disk device.
45 
46   @param[in] PrivateData     Points to RAM disk private data.
47 
48 **/
49 VOID
RamDiskInitBlockIo(IN RAM_DISK_PRIVATE_DATA * PrivateData)50 RamDiskInitBlockIo (
51   IN     RAM_DISK_PRIVATE_DATA    *PrivateData
52   )
53 {
54   EFI_BLOCK_IO_PROTOCOL           *BlockIo;
55   EFI_BLOCK_IO2_PROTOCOL          *BlockIo2;
56   EFI_BLOCK_IO_MEDIA              *Media;
57 
58   BlockIo  = &PrivateData->BlockIo;
59   BlockIo2 = &PrivateData->BlockIo2;
60   Media    = &PrivateData->Media;
61 
62   CopyMem (BlockIo, &mRamDiskBlockIoTemplate, sizeof (EFI_BLOCK_IO_PROTOCOL));
63   CopyMem (BlockIo2, &mRamDiskBlockIo2Template, sizeof (EFI_BLOCK_IO2_PROTOCOL));
64 
65   BlockIo->Media          = Media;
66   BlockIo2->Media         = Media;
67   Media->RemovableMedia   = FALSE;
68   Media->MediaPresent     = TRUE;
69   Media->LogicalPartition = FALSE;
70   Media->ReadOnly         = FALSE;
71   Media->WriteCaching     = FALSE;
72   Media->BlockSize        = RAM_DISK_BLOCK_SIZE;
73   Media->LastBlock        = DivU64x32 (
74                               PrivateData->Size + RAM_DISK_BLOCK_SIZE - 1,
75                               RAM_DISK_BLOCK_SIZE
76                               ) - 1;
77 }
78 
79 
80 /**
81   Reset the Block Device.
82 
83   @param  This                 Indicates a pointer to the calling context.
84   @param  ExtendedVerification Driver may perform diagnostics on reset.
85 
86   @retval EFI_SUCCESS          The device was reset.
87   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
88                                not be reset.
89 
90 **/
91 EFI_STATUS
92 EFIAPI
RamDiskBlkIoReset(IN EFI_BLOCK_IO_PROTOCOL * This,IN BOOLEAN ExtendedVerification)93 RamDiskBlkIoReset (
94   IN EFI_BLOCK_IO_PROTOCOL        *This,
95   IN BOOLEAN                      ExtendedVerification
96   )
97 {
98   return EFI_SUCCESS;
99 }
100 
101 
102 /**
103   Read BufferSize bytes from Lba into Buffer.
104 
105   @param[in]  This           Indicates a pointer to the calling context.
106   @param[in]  MediaId        Id of the media, changes every time the media is
107                              replaced.
108   @param[in]  Lba            The starting Logical Block Address to read from.
109   @param[in]  BufferSize     Size of Buffer, must be a multiple of device block
110                              size.
111   @param[out] Buffer         A pointer to the destination buffer for the data.
112                              The caller is responsible for either having
113                              implicit or explicit ownership of the buffer.
114 
115   @retval EFI_SUCCESS             The data was read correctly from the device.
116   @retval EFI_DEVICE_ERROR        The device reported an error while performing
117                                   the read.
118   @retval EFI_NO_MEDIA            There is no media in the device.
119   @retval EFI_MEDIA_CHANGED       The MediaId does not matched the current
120                                   device.
121   @retval EFI_BAD_BUFFER_SIZE     The Buffer was not a multiple of the block
122                                   size of the device.
123   @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not
124                                   valid, or the buffer is not on proper alignment.
125 
126 **/
127 EFI_STATUS
128 EFIAPI
RamDiskBlkIoReadBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,OUT VOID * Buffer)129 RamDiskBlkIoReadBlocks (
130   IN EFI_BLOCK_IO_PROTOCOL        *This,
131   IN UINT32                       MediaId,
132   IN EFI_LBA                      Lba,
133   IN UINTN                        BufferSize,
134   OUT VOID                        *Buffer
135   )
136 {
137   RAM_DISK_PRIVATE_DATA           *PrivateData;
138   UINTN                           NumberOfBlocks;
139 
140   if (Buffer == NULL) {
141     return EFI_INVALID_PARAMETER;
142   }
143 
144   if (BufferSize == 0) {
145     return EFI_SUCCESS;
146   }
147 
148   PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This);
149 
150   if (MediaId != PrivateData->Media.MediaId) {
151     return EFI_MEDIA_CHANGED;
152   }
153 
154   if ((BufferSize % PrivateData->Media.BlockSize) != 0) {
155     return EFI_BAD_BUFFER_SIZE;
156   }
157 
158   if (Lba > PrivateData->Media.LastBlock) {
159     return EFI_INVALID_PARAMETER;
160   }
161 
162   NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize;
163   if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) {
164     return EFI_INVALID_PARAMETER;
165   }
166 
167   CopyMem (
168     Buffer,
169     (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)),
170     BufferSize
171     );
172 
173   return EFI_SUCCESS;
174 }
175 
176 
177 /**
178   Write BufferSize bytes from Lba into Buffer.
179 
180   @param[in] This            Indicates a pointer to the calling context.
181   @param[in] MediaId         The media ID that the write request is for.
182   @param[in] Lba             The starting logical block address to be written.
183                              The caller is responsible for writing to only
184                              legitimate locations.
185   @param[in] BufferSize      Size of Buffer, must be a multiple of device block
186                              size.
187   @param[in] Buffer          A pointer to the source buffer for the data.
188 
189   @retval EFI_SUCCESS             The data was written correctly to the device.
190   @retval EFI_WRITE_PROTECTED     The device can not be written to.
191   @retval EFI_DEVICE_ERROR        The device reported an error while performing
192                                   the write.
193   @retval EFI_NO_MEDIA            There is no media in the device.
194   @retval EFI_MEDIA_CHNAGED       The MediaId does not matched the current
195                                   device.
196   @retval EFI_BAD_BUFFER_SIZE     The Buffer was not a multiple of the block
197                                   size of the device.
198   @retval EFI_INVALID_PARAMETER   The write request contains LBAs that are not
199                                   valid, or the buffer is not on proper alignment.
200 
201 **/
202 EFI_STATUS
203 EFIAPI
RamDiskBlkIoWriteBlocks(IN EFI_BLOCK_IO_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN UINTN BufferSize,IN VOID * Buffer)204 RamDiskBlkIoWriteBlocks (
205   IN EFI_BLOCK_IO_PROTOCOL        *This,
206   IN UINT32                       MediaId,
207   IN EFI_LBA                      Lba,
208   IN UINTN                        BufferSize,
209   IN VOID                         *Buffer
210   )
211 {
212   RAM_DISK_PRIVATE_DATA           *PrivateData;
213   UINTN                           NumberOfBlocks;
214 
215   if (Buffer == NULL) {
216     return EFI_INVALID_PARAMETER;
217   }
218 
219   if (BufferSize == 0) {
220     return EFI_SUCCESS;
221   }
222 
223   PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO (This);
224 
225   if (MediaId != PrivateData->Media.MediaId) {
226     return EFI_MEDIA_CHANGED;
227   }
228 
229   if (TRUE == PrivateData->Media.ReadOnly) {
230     return EFI_WRITE_PROTECTED;
231   }
232 
233   if ((BufferSize % PrivateData->Media.BlockSize) != 0) {
234     return EFI_BAD_BUFFER_SIZE;
235   }
236 
237   if (Lba > PrivateData->Media.LastBlock) {
238     return EFI_INVALID_PARAMETER;
239   }
240 
241   NumberOfBlocks = BufferSize / PrivateData->Media.BlockSize;
242   if ((Lba + NumberOfBlocks - 1) > PrivateData->Media.LastBlock) {
243     return EFI_INVALID_PARAMETER;
244   }
245 
246   CopyMem (
247     (VOID *)(UINTN)(PrivateData->StartingAddr + MultU64x32 (Lba, PrivateData->Media.BlockSize)),
248     Buffer,
249     BufferSize
250     );
251 
252   return EFI_SUCCESS;
253 }
254 
255 
256 /**
257   Flush the Block Device.
258 
259   @param[in] This            Indicates a pointer to the calling context.
260 
261   @retval EFI_SUCCESS             All outstanding data was written to the device.
262   @retval EFI_DEVICE_ERROR        The device reported an error while writting
263                                   back the data
264   @retval EFI_NO_MEDIA            There is no media in the device.
265 
266 **/
267 EFI_STATUS
268 EFIAPI
RamDiskBlkIoFlushBlocks(IN EFI_BLOCK_IO_PROTOCOL * This)269 RamDiskBlkIoFlushBlocks (
270   IN EFI_BLOCK_IO_PROTOCOL        *This
271   )
272 {
273   return EFI_SUCCESS;
274 }
275 
276 
277 /**
278   Resets the block device hardware.
279 
280   @param[in] This                 The pointer of EFI_BLOCK_IO2_PROTOCOL.
281   @param[in] ExtendedVerification The flag about if extend verificate.
282 
283   @retval EFI_SUCCESS             The device was reset.
284   @retval EFI_DEVICE_ERROR        The block device is not functioning correctly
285                                   and could not be reset.
286 
287 **/
288 EFI_STATUS
289 EFIAPI
RamDiskBlkIo2Reset(IN EFI_BLOCK_IO2_PROTOCOL * This,IN BOOLEAN ExtendedVerification)290 RamDiskBlkIo2Reset (
291   IN EFI_BLOCK_IO2_PROTOCOL       *This,
292   IN BOOLEAN                      ExtendedVerification
293   )
294 {
295   return EFI_SUCCESS;
296 }
297 
298 
299 /**
300   Reads the requested number of blocks from the device.
301 
302   @param[in]      This            Indicates a pointer to the calling context.
303   @param[in]      MediaId         The media ID that the read request is for.
304   @param[in]      Lba             The starting logical block address to read
305                                   from on the device.
306   @param[in, out] Token           A pointer to the token associated with the
307                                   transaction.
308   @param[in]      BufferSize      The size of the Buffer in bytes. This must be
309                                   a multiple of the intrinsic block size of the
310                                   device.
311   @param[out]     Buffer          A pointer to the destination buffer for the
312                                   data. The caller is responsible for either
313                                   having implicit or explicit ownership of the
314                                   buffer.
315 
316   @retval EFI_SUCCESS             The read request was queued if Token->Event
317                                   is not NULL. The data was read correctly from
318                                   the device if the Token->Event is NULL.
319   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
320                                   to perform the read operation.
321   @retval EFI_NO_MEDIA            There is no media in the device.
322   @retval EFI_MEDIA_CHANGED       The MediaId is not for the current media.
323   @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
324                                   the intrinsic block size of the device.
325   @retval EFI_INVALID_PARAMETER   The read request contains LBAs that are not
326                                   valid, or the buffer is not on proper
327                                   alignment.
328   @retval EFI_OUT_OF_RESOURCES    The request could not be completed due to a
329                                   lack of resources.
330 
331 **/
332 EFI_STATUS
333 EFIAPI
RamDiskBlkIo2ReadBlocksEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN OUT EFI_BLOCK_IO2_TOKEN * Token,IN UINTN BufferSize,OUT VOID * Buffer)334 RamDiskBlkIo2ReadBlocksEx (
335   IN     EFI_BLOCK_IO2_PROTOCOL   *This,
336   IN     UINT32                   MediaId,
337   IN     EFI_LBA                  Lba,
338   IN OUT EFI_BLOCK_IO2_TOKEN      *Token,
339   IN     UINTN                    BufferSize,
340      OUT VOID                     *Buffer
341   )
342 {
343   RAM_DISK_PRIVATE_DATA           *PrivateData;
344   EFI_STATUS                      Status;
345 
346   PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);
347 
348   Status = RamDiskBlkIoReadBlocks (
349               &PrivateData->BlockIo,
350               MediaId,
351               Lba,
352               BufferSize,
353               Buffer
354               );
355   if (EFI_ERROR (Status)) {
356     return Status;
357   }
358 
359   //
360   // If caller's event is given, signal it after the memory read completes.
361   //
362   if ((Token != NULL) && (Token->Event != NULL)) {
363     Token->TransactionStatus = EFI_SUCCESS;
364     gBS->SignalEvent (Token->Event);
365   }
366 
367   return EFI_SUCCESS;
368 }
369 
370 
371 /**
372   Writes a specified number of blocks to the device.
373 
374   @param[in]      This            Indicates a pointer to the calling context.
375   @param[in]      MediaId         The media ID that the write request is for.
376   @param[in]      Lba             The starting logical block address to be
377                                   written. The caller is responsible for
378                                   writing to only legitimate locations.
379   @param[in, out] Token           A pointer to the token associated with the
380                                   transaction.
381   @param[in]      BufferSize      The size in bytes of Buffer. This must be a
382                                   multiple of the intrinsic block size of the
383                                   device.
384   @param[in]      Buffer          A pointer to the source buffer for the data.
385 
386   @retval EFI_SUCCESS             The write request was queued if Event is not
387                                   NULL. The data was written correctly to the
388                                   device if the Event is NULL.
389   @retval EFI_WRITE_PROTECTED     The device cannot be written to.
390   @retval EFI_NO_MEDIA            There is no media in the device.
391   @retval EFI_MEDIA_CHANGED       The MediaId is not for the current media.
392   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
393                                   to perform the write operation.
394   @retval EFI_BAD_BUFFER_SIZE     The BufferSize parameter is not a multiple of
395                                   the intrinsic block size of the device.
396   @retval EFI_INVALID_PARAMETER   The write request contains LBAs that are not
397                                   valid, or the buffer is not on proper
398                                   alignment.
399   @retval EFI_OUT_OF_RESOURCES    The request could not be completed due to a
400                                   lack of resources.
401 
402 **/
403 EFI_STATUS
404 EFIAPI
RamDiskBlkIo2WriteBlocksEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN UINT32 MediaId,IN EFI_LBA Lba,IN OUT EFI_BLOCK_IO2_TOKEN * Token,IN UINTN BufferSize,IN VOID * Buffer)405 RamDiskBlkIo2WriteBlocksEx (
406   IN     EFI_BLOCK_IO2_PROTOCOL   *This,
407   IN     UINT32                   MediaId,
408   IN     EFI_LBA                  Lba,
409   IN OUT EFI_BLOCK_IO2_TOKEN      *Token,
410   IN     UINTN                    BufferSize,
411   IN     VOID                     *Buffer
412   )
413 {
414   RAM_DISK_PRIVATE_DATA           *PrivateData;
415   EFI_STATUS                      Status;
416 
417   PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);
418 
419   Status = RamDiskBlkIoWriteBlocks (
420               &PrivateData->BlockIo,
421               MediaId,
422               Lba,
423               BufferSize,
424               Buffer
425               );
426   if (EFI_ERROR (Status)) {
427     return Status;
428   }
429 
430   //
431   // If caller's event is given, signal it after the memory write completes.
432   //
433   if ((Token != NULL) && (Token->Event != NULL)) {
434     Token->TransactionStatus = EFI_SUCCESS;
435     gBS->SignalEvent (Token->Event);
436   }
437 
438   return EFI_SUCCESS;
439 }
440 
441 
442 /**
443   Flushes all modified data to a physical block device.
444 
445   @param[in]      This            Indicates a pointer to the calling context.
446   @param[in, out] Token           A pointer to the token associated with the
447                                   transaction.
448 
449   @retval EFI_SUCCESS             The flush request was queued if Event is not
450                                   NULL. All outstanding data was written
451                                   correctly to the device if the Event is NULL.
452   @retval EFI_DEVICE_ERROR        The device reported an error while attempting
453                                   to write data.
454   @retval EFI_WRITE_PROTECTED     The device cannot be written to.
455   @retval EFI_NO_MEDIA            There is no media in the device.
456   @retval EFI_MEDIA_CHANGED       The MediaId is not for the current media.
457   @retval EFI_OUT_OF_RESOURCES    The request could not be completed due to a
458                                   lack of resources.
459 
460 **/
461 EFI_STATUS
462 EFIAPI
RamDiskBlkIo2FlushBlocksEx(IN EFI_BLOCK_IO2_PROTOCOL * This,IN OUT EFI_BLOCK_IO2_TOKEN * Token)463 RamDiskBlkIo2FlushBlocksEx (
464   IN     EFI_BLOCK_IO2_PROTOCOL   *This,
465   IN OUT EFI_BLOCK_IO2_TOKEN      *Token
466   )
467 {
468   RAM_DISK_PRIVATE_DATA           *PrivateData;
469 
470   PrivateData = RAM_DISK_PRIVATE_FROM_BLKIO2 (This);
471 
472   if (TRUE == PrivateData->Media.ReadOnly) {
473     return EFI_WRITE_PROTECTED;
474   }
475 
476   //
477   // If caller's event is given, signal it directly.
478   //
479   if ((Token != NULL) && (Token->Event != NULL)) {
480     Token->TransactionStatus = EFI_SUCCESS;
481     gBS->SignalEvent (Token->Event);
482   }
483 
484   return EFI_SUCCESS;
485 }
486