]>
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 | |
d59326d3 | 258 | return Status;\r |
d59326d3 | 259 | }\r |
260 | \r | |
bfa084fa | 261 | \r |
d59326d3 | 262 | EFI_STATUS\r |
033d0e5f | 263 | EmuBlockIoReadWriteCommon (\r |
264 | IN EMU_BLOCK_IO_PRIVATE *Private,\r | |
d59326d3 | 265 | IN UINT32 MediaId,\r |
266 | IN EFI_LBA Lba,\r | |
267 | IN UINTN BufferSize,\r | |
268 | IN VOID *Buffer,\r | |
269 | IN CHAR8 *CallerName\r | |
270 | )\r | |
271 | {\r | |
272 | EFI_STATUS Status;\r | |
273 | UINTN BlockSize;\r | |
274 | UINT64 LastBlock;\r | |
275 | INT64 DistanceToMove;\r | |
276 | UINT64 DistanceMoved;\r | |
277 | \r | |
278 | if (Private->fd < 0) {\r | |
033d0e5f | 279 | Status = EmuBlockIoOpenDevice (Private);\r |
d59326d3 | 280 | if (EFI_ERROR (Status)) {\r |
281 | return Status;\r | |
282 | }\r | |
283 | }\r | |
284 | \r | |
033d0e5f | 285 | if (!Private->Media->MediaPresent) {\r |
d59326d3 | 286 | DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));\r |
287 | return EFI_NO_MEDIA;\r | |
288 | }\r | |
289 | \r | |
033d0e5f | 290 | if (Private->Media->MediaId != MediaId) {\r |
d59326d3 | 291 | return EFI_MEDIA_CHANGED;\r |
292 | }\r | |
293 | \r | |
033d0e5f | 294 | if ((UINTN) Buffer % Private->Media->IoAlign != 0) {\r |
d59326d3 | 295 | return EFI_INVALID_PARAMETER;\r |
296 | }\r | |
297 | \r | |
298 | //\r | |
299 | // Verify buffer size\r | |
300 | //\r | |
63947cc4 | 301 | BlockSize = Private->Media->BlockSize;\r |
d59326d3 | 302 | if (BufferSize == 0) {\r |
303 | DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));\r | |
304 | return EFI_SUCCESS;\r | |
305 | }\r | |
306 | \r | |
307 | if ((BufferSize % BlockSize) != 0) {\r | |
308 | DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));\r | |
309 | return EFI_BAD_BUFFER_SIZE;\r | |
310 | }\r | |
311 | \r | |
312 | LastBlock = Lba + (BufferSize / BlockSize) - 1;\r | |
63947cc4 | 313 | if (LastBlock > Private->Media->LastBlock) {\r |
d59326d3 | 314 | DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));\r |
315 | return EFI_INVALID_PARAMETER;\r | |
316 | }\r | |
317 | //\r | |
318 | // Seek to End of File\r | |
319 | //\r | |
320 | DistanceToMove = MultU64x32 (Lba, BlockSize);\r | |
321 | Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);\r | |
322 | \r | |
323 | if (EFI_ERROR (Status)) {\r | |
324 | DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));\r | |
033d0e5f | 325 | return EmuBlockIoError (Private);\r |
d59326d3 | 326 | }\r |
327 | \r | |
328 | return EFI_SUCCESS;\r | |
329 | }\r | |
330 | \r | |
d59326d3 | 331 | \r |
033d0e5f | 332 | /**\r |
333 | Read BufferSize bytes from Lba into Buffer.\r | |
334 | \r | |
335 | This function reads the requested number of blocks from the device. All the\r | |
336 | blocks are read, or an error is returned.\r | |
337 | If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and\r | |
338 | non-blocking I/O is being used, the Event associated with this request will\r | |
339 | not be signaled.\r | |
340 | \r | |
341 | @param[in] This Indicates a pointer to the calling context.\r | |
342 | @param[in] MediaId Id of the media, changes every time the media is \r | |
343 | replaced.\r | |
344 | @param[in] Lba The starting Logical Block Address to read from.\r | |
345 | @param[in, out] Token A pointer to the token associated with the transaction.\r | |
346 | @param[in] BufferSize Size of Buffer, must be a multiple of device block size. \r | |
347 | @param[out] Buffer A pointer to the destination buffer for the data. The \r | |
348 | caller is responsible for either having implicit or \r | |
349 | explicit ownership of the buffer.\r | |
350 | \r | |
351 | @retval EFI_SUCCESS The read request was queued if Token->Event is\r | |
352 | not NULL.The data was read correctly from the\r | |
353 | device if the Token->Event is NULL.\r | |
354 | @retval EFI_DEVICE_ERROR The device reported an error while performing\r | |
355 | the read.\r | |
356 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
357 | @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r | |
358 | @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r | |
359 | intrinsic block size of the device.\r | |
360 | @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r | |
361 | or the buffer is not on proper alignment.\r | |
362 | @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r | |
363 | of resources.\r | |
d59326d3 | 364 | **/\r |
033d0e5f | 365 | EFI_STATUS\r |
366 | EmuBlockIoReadBlocks (\r | |
367 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
368 | IN UINT32 MediaId,\r | |
369 | IN EFI_LBA LBA,\r | |
370 | IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r | |
371 | IN UINTN BufferSize,\r | |
372 | OUT VOID *Buffer\r | |
373 | )\r | |
d59326d3 | 374 | {\r |
d59326d3 | 375 | EFI_STATUS Status;\r |
033d0e5f | 376 | EMU_BLOCK_IO_PRIVATE *Private;\r |
377 | ssize_t len;\r | |
d59326d3 | 378 | \r |
379 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r | |
380 | \r | |
033d0e5f | 381 | Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixReadBlocks");\r |
d59326d3 | 382 | if (EFI_ERROR (Status)) {\r |
383 | goto Done;\r | |
384 | }\r | |
385 | \r | |
033d0e5f | 386 | len = read (Private->fd, Buffer, BufferSize);\r |
d59326d3 | 387 | if (len != BufferSize) {\r |
388 | DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));\r | |
033d0e5f | 389 | Status = EmuBlockIoError (Private);\r |
d59326d3 | 390 | goto Done;\r |
391 | }\r | |
392 | \r | |
393 | //\r | |
033d0e5f | 394 | // If we read then media is present.\r |
d59326d3 | 395 | //\r |
033d0e5f | 396 | Private->Media->MediaPresent = TRUE;\r |
d59326d3 | 397 | Status = EFI_SUCCESS;\r |
398 | \r | |
399 | Done:\r | |
033d0e5f | 400 | if (Token != NULL) {\r |
401 | if (Token->Event != NULL) {\r | |
402 | // Caller is responcible for signaling EFI Event\r | |
403 | Token->TransactionStatus = Status;\r | |
404 | return EFI_SUCCESS;\r | |
405 | }\r | |
406 | }\r | |
d59326d3 | 407 | return Status;\r |
408 | }\r | |
409 | \r | |
d59326d3 | 410 | \r |
033d0e5f | 411 | /**\r |
412 | Write BufferSize bytes from Lba into Buffer.\r | |
413 | \r | |
414 | This function writes the requested number of blocks to the device. All blocks\r | |
415 | are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,\r | |
416 | EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is\r | |
417 | being used, the Event associated with this request will not be signaled.\r | |
418 | \r | |
419 | @param[in] This Indicates a pointer to the calling context.\r | |
420 | @param[in] MediaId The media ID that the write request is for.\r | |
421 | @param[in] Lba The starting logical block address to be written. The\r | |
422 | caller is responsible for writing to only legitimate\r | |
423 | locations.\r | |
424 | @param[in, out] Token A pointer to the token associated with the transaction.\r | |
425 | @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r | |
426 | @param[in] Buffer A pointer to the source buffer for the data.\r | |
427 | \r | |
428 | @retval EFI_SUCCESS The write request was queued if Event is not NULL.\r | |
429 | The data was written correctly to the device if\r | |
430 | the Event is NULL.\r | |
431 | @retval EFI_WRITE_PROTECTED The device can not be written to.\r | |
432 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
433 | @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r | |
434 | @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r | |
435 | @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r | |
436 | @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r | |
437 | or the buffer is not on proper alignment.\r | |
438 | @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r | |
439 | of resources.\r | |
d59326d3 | 440 | \r |
441 | **/\r | |
033d0e5f | 442 | EFI_STATUS\r |
443 | EmuBlockIoWriteBlocks (\r | |
444 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
445 | IN UINT32 MediaId,\r | |
446 | IN EFI_LBA LBA,\r | |
447 | IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r | |
448 | IN UINTN BufferSize,\r | |
449 | IN VOID *Buffer\r | |
450 | )\r | |
d59326d3 | 451 | {\r |
033d0e5f | 452 | EMU_BLOCK_IO_PRIVATE *Private;\r |
d59326d3 | 453 | ssize_t len;\r |
454 | EFI_STATUS Status;\r | |
d59326d3 | 455 | \r |
d59326d3 | 456 | \r |
457 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r | |
458 | \r | |
033d0e5f | 459 | Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixWriteBlocks");\r |
d59326d3 | 460 | if (EFI_ERROR (Status)) {\r |
461 | goto Done;\r | |
462 | }\r | |
463 | \r | |
033d0e5f | 464 | len = write (Private->fd, Buffer, BufferSize);\r |
d59326d3 | 465 | if (len != BufferSize) {\r |
466 | DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));\r | |
033d0e5f | 467 | Status = EmuBlockIoError (Private);\r |
d59326d3 | 468 | goto Done;\r |
469 | }\r | |
470 | \r | |
471 | //\r | |
472 | // If the write succeeded, we are not write protected and media is present.\r | |
473 | //\r | |
033d0e5f | 474 | Private->Media->MediaPresent = TRUE;\r |
475 | Private->Media->ReadOnly = FALSE;\r | |
d59326d3 | 476 | Status = EFI_SUCCESS;\r |
477 | \r | |
478 | Done:\r | |
033d0e5f | 479 | if (Token != NULL) {\r |
480 | if (Token->Event != NULL) {\r | |
481 | // Caller is responcible for signaling EFI Event\r | |
482 | Token->TransactionStatus = Status;\r | |
483 | return EFI_SUCCESS;\r | |
484 | }\r | |
485 | }\r | |
486 | \r | |
d59326d3 | 487 | return Status;\r |
488 | }\r | |
489 | \r | |
d59326d3 | 490 | \r |
033d0e5f | 491 | /**\r |
492 | Flush the Block Device.\r | |
493 | \r | |
494 | If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED\r | |
495 | is returned and non-blocking I/O is being used, the Event associated with\r | |
496 | this request will not be signaled. \r | |
497 | \r | |
498 | @param[in] This Indicates a pointer to the calling context.\r | |
499 | @param[in,out] Token A pointer to the token associated with the transaction\r | |
500 | \r | |
501 | @retval EFI_SUCCESS The flush request was queued if Event is not NULL.\r | |
502 | All outstanding data was written correctly to the\r | |
503 | device if the Event is NULL.\r | |
504 | @retval EFI_DEVICE_ERROR The device reported an error while writting back\r | |
505 | the data.\r | |
506 | @retval EFI_WRITE_PROTECTED The device cannot be written to.\r | |
507 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
508 | @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r | |
509 | @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r | |
510 | of resources.\r | |
d59326d3 | 511 | \r |
512 | **/\r | |
033d0e5f | 513 | EFI_STATUS\r |
514 | EmuBlockIoFlushBlocks (\r | |
515 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
516 | IN OUT EFI_BLOCK_IO2_TOKEN *Token\r | |
517 | )\r | |
d59326d3 | 518 | {\r |
033d0e5f | 519 | EMU_BLOCK_IO_PRIVATE *Private;\r |
63947cc4 | 520 | int Res;\r |
033d0e5f | 521 | \r |
522 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r | |
523 | \r | |
524 | if (Private->fd >= 0) {\r | |
63947cc4 | 525 | Res = fcntl (Private->fd, F_FULLFSYNC);\r |
033d0e5f | 526 | }\r |
527 | \r | |
63947cc4 | 528 | \r |
033d0e5f | 529 | if (Token != NULL) {\r |
530 | if (Token->Event != NULL) {\r | |
531 | // Caller is responcible for signaling EFI Event\r | |
532 | Token->TransactionStatus = EFI_SUCCESS;\r | |
533 | return EFI_SUCCESS;\r | |
534 | }\r | |
535 | }\r | |
536 | \r | |
d59326d3 | 537 | return EFI_SUCCESS;\r |
538 | }\r | |
539 | \r | |
033d0e5f | 540 | \r |
541 | /**\r | |
542 | Reset the block device hardware.\r | |
543 | \r | |
544 | @param[in] This Indicates a pointer to the calling context.\r | |
545 | @param[in] ExtendedVerification Indicates that the driver may perform a more\r | |
546 | exhausive verfication operation of the device\r | |
547 | during reset.\r | |
548 | \r | |
549 | @retval EFI_SUCCESS The device was reset.\r | |
550 | @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r | |
551 | not be reset.\r | |
552 | \r | |
553 | **/\r | |
d59326d3 | 554 | EFI_STATUS\r |
033d0e5f | 555 | EmuBlockIoReset (\r |
556 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
557 | IN BOOLEAN ExtendedVerification\r | |
d59326d3 | 558 | )\r |
d59326d3 | 559 | {\r |
560 | EMU_BLOCK_IO_PRIVATE *Private;\r | |
d59326d3 | 561 | \r |
d59326d3 | 562 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r |
563 | \r | |
564 | if (Private->fd >= 0) {\r | |
033d0e5f | 565 | close (Private->fd);\r |
d59326d3 | 566 | Private->fd = -1;\r |
567 | }\r | |
568 | \r | |
d59326d3 | 569 | return EFI_SUCCESS;\r |
570 | }\r | |
571 | \r | |
d59326d3 | 572 | \r |
033d0e5f | 573 | char *\r |
574 | StdDupUnicodeToAscii (\r | |
575 | IN CHAR16 *Str\r | |
576 | )\r | |
577 | {\r | |
578 | UINTN Size;\r | |
579 | char *Ascii;\r | |
580 | char *Ptr;\r | |
581 | \r | |
582 | Size = StrLen (Str) + 1;\r | |
583 | Ascii = malloc (Size);\r | |
584 | if (Ascii == NULL) {\r | |
585 | return NULL;\r | |
586 | }\r | |
587 | \r | |
588 | for (Ptr = Ascii; *Str != '\0'; Ptr++, Str++) {\r | |
589 | *Ptr = *Str;\r | |
590 | }\r | |
591 | *Ptr = 0;\r | |
592 | \r | |
593 | return Ascii;\r | |
594 | }\r | |
d59326d3 | 595 | \r |
d59326d3 | 596 | \r |
033d0e5f | 597 | EMU_BLOCK_IO_PROTOCOL gEmuBlockIoProtocol = {\r |
598 | GasketEmuBlockIoReset,\r | |
599 | GasketEmuBlockIoReadBlocks,\r | |
600 | GasketEmuBlockIoWriteBlocks,\r | |
601 | GasketEmuBlockIoFlushBlocks,\r | |
602 | GasketEmuBlockIoCreateMapping\r | |
603 | };\r | |
d59326d3 | 604 | \r |
033d0e5f | 605 | EFI_STATUS\r |
606 | EmuBlockIoThunkOpen (\r | |
607 | IN EMU_IO_THUNK_PROTOCOL *This\r | |
608 | )\r | |
d59326d3 | 609 | {\r |
033d0e5f | 610 | EMU_BLOCK_IO_PRIVATE *Private;\r |
611 | char *Str;\r | |
612 | \r | |
613 | if (This->Private != NULL) {\r | |
614 | return EFI_ALREADY_STARTED;\r | |
d59326d3 | 615 | }\r |
033d0e5f | 616 | \r |
617 | if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {\r | |
618 | return EFI_UNSUPPORTED;\r | |
619 | }\r | |
620 | \r | |
621 | Private = malloc (sizeof (EMU_BLOCK_IO_PRIVATE));\r | |
622 | if (Private == NULL) {\r | |
623 | return EFI_OUT_OF_RESOURCES;\r | |
d59326d3 | 624 | }\r |
625 | \r | |
033d0e5f | 626 | \r |
627 | Private->Signature = EMU_BLOCK_IO_PRIVATE_SIGNATURE;\r | |
628 | Private->Thunk = This;\r | |
629 | CopyMem (&Private->EmuBlockIo, &gEmuBlockIoProtocol, sizeof (gEmuBlockIoProtocol));\r | |
630 | Private->fd = -1;\r | |
631 | \r | |
632 | Private->Filename = StdDupUnicodeToAscii (This->ConfigString);\r | |
633 | if (Private->Filename == NULL) {\r | |
634 | return EFI_OUT_OF_RESOURCES;\r | |
635 | }\r | |
636 | \r | |
637 | Str = strstr (Private->Filename, ":");\r | |
638 | if (Str == NULL) {\r | |
639 | Private->RemovableMedia = FALSE;\r | |
640 | Private->WriteProtected = FALSE;\r | |
641 | } else {\r | |
642 | for (*Str++ = '\0'; *Str != 0; Str++) {\r | |
643 | if (*Str == 'R' || *Str == 'F') {\r | |
644 | Private->RemovableMedia = (BOOLEAN) (*Str == 'R');\r | |
645 | }\r | |
646 | if (*Str == 'O' || *Str == 'W') {\r | |
647 | Private->WriteProtected = (BOOLEAN) (*Str == 'O');\r | |
648 | }\r | |
649 | }\r | |
650 | }\r | |
651 | \r | |
033d0e5f | 652 | This->Interface = &Private->EmuBlockIo;\r |
653 | This->Private = Private;\r | |
654 | return EFI_SUCCESS;\r | |
d59326d3 | 655 | }\r |
656 | \r | |
657 | \r | |
d59326d3 | 658 | EFI_STATUS\r |
033d0e5f | 659 | EmuBlockIoThunkClose (\r |
660 | IN EMU_IO_THUNK_PROTOCOL *This\r | |
d59326d3 | 661 | )\r |
662 | {\r | |
033d0e5f | 663 | EMU_BLOCK_IO_PRIVATE *Private;\r |
d59326d3 | 664 | \r |
033d0e5f | 665 | if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {\r |
666 | return EFI_UNSUPPORTED;\r | |
d59326d3 | 667 | }\r |
033d0e5f | 668 | \r |
669 | Private = This->Private;\r | |
670 | \r | |
671 | if (This->Private != NULL) {\r | |
672 | if (Private->Filename != NULL) {\r | |
673 | free (Private->Filename);\r | |
674 | } \r | |
675 | free (This->Private);\r | |
21ce7a41 | 676 | This->Private = NULL;\r |
d59326d3 | 677 | }\r |
033d0e5f | 678 | \r |
679 | return EFI_SUCCESS;\r | |
d59326d3 | 680 | }\r |
033d0e5f | 681 | \r |
682 | \r | |
683 | \r | |
684 | EMU_IO_THUNK_PROTOCOL gBlockIoThunkIo = {\r | |
685 | &gEmuBlockIoProtocolGuid,\r | |
686 | NULL,\r | |
687 | NULL,\r | |
688 | 0,\r | |
689 | GasketBlockIoThunkOpen,\r | |
690 | GasketBlockIoThunkClose,\r | |
691 | NULL\r | |
692 | };\r | |
693 | \r | |
694 | \r |