]>
Commit | Line | Data |
---|---|---|
d59326d3 | 1 | /**@file\r |
2 | \r | |
3 | Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>\r | |
e3ba31da | 4 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
d59326d3 | 5 | \r |
d59326d3 | 6 | **/\r |
7 | \r | |
59ad461d | 8 | #include "Host.h"\r |
d59326d3 | 9 | \r |
033d0e5f | 10 | #define EMU_BLOCK_IO_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'M', 'b', 'k')\r |
11 | typedef struct {\r | |
12 | UINTN Signature;\r | |
d59326d3 | 13 | \r |
033d0e5f | 14 | EMU_IO_THUNK_PROTOCOL *Thunk;\r |
d59326d3 | 15 | \r |
033d0e5f | 16 | char *Filename;\r |
17 | UINTN ReadMode;\r | |
18 | UINTN Mode;\r | |
d59326d3 | 19 | \r |
033d0e5f | 20 | int fd;\r |
d59326d3 | 21 | \r |
d59326d3 | 22 | BOOLEAN RemovableMedia;\r |
23 | BOOLEAN WriteProtected;\r | |
d59326d3 | 24 | \r |
033d0e5f | 25 | UINT64 NumberOfBlocks;\r |
5dcda296 | 26 | UINT32 BlockSize;\r |
d59326d3 | 27 | \r |
033d0e5f | 28 | EMU_BLOCK_IO_PROTOCOL EmuBlockIo;\r |
29 | EFI_BLOCK_IO_MEDIA *Media;\r | |
d59326d3 | 30 | \r |
033d0e5f | 31 | } EMU_BLOCK_IO_PRIVATE;\r |
d59326d3 | 32 | \r |
033d0e5f | 33 | #define EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS(a) \\r |
34 | CR(a, EMU_BLOCK_IO_PRIVATE, EmuBlockIo, EMU_BLOCK_IO_PRIVATE_SIGNATURE)\r | |
d59326d3 | 35 | \r |
d59326d3 | 36 | \r |
d59326d3 | 37 | \r |
38 | EFI_STATUS\r | |
033d0e5f | 39 | EmuBlockIoReset (\r |
40 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
41 | IN BOOLEAN ExtendedVerification\r | |
42 | );\r | |
d59326d3 | 43 | \r |
d59326d3 | 44 | \r |
d59326d3 | 45 | /*++\r |
46 | \r | |
033d0e5f | 47 | This function extends the capability of SetFilePointer to accept 64 bit parameters\r |
d59326d3 | 48 | \r |
49 | **/\r | |
d59326d3 | 50 | EFI_STATUS\r |
033d0e5f | 51 | SetFilePointer64 (\r |
52 | IN EMU_BLOCK_IO_PRIVATE *Private,\r | |
53 | IN INT64 DistanceToMove,\r | |
54 | OUT UINT64 *NewFilePointer,\r | |
55 | IN INT32 MoveMethod\r | |
d59326d3 | 56 | )\r |
57 | {\r | |
033d0e5f | 58 | EFI_STATUS Status;\r |
59 | off_t res;\r | |
63947cc4 | 60 | off_t offset = DistanceToMove;\r |
d59326d3 | 61 | \r |
033d0e5f | 62 | Status = EFI_SUCCESS;\r |
63947cc4 | 63 | res = lseek (Private->fd, offset, (int)MoveMethod);\r |
033d0e5f | 64 | if (res == -1) {\r |
65 | Status = EFI_INVALID_PARAMETER;\r | |
d18d8a1d | 66 | }\r |
d59326d3 | 67 | \r |
033d0e5f | 68 | if (NewFilePointer != NULL) {\r |
69 | *NewFilePointer = res;\r | |
d59326d3 | 70 | }\r |
71 | \r | |
72 | return Status;\r | |
73 | }\r | |
74 | \r | |
033d0e5f | 75 | \r |
d59326d3 | 76 | EFI_STATUS\r |
033d0e5f | 77 | EmuBlockIoOpenDevice (\r |
78 | IN EMU_BLOCK_IO_PRIVATE *Private\r | |
d59326d3 | 79 | )\r |
80 | {\r | |
81 | EFI_STATUS Status;\r | |
82 | UINT64 FileSize;\r | |
63947cc4 | 83 | struct statfs buf;\r |
d59326d3 | 84 | \r |
d59326d3 | 85 | \r |
86 | //\r | |
87 | // If the device is already opened, close it\r | |
88 | //\r | |
89 | if (Private->fd >= 0) {\r | |
033d0e5f | 90 | EmuBlockIoReset (&Private->EmuBlockIo, FALSE);\r |
d59326d3 | 91 | }\r |
92 | \r | |
93 | //\r | |
94 | // Open the device\r | |
95 | //\r | |
033d0e5f | 96 | Private->fd = open (Private->Filename, Private->Mode, 0644);\r |
d59326d3 | 97 | if (Private->fd < 0) {\r |
63947cc4 | 98 | printf ("EmuOpenBlock: Could not open %s: %s\n", Private->Filename, strerror(errno));\r |
033d0e5f | 99 | Private->Media->MediaPresent = FALSE;\r |
63947cc4 | 100 | Status = EFI_NO_MEDIA;\r |
d59326d3 | 101 | goto Done;\r |
102 | }\r | |
103 | \r | |
033d0e5f | 104 | if (!Private->Media->MediaPresent) {\r |
d59326d3 | 105 | //\r |
106 | // BugBug: try to emulate if a CD appears - notify drivers to check it out\r | |
107 | //\r | |
033d0e5f | 108 | Private->Media->MediaPresent = TRUE;\r |
d59326d3 | 109 | }\r |
110 | \r | |
111 | //\r | |
112 | // get the size of the file\r | |
113 | //\r | |
114 | Status = SetFilePointer64 (Private, 0, &FileSize, SEEK_END);\r | |
115 | if (EFI_ERROR (Status)) {\r | |
63947cc4 | 116 | printf ("EmuOpenBlock: Could not get filesize of %s\n", Private->Filename);\r |
d59326d3 | 117 | Status = EFI_UNSUPPORTED;\r |
118 | goto Done;\r | |
119 | }\r | |
d18d8a1d | 120 | \r |
63947cc4 | 121 | if (FileSize == 0) {\r |
122 | // lseek fails on a real device. ioctl calls are OS specific\r | |
123 | #if __APPLE__\r | |
124 | {\r | |
125 | UINT32 BlockSize;\r | |
d18d8a1d | 126 | \r |
63947cc4 | 127 | if (ioctl (Private->fd, DKIOCGETBLOCKSIZE, &BlockSize) == 0) {\r |
128 | Private->Media->BlockSize = BlockSize;\r | |
129 | }\r | |
130 | if (ioctl (Private->fd, DKIOCGETBLOCKCOUNT, &Private->NumberOfBlocks) == 0) {\r | |
131 | if ((Private->NumberOfBlocks == 0) && (BlockSize == 0x800)) {\r | |
132 | // A DVD is ~ 4.37 GB so make up a number\r | |
133 | Private->Media->LastBlock = (0x100000000ULL/0x800) - 1;\r | |
134 | } else {\r | |
135 | Private->Media->LastBlock = Private->NumberOfBlocks - 1;\r | |
136 | }\r | |
137 | }\r | |
d18d8a1d | 138 | ioctl (Private->fd, DKIOCGETMAXBLOCKCOUNTWRITE, &Private->Media->OptimalTransferLengthGranularity);\r |
63947cc4 | 139 | }\r |
d18d8a1d | 140 | #else\r |
63947cc4 | 141 | {\r |
142 | size_t BlockSize;\r | |
143 | UINT64 DiskSize;\r | |
d18d8a1d | 144 | \r |
63947cc4 | 145 | if (ioctl (Private->fd, BLKSSZGET, &BlockSize) == 0) {\r |
146 | Private->Media->BlockSize = BlockSize;\r | |
147 | }\r | |
148 | if (ioctl (Private->fd, BLKGETSIZE64, &DiskSize) == 0) {\r | |
149 | Private->NumberOfBlocks = DivU64x32 (DiskSize, (UINT32)BlockSize);\r | |
150 | Private->Media->LastBlock = Private->NumberOfBlocks - 1;\r | |
151 | }\r | |
152 | }\r | |
153 | #endif\r | |
d18d8a1d | 154 | \r |
5dcda296 | 155 | } else {\r |
156 | Private->Media->BlockSize = Private->BlockSize;\r | |
63947cc4 | 157 | Private->NumberOfBlocks = DivU64x32 (FileSize, Private->Media->BlockSize);\r |
158 | Private->Media->LastBlock = Private->NumberOfBlocks - 1;\r | |
d18d8a1d | 159 | \r |
5dcda296 | 160 | if (fstatfs (Private->fd, &buf) == 0) {\r |
0bc26da2 | 161 | #if __APPLE__\r |
5dcda296 | 162 | Private->Media->OptimalTransferLengthGranularity = buf.f_iosize/buf.f_bsize;\r |
0bc26da2 | 163 | #else\r |
164 | Private->Media->OptimalTransferLengthGranularity = buf.f_bsize/buf.f_bsize;\r | |
165 | #endif\r | |
5dcda296 | 166 | }\r |
d18d8a1d | 167 | }\r |
d59326d3 | 168 | \r |
033d0e5f | 169 | DEBUG ((EFI_D_INIT, "%HEmuOpenBlock: opened %a%N\n", Private->Filename));\r |
d59326d3 | 170 | Status = EFI_SUCCESS;\r |
171 | \r | |
172 | Done:\r | |
173 | if (EFI_ERROR (Status)) {\r | |
174 | if (Private->fd >= 0) {\r | |
033d0e5f | 175 | EmuBlockIoReset (&Private->EmuBlockIo, FALSE);\r |
d59326d3 | 176 | }\r |
177 | }\r | |
178 | \r | |
d59326d3 | 179 | return Status;\r |
180 | }\r | |
181 | \r | |
033d0e5f | 182 | \r |
d59326d3 | 183 | EFI_STATUS\r |
033d0e5f | 184 | EmuBlockIoCreateMapping (\r |
185 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
186 | IN EFI_BLOCK_IO_MEDIA *Media\r | |
d59326d3 | 187 | )\r |
188 | {\r | |
033d0e5f | 189 | EFI_STATUS Status;\r |
190 | EMU_BLOCK_IO_PRIVATE *Private;\r | |
191 | \r | |
192 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r | |
193 | \r | |
194 | Private->Media = Media;\r | |
d18d8a1d | 195 | \r |
033d0e5f | 196 | Media->MediaId = 0;\r |
197 | Media->RemovableMedia = Private->RemovableMedia;\r | |
198 | Media->MediaPresent = TRUE;\r | |
199 | Media->LogicalPartition = FALSE;\r | |
200 | Media->ReadOnly = Private->WriteProtected;\r | |
201 | Media->WriteCaching = FALSE;\r | |
033d0e5f | 202 | Media->IoAlign = 1;\r |
203 | Media->LastBlock = 0; // Filled in by OpenDevice\r | |
d18d8a1d | 204 | \r |
033d0e5f | 205 | // EFI_BLOCK_IO_PROTOCOL_REVISION2\r |
206 | Media->LowestAlignedLba = 0;\r | |
d18d8a1d | 207 | Media->LogicalBlocksPerPhysicalBlock = 0;\r |
208 | \r | |
63947cc4 | 209 | \r |
033d0e5f | 210 | // EFI_BLOCK_IO_PROTOCOL_REVISION3\r |
211 | Media->OptimalTransferLengthGranularity = 0;\r | |
d18d8a1d | 212 | \r |
033d0e5f | 213 | Status = EmuBlockIoOpenDevice (Private);\r |
214 | \r | |
d18d8a1d | 215 | \r |
033d0e5f | 216 | return Status;\r |
217 | }\r | |
218 | \r | |
d59326d3 | 219 | \r |
033d0e5f | 220 | EFI_STATUS\r |
221 | EmuBlockIoError (\r | |
222 | IN EMU_BLOCK_IO_PRIVATE *Private\r | |
223 | )\r | |
224 | {\r | |
d59326d3 | 225 | EFI_STATUS Status;\r |
226 | BOOLEAN ReinstallBlockIoFlag;\r | |
227 | \r | |
228 | \r | |
033d0e5f | 229 | switch (errno) {\r |
d59326d3 | 230 | \r |
033d0e5f | 231 | case EAGAIN:\r |
d59326d3 | 232 | Status = EFI_NO_MEDIA;\r |
033d0e5f | 233 | Private->Media->ReadOnly = FALSE;\r |
234 | Private->Media->MediaPresent = FALSE;\r | |
d59326d3 | 235 | ReinstallBlockIoFlag = FALSE;\r |
236 | break;\r | |
237 | \r | |
033d0e5f | 238 | case EACCES:\r |
239 | Private->Media->ReadOnly = FALSE;\r | |
240 | Private->Media->MediaPresent = TRUE;\r | |
241 | Private->Media->MediaId += 1;\r | |
d59326d3 | 242 | ReinstallBlockIoFlag = TRUE;\r |
243 | Status = EFI_MEDIA_CHANGED;\r | |
244 | break;\r | |
245 | \r | |
033d0e5f | 246 | case EROFS:\r |
247 | Private->Media->ReadOnly = TRUE;\r | |
d59326d3 | 248 | ReinstallBlockIoFlag = FALSE;\r |
249 | Status = EFI_WRITE_PROTECTED;\r | |
250 | break;\r | |
251 | \r | |
252 | default:\r | |
253 | ReinstallBlockIoFlag = FALSE;\r | |
254 | Status = EFI_DEVICE_ERROR;\r | |
255 | break;\r | |
256 | }\r | |
d59326d3 | 257 | return Status;\r |
d59326d3 | 258 | }\r |
259 | \r | |
bfa084fa | 260 | \r |
d59326d3 | 261 | EFI_STATUS\r |
033d0e5f | 262 | EmuBlockIoReadWriteCommon (\r |
263 | IN EMU_BLOCK_IO_PRIVATE *Private,\r | |
d59326d3 | 264 | IN UINT32 MediaId,\r |
265 | IN EFI_LBA Lba,\r | |
266 | IN UINTN BufferSize,\r | |
267 | IN VOID *Buffer,\r | |
268 | IN CHAR8 *CallerName\r | |
269 | )\r | |
270 | {\r | |
271 | EFI_STATUS Status;\r | |
272 | UINTN BlockSize;\r | |
273 | UINT64 LastBlock;\r | |
274 | INT64 DistanceToMove;\r | |
275 | UINT64 DistanceMoved;\r | |
276 | \r | |
277 | if (Private->fd < 0) {\r | |
033d0e5f | 278 | Status = EmuBlockIoOpenDevice (Private);\r |
d59326d3 | 279 | if (EFI_ERROR (Status)) {\r |
280 | return Status;\r | |
281 | }\r | |
282 | }\r | |
283 | \r | |
033d0e5f | 284 | if (!Private->Media->MediaPresent) {\r |
d59326d3 | 285 | DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));\r |
286 | return EFI_NO_MEDIA;\r | |
287 | }\r | |
288 | \r | |
033d0e5f | 289 | if (Private->Media->MediaId != MediaId) {\r |
d59326d3 | 290 | return EFI_MEDIA_CHANGED;\r |
291 | }\r | |
292 | \r | |
033d0e5f | 293 | if ((UINTN) Buffer % Private->Media->IoAlign != 0) {\r |
d59326d3 | 294 | return EFI_INVALID_PARAMETER;\r |
295 | }\r | |
d18d8a1d | 296 | \r |
d59326d3 | 297 | //\r |
298 | // Verify buffer size\r | |
299 | //\r | |
63947cc4 | 300 | BlockSize = Private->Media->BlockSize;\r |
d59326d3 | 301 | if (BufferSize == 0) {\r |
302 | DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));\r | |
303 | return EFI_SUCCESS;\r | |
304 | }\r | |
305 | \r | |
306 | if ((BufferSize % BlockSize) != 0) {\r | |
307 | DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));\r | |
308 | return EFI_BAD_BUFFER_SIZE;\r | |
309 | }\r | |
310 | \r | |
311 | LastBlock = Lba + (BufferSize / BlockSize) - 1;\r | |
63947cc4 | 312 | if (LastBlock > Private->Media->LastBlock) {\r |
d59326d3 | 313 | DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));\r |
314 | return EFI_INVALID_PARAMETER;\r | |
315 | }\r | |
316 | //\r | |
317 | // Seek to End of File\r | |
318 | //\r | |
319 | DistanceToMove = MultU64x32 (Lba, BlockSize);\r | |
320 | Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);\r | |
321 | \r | |
322 | if (EFI_ERROR (Status)) {\r | |
323 | DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));\r | |
033d0e5f | 324 | return EmuBlockIoError (Private);\r |
d59326d3 | 325 | }\r |
326 | \r | |
327 | return EFI_SUCCESS;\r | |
328 | }\r | |
329 | \r | |
d59326d3 | 330 | \r |
033d0e5f | 331 | /**\r |
332 | Read BufferSize bytes from Lba into Buffer.\r | |
d18d8a1d | 333 | \r |
033d0e5f | 334 | This function reads the requested number of blocks from the device. All the\r |
335 | blocks are read, or an error is returned.\r | |
336 | If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and\r | |
337 | non-blocking I/O is being used, the Event associated with this request will\r | |
338 | not be signaled.\r | |
339 | \r | |
340 | @param[in] This Indicates a pointer to the calling context.\r | |
d18d8a1d | 341 | @param[in] MediaId Id of the media, changes every time the media is\r |
033d0e5f | 342 | replaced.\r |
343 | @param[in] Lba The starting Logical Block Address to read from.\r | |
79e4f2a5 | 344 | @param[in, out] Token A pointer to the token associated with the transaction.\r |
d18d8a1d | 345 | @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r |
346 | @param[out] Buffer A pointer to the destination buffer for the data. The\r | |
347 | caller is responsible for either having implicit or\r | |
033d0e5f | 348 | explicit ownership of the buffer.\r |
349 | \r | |
350 | @retval EFI_SUCCESS The read request was queued if Token->Event is\r | |
351 | not NULL.The data was read correctly from the\r | |
352 | device if the Token->Event is NULL.\r | |
353 | @retval EFI_DEVICE_ERROR The device reported an error while performing\r | |
354 | the read.\r | |
355 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
356 | @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r | |
357 | @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r | |
358 | intrinsic block size of the device.\r | |
d18d8a1d | 359 | @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,\r |
033d0e5f | 360 | or the buffer is not on proper alignment.\r |
361 | @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r | |
362 | of resources.\r | |
d59326d3 | 363 | **/\r |
033d0e5f | 364 | EFI_STATUS\r |
365 | EmuBlockIoReadBlocks (\r | |
366 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
367 | IN UINT32 MediaId,\r | |
368 | IN EFI_LBA LBA,\r | |
369 | IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r | |
370 | IN UINTN BufferSize,\r | |
371 | OUT VOID *Buffer\r | |
372 | )\r | |
d59326d3 | 373 | {\r |
d59326d3 | 374 | EFI_STATUS Status;\r |
033d0e5f | 375 | EMU_BLOCK_IO_PRIVATE *Private;\r |
376 | ssize_t len;\r | |
d59326d3 | 377 | \r |
378 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r | |
379 | \r | |
033d0e5f | 380 | Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixReadBlocks");\r |
d59326d3 | 381 | if (EFI_ERROR (Status)) {\r |
382 | goto Done;\r | |
383 | }\r | |
384 | \r | |
033d0e5f | 385 | len = read (Private->fd, Buffer, BufferSize);\r |
d59326d3 | 386 | if (len != BufferSize) {\r |
387 | DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));\r | |
033d0e5f | 388 | Status = EmuBlockIoError (Private);\r |
d59326d3 | 389 | goto Done;\r |
390 | }\r | |
391 | \r | |
392 | //\r | |
033d0e5f | 393 | // If we read then media is present.\r |
d59326d3 | 394 | //\r |
033d0e5f | 395 | Private->Media->MediaPresent = TRUE;\r |
d59326d3 | 396 | Status = EFI_SUCCESS;\r |
397 | \r | |
398 | Done:\r | |
033d0e5f | 399 | if (Token != NULL) {\r |
400 | if (Token->Event != NULL) {\r | |
26cfe2c6 | 401 | // Caller is responsible for signaling EFI Event\r |
033d0e5f | 402 | Token->TransactionStatus = Status;\r |
403 | return EFI_SUCCESS;\r | |
404 | }\r | |
405 | }\r | |
d59326d3 | 406 | return Status;\r |
407 | }\r | |
408 | \r | |
d59326d3 | 409 | \r |
033d0e5f | 410 | /**\r |
411 | Write BufferSize bytes from Lba into Buffer.\r | |
412 | \r | |
413 | This function writes the requested number of blocks to the device. All blocks\r | |
414 | are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,\r | |
415 | EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is\r | |
416 | being used, the Event associated with this request will not be signaled.\r | |
417 | \r | |
418 | @param[in] This Indicates a pointer to the calling context.\r | |
419 | @param[in] MediaId The media ID that the write request is for.\r | |
420 | @param[in] Lba The starting logical block address to be written. The\r | |
421 | caller is responsible for writing to only legitimate\r | |
422 | locations.\r | |
423 | @param[in, out] Token A pointer to the token associated with the transaction.\r | |
424 | @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r | |
425 | @param[in] Buffer A pointer to the source buffer for the data.\r | |
426 | \r | |
427 | @retval EFI_SUCCESS The write request was queued if Event is not NULL.\r | |
428 | The data was written correctly to the device if\r | |
429 | the Event is NULL.\r | |
430 | @retval EFI_WRITE_PROTECTED The device can not be written to.\r | |
431 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
26cfe2c6 | 432 | @retval EFI_MEDIA_CHANGED The MediaId does not match the current device.\r |
033d0e5f | 433 | @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r |
434 | @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r | |
d18d8a1d | 435 | @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,\r |
033d0e5f | 436 | or the buffer is not on proper alignment.\r |
437 | @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r | |
438 | of resources.\r | |
d59326d3 | 439 | \r |
440 | **/\r | |
033d0e5f | 441 | EFI_STATUS\r |
442 | EmuBlockIoWriteBlocks (\r | |
443 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
444 | IN UINT32 MediaId,\r | |
445 | IN EFI_LBA LBA,\r | |
446 | IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r | |
447 | IN UINTN BufferSize,\r | |
448 | IN VOID *Buffer\r | |
449 | )\r | |
d59326d3 | 450 | {\r |
033d0e5f | 451 | EMU_BLOCK_IO_PRIVATE *Private;\r |
d59326d3 | 452 | ssize_t len;\r |
453 | EFI_STATUS Status;\r | |
d59326d3 | 454 | \r |
d59326d3 | 455 | \r |
456 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r | |
457 | \r | |
033d0e5f | 458 | Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixWriteBlocks");\r |
d59326d3 | 459 | if (EFI_ERROR (Status)) {\r |
460 | goto Done;\r | |
461 | }\r | |
462 | \r | |
033d0e5f | 463 | len = write (Private->fd, Buffer, BufferSize);\r |
d59326d3 | 464 | if (len != BufferSize) {\r |
465 | DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));\r | |
033d0e5f | 466 | Status = EmuBlockIoError (Private);\r |
d59326d3 | 467 | goto Done;\r |
468 | }\r | |
469 | \r | |
470 | //\r | |
471 | // If the write succeeded, we are not write protected and media is present.\r | |
472 | //\r | |
033d0e5f | 473 | Private->Media->MediaPresent = TRUE;\r |
474 | Private->Media->ReadOnly = FALSE;\r | |
d59326d3 | 475 | Status = EFI_SUCCESS;\r |
476 | \r | |
477 | Done:\r | |
033d0e5f | 478 | if (Token != NULL) {\r |
479 | if (Token->Event != NULL) {\r | |
26cfe2c6 | 480 | // Caller is responsible for signaling EFI Event\r |
033d0e5f | 481 | Token->TransactionStatus = Status;\r |
482 | return EFI_SUCCESS;\r | |
483 | }\r | |
484 | }\r | |
485 | \r | |
d59326d3 | 486 | return Status;\r |
487 | }\r | |
488 | \r | |
d59326d3 | 489 | \r |
033d0e5f | 490 | /**\r |
491 | Flush the Block Device.\r | |
d18d8a1d | 492 | \r |
033d0e5f | 493 | If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED\r |
494 | is returned and non-blocking I/O is being used, the Event associated with\r | |
d18d8a1d | 495 | this request will not be signaled.\r |
033d0e5f | 496 | \r |
497 | @param[in] This Indicates a pointer to the calling context.\r | |
498 | @param[in,out] Token A pointer to the token associated with the transaction\r | |
499 | \r | |
500 | @retval EFI_SUCCESS The flush request was queued if Event is not NULL.\r | |
501 | All outstanding data was written correctly to the\r | |
502 | device if the Event is NULL.\r | |
26cfe2c6 | 503 | @retval EFI_DEVICE_ERROR The device reported an error while writing back\r |
033d0e5f | 504 | the data.\r |
505 | @retval EFI_WRITE_PROTECTED The device cannot be written to.\r | |
506 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
507 | @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r | |
508 | @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r | |
509 | of resources.\r | |
d59326d3 | 510 | \r |
511 | **/\r | |
033d0e5f | 512 | EFI_STATUS\r |
513 | EmuBlockIoFlushBlocks (\r | |
514 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
515 | IN OUT EFI_BLOCK_IO2_TOKEN *Token\r | |
516 | )\r | |
d59326d3 | 517 | {\r |
033d0e5f | 518 | EMU_BLOCK_IO_PRIVATE *Private;\r |
519 | \r | |
520 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r | |
521 | \r | |
522 | if (Private->fd >= 0) {\r | |
0bc26da2 | 523 | fsync (Private->fd);\r |
524 | #if __APPLE__\r | |
525 | fcntl (Private->fd, F_FULLFSYNC);\r | |
526 | #endif\r | |
033d0e5f | 527 | }\r |
d18d8a1d | 528 | \r |
529 | \r | |
033d0e5f | 530 | if (Token != NULL) {\r |
531 | if (Token->Event != NULL) {\r | |
26cfe2c6 | 532 | // Caller is responsible for signaling EFI Event\r |
033d0e5f | 533 | Token->TransactionStatus = EFI_SUCCESS;\r |
534 | return EFI_SUCCESS;\r | |
535 | }\r | |
536 | }\r | |
d18d8a1d | 537 | \r |
d59326d3 | 538 | return EFI_SUCCESS;\r |
539 | }\r | |
540 | \r | |
033d0e5f | 541 | \r |
542 | /**\r | |
543 | Reset the block device hardware.\r | |
544 | \r | |
545 | @param[in] This Indicates a pointer to the calling context.\r | |
546 | @param[in] ExtendedVerification Indicates that the driver may perform a more\r | |
26cfe2c6 | 547 | exhaustive verification operation of the device\r |
033d0e5f | 548 | during reset.\r |
549 | \r | |
550 | @retval EFI_SUCCESS The device was reset.\r | |
551 | @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r | |
552 | not be reset.\r | |
553 | \r | |
554 | **/\r | |
d59326d3 | 555 | EFI_STATUS\r |
033d0e5f | 556 | EmuBlockIoReset (\r |
557 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
558 | IN BOOLEAN ExtendedVerification\r | |
d59326d3 | 559 | )\r |
d59326d3 | 560 | {\r |
561 | EMU_BLOCK_IO_PRIVATE *Private;\r | |
d59326d3 | 562 | \r |
d59326d3 | 563 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r |
564 | \r | |
565 | if (Private->fd >= 0) {\r | |
033d0e5f | 566 | close (Private->fd);\r |
d59326d3 | 567 | Private->fd = -1;\r |
568 | }\r | |
569 | \r | |
d59326d3 | 570 | return EFI_SUCCESS;\r |
571 | }\r | |
572 | \r | |
d59326d3 | 573 | \r |
033d0e5f | 574 | char *\r |
575 | StdDupUnicodeToAscii (\r | |
576 | IN CHAR16 *Str\r | |
577 | )\r | |
578 | {\r | |
579 | UINTN Size;\r | |
580 | char *Ascii;\r | |
581 | char *Ptr;\r | |
d18d8a1d | 582 | \r |
033d0e5f | 583 | Size = StrLen (Str) + 1;\r |
584 | Ascii = malloc (Size);\r | |
585 | if (Ascii == NULL) {\r | |
586 | return NULL;\r | |
587 | }\r | |
d18d8a1d | 588 | \r |
033d0e5f | 589 | for (Ptr = Ascii; *Str != '\0'; Ptr++, Str++) {\r |
590 | *Ptr = *Str;\r | |
591 | }\r | |
592 | *Ptr = 0;\r | |
d18d8a1d | 593 | \r |
033d0e5f | 594 | return Ascii;\r |
595 | }\r | |
d59326d3 | 596 | \r |
d59326d3 | 597 | \r |
033d0e5f | 598 | EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {\r |
599 | GasketEmuBlockIoReset,\r | |
600 | GasketEmuBlockIoReadBlocks,\r | |
601 | GasketEmuBlockIoWriteBlocks,\r | |
602 | GasketEmuBlockIoFlushBlocks,\r | |
603 | GasketEmuBlockIoCreateMapping\r | |
604 | };\r | |
d59326d3 | 605 | \r |
033d0e5f | 606 | EFI_STATUS\r |
607 | EmuBlockIoThunkOpen (\r | |
608 | IN EMU_IO_THUNK_PROTOCOL *This\r | |
609 | )\r | |
d59326d3 | 610 | {\r |
033d0e5f | 611 | EMU_BLOCK_IO_PRIVATE *Private;\r |
612 | char *Str;\r | |
d18d8a1d | 613 | \r |
033d0e5f | 614 | if (This->Private != NULL) {\r |
615 | return EFI_ALREADY_STARTED;\r | |
d59326d3 | 616 | }\r |
d18d8a1d | 617 | \r |
033d0e5f | 618 | if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {\r |
619 | return EFI_UNSUPPORTED;\r | |
620 | }\r | |
d18d8a1d | 621 | \r |
033d0e5f | 622 | Private = malloc (sizeof (EMU_BLOCK_IO_PRIVATE));\r |
623 | if (Private == NULL) {\r | |
624 | return EFI_OUT_OF_RESOURCES;\r | |
d59326d3 | 625 | }\r |
626 | \r | |
d18d8a1d | 627 | \r |
033d0e5f | 628 | Private->Signature = EMU_BLOCK_IO_PRIVATE_SIGNATURE;\r |
629 | Private->Thunk = This;\r | |
630 | CopyMem (&Private->EmuBlockIo, &gEmuBlockIoProtocol, sizeof (gEmuBlockIoProtocol));\r | |
5dcda296 | 631 | Private->fd = -1;\r |
632 | Private->BlockSize = 512;\r | |
d18d8a1d | 633 | \r |
033d0e5f | 634 | Private->Filename = StdDupUnicodeToAscii (This->ConfigString);\r |
635 | if (Private->Filename == NULL) {\r | |
636 | return EFI_OUT_OF_RESOURCES;\r | |
637 | }\r | |
d18d8a1d | 638 | \r |
033d0e5f | 639 | Str = strstr (Private->Filename, ":");\r |
640 | if (Str == NULL) {\r | |
641 | Private->RemovableMedia = FALSE;\r | |
642 | Private->WriteProtected = FALSE;\r | |
643 | } else {\r | |
644 | for (*Str++ = '\0'; *Str != 0; Str++) {\r | |
645 | if (*Str == 'R' || *Str == 'F') {\r | |
646 | Private->RemovableMedia = (BOOLEAN) (*Str == 'R');\r | |
647 | }\r | |
648 | if (*Str == 'O' || *Str == 'W') {\r | |
649 | Private->WriteProtected = (BOOLEAN) (*Str == 'O');\r | |
650 | }\r | |
5dcda296 | 651 | if (*Str == ':') {\r |
652 | Private->BlockSize = strtol (++Str, NULL, 0);\r | |
653 | break;\r | |
654 | }\r | |
033d0e5f | 655 | }\r |
656 | }\r | |
d18d8a1d | 657 | \r |
2c5ce61d | 658 | Private->Mode = Private->WriteProtected ? O_RDONLY : O_RDWR;\r |
659 | \r | |
033d0e5f | 660 | This->Interface = &Private->EmuBlockIo;\r |
661 | This->Private = Private;\r | |
662 | return EFI_SUCCESS;\r | |
d59326d3 | 663 | }\r |
664 | \r | |
665 | \r | |
d59326d3 | 666 | EFI_STATUS\r |
033d0e5f | 667 | EmuBlockIoThunkClose (\r |
668 | IN EMU_IO_THUNK_PROTOCOL *This\r | |
d59326d3 | 669 | )\r |
670 | {\r | |
033d0e5f | 671 | EMU_BLOCK_IO_PRIVATE *Private;\r |
d59326d3 | 672 | \r |
033d0e5f | 673 | if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {\r |
674 | return EFI_UNSUPPORTED;\r | |
d59326d3 | 675 | }\r |
d18d8a1d | 676 | \r |
033d0e5f | 677 | Private = This->Private;\r |
d18d8a1d | 678 | \r |
033d0e5f | 679 | if (This->Private != NULL) {\r |
680 | if (Private->Filename != NULL) {\r | |
681 | free (Private->Filename);\r | |
d18d8a1d | 682 | }\r |
033d0e5f | 683 | free (This->Private);\r |
21ce7a41 | 684 | This->Private = NULL;\r |
d59326d3 | 685 | }\r |
d18d8a1d | 686 | \r |
033d0e5f | 687 | return EFI_SUCCESS;\r |
d59326d3 | 688 | }\r |
033d0e5f | 689 | \r |
690 | \r | |
691 | \r | |
692 | EMU_IO_THUNK_PROTOCOL gBlockIoThunkIo = {\r | |
693 | &gEmuBlockIoProtocolGuid,\r | |
694 | NULL,\r | |
695 | NULL,\r | |
696 | 0,\r | |
697 | GasketBlockIoThunkOpen,\r | |
698 | GasketBlockIoThunkClose,\r | |
699 | NULL\r | |
700 | };\r | |
701 | \r | |
702 | \r |