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