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