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