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