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 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 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 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 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 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 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 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 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 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