]>
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 |
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 | |
63947cc4 | 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 | |
63947cc4 | 126 | \r |
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 | |
132 | \r | |
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 | |
144 | ioctl (Private->fd, DKIOCGETMAXBLOCKCOUNTWRITE, &Private->Media->OptimalTransferLengthGranularity); \r | |
145 | }\r | |
146 | #else \r | |
147 | {\r | |
148 | size_t BlockSize;\r | |
149 | UINT64 DiskSize;\r | |
150 | \r | |
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 | |
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 | |
5dcda296 | 165 | \r |
166 | if (fstatfs (Private->fd, &buf) == 0) {\r | |
167 | Private->Media->OptimalTransferLengthGranularity = buf.f_iosize/buf.f_bsize;\r | |
168 | }\r | |
63947cc4 | 169 | } \r |
d59326d3 | 170 | \r |
033d0e5f | 171 | DEBUG ((EFI_D_INIT, "%HEmuOpenBlock: opened %a%N\n", Private->Filename));\r |
d59326d3 | 172 | Status = EFI_SUCCESS;\r |
173 | \r | |
174 | Done:\r | |
175 | if (EFI_ERROR (Status)) {\r | |
176 | if (Private->fd >= 0) {\r | |
033d0e5f | 177 | EmuBlockIoReset (&Private->EmuBlockIo, FALSE);\r |
d59326d3 | 178 | }\r |
179 | }\r | |
180 | \r | |
d59326d3 | 181 | return Status;\r |
182 | }\r | |
183 | \r | |
033d0e5f | 184 | \r |
d59326d3 | 185 | EFI_STATUS\r |
033d0e5f | 186 | EmuBlockIoCreateMapping (\r |
187 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
188 | IN EFI_BLOCK_IO_MEDIA *Media\r | |
d59326d3 | 189 | )\r |
190 | {\r | |
033d0e5f | 191 | EFI_STATUS Status;\r |
192 | EMU_BLOCK_IO_PRIVATE *Private;\r | |
193 | \r | |
194 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r | |
195 | \r | |
196 | Private->Media = Media;\r | |
197 | \r | |
198 | Media->MediaId = 0;\r | |
199 | Media->RemovableMedia = Private->RemovableMedia;\r | |
200 | Media->MediaPresent = TRUE;\r | |
201 | Media->LogicalPartition = FALSE;\r | |
202 | Media->ReadOnly = Private->WriteProtected;\r | |
203 | Media->WriteCaching = FALSE;\r | |
033d0e5f | 204 | Media->IoAlign = 1;\r |
205 | Media->LastBlock = 0; // Filled in by OpenDevice\r | |
206 | \r | |
207 | // EFI_BLOCK_IO_PROTOCOL_REVISION2\r | |
208 | Media->LowestAlignedLba = 0;\r | |
209 | Media->LogicalBlocksPerPhysicalBlock = 0; \r | |
63947cc4 | 210 | \r |
211 | \r | |
033d0e5f | 212 | // EFI_BLOCK_IO_PROTOCOL_REVISION3\r |
213 | Media->OptimalTransferLengthGranularity = 0;\r | |
63947cc4 | 214 | \r |
033d0e5f | 215 | Status = EmuBlockIoOpenDevice (Private);\r |
216 | \r | |
63947cc4 | 217 | \r |
033d0e5f | 218 | return Status;\r |
219 | }\r | |
220 | \r | |
d59326d3 | 221 | \r |
033d0e5f | 222 | EFI_STATUS\r |
223 | EmuBlockIoError (\r | |
224 | IN EMU_BLOCK_IO_PRIVATE *Private\r | |
225 | )\r | |
226 | {\r | |
d59326d3 | 227 | EFI_STATUS Status;\r |
228 | BOOLEAN ReinstallBlockIoFlag;\r | |
229 | \r | |
230 | \r | |
033d0e5f | 231 | switch (errno) {\r |
d59326d3 | 232 | \r |
033d0e5f | 233 | case EAGAIN:\r |
d59326d3 | 234 | Status = EFI_NO_MEDIA;\r |
033d0e5f | 235 | Private->Media->ReadOnly = FALSE;\r |
236 | Private->Media->MediaPresent = FALSE;\r | |
d59326d3 | 237 | ReinstallBlockIoFlag = FALSE;\r |
238 | break;\r | |
239 | \r | |
033d0e5f | 240 | case EACCES:\r |
241 | Private->Media->ReadOnly = FALSE;\r | |
242 | Private->Media->MediaPresent = TRUE;\r | |
243 | Private->Media->MediaId += 1;\r | |
d59326d3 | 244 | ReinstallBlockIoFlag = TRUE;\r |
245 | Status = EFI_MEDIA_CHANGED;\r | |
246 | break;\r | |
247 | \r | |
033d0e5f | 248 | case EROFS:\r |
249 | Private->Media->ReadOnly = TRUE;\r | |
d59326d3 | 250 | ReinstallBlockIoFlag = FALSE;\r |
251 | Status = EFI_WRITE_PROTECTED;\r | |
252 | break;\r | |
253 | \r | |
254 | default:\r | |
255 | ReinstallBlockIoFlag = FALSE;\r | |
256 | Status = EFI_DEVICE_ERROR;\r | |
257 | break;\r | |
258 | }\r | |
d59326d3 | 259 | return Status;\r |
d59326d3 | 260 | }\r |
261 | \r | |
bfa084fa | 262 | \r |
d59326d3 | 263 | EFI_STATUS\r |
033d0e5f | 264 | EmuBlockIoReadWriteCommon (\r |
265 | IN EMU_BLOCK_IO_PRIVATE *Private,\r | |
d59326d3 | 266 | IN UINT32 MediaId,\r |
267 | IN EFI_LBA Lba,\r | |
268 | IN UINTN BufferSize,\r | |
269 | IN VOID *Buffer,\r | |
270 | IN CHAR8 *CallerName\r | |
271 | )\r | |
272 | {\r | |
273 | EFI_STATUS Status;\r | |
274 | UINTN BlockSize;\r | |
275 | UINT64 LastBlock;\r | |
276 | INT64 DistanceToMove;\r | |
277 | UINT64 DistanceMoved;\r | |
278 | \r | |
279 | if (Private->fd < 0) {\r | |
033d0e5f | 280 | Status = EmuBlockIoOpenDevice (Private);\r |
d59326d3 | 281 | if (EFI_ERROR (Status)) {\r |
282 | return Status;\r | |
283 | }\r | |
284 | }\r | |
285 | \r | |
033d0e5f | 286 | if (!Private->Media->MediaPresent) {\r |
d59326d3 | 287 | DEBUG ((EFI_D_INIT, "%s: No Media\n", CallerName));\r |
288 | return EFI_NO_MEDIA;\r | |
289 | }\r | |
290 | \r | |
033d0e5f | 291 | if (Private->Media->MediaId != MediaId) {\r |
d59326d3 | 292 | return EFI_MEDIA_CHANGED;\r |
293 | }\r | |
294 | \r | |
033d0e5f | 295 | if ((UINTN) Buffer % Private->Media->IoAlign != 0) {\r |
d59326d3 | 296 | return EFI_INVALID_PARAMETER;\r |
297 | }\r | |
298 | \r | |
299 | //\r | |
300 | // Verify buffer size\r | |
301 | //\r | |
63947cc4 | 302 | BlockSize = Private->Media->BlockSize;\r |
d59326d3 | 303 | if (BufferSize == 0) {\r |
304 | DEBUG ((EFI_D_INIT, "%s: Zero length read\n", CallerName));\r | |
305 | return EFI_SUCCESS;\r | |
306 | }\r | |
307 | \r | |
308 | if ((BufferSize % BlockSize) != 0) {\r | |
309 | DEBUG ((EFI_D_INIT, "%s: Invalid read size\n", CallerName));\r | |
310 | return EFI_BAD_BUFFER_SIZE;\r | |
311 | }\r | |
312 | \r | |
313 | LastBlock = Lba + (BufferSize / BlockSize) - 1;\r | |
63947cc4 | 314 | if (LastBlock > Private->Media->LastBlock) {\r |
d59326d3 | 315 | DEBUG ((EFI_D_INIT, "ReadBlocks: Attempted to read off end of device\n"));\r |
316 | return EFI_INVALID_PARAMETER;\r | |
317 | }\r | |
318 | //\r | |
319 | // Seek to End of File\r | |
320 | //\r | |
321 | DistanceToMove = MultU64x32 (Lba, BlockSize);\r | |
322 | Status = SetFilePointer64 (Private, DistanceToMove, &DistanceMoved, SEEK_SET);\r | |
323 | \r | |
324 | if (EFI_ERROR (Status)) {\r | |
325 | DEBUG ((EFI_D_INIT, "WriteBlocks: SetFilePointer failed\n"));\r | |
033d0e5f | 326 | return EmuBlockIoError (Private);\r |
d59326d3 | 327 | }\r |
328 | \r | |
329 | return EFI_SUCCESS;\r | |
330 | }\r | |
331 | \r | |
d59326d3 | 332 | \r |
033d0e5f | 333 | /**\r |
334 | Read BufferSize bytes from Lba into Buffer.\r | |
335 | \r | |
336 | This function reads the requested number of blocks from the device. All the\r | |
337 | blocks are read, or an error is returned.\r | |
338 | If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_or EFI_MEDIA_CHANGED is returned and\r | |
339 | non-blocking I/O is being used, the Event associated with this request will\r | |
340 | not be signaled.\r | |
341 | \r | |
342 | @param[in] This Indicates a pointer to the calling context.\r | |
343 | @param[in] MediaId Id of the media, changes every time the media is \r | |
344 | replaced.\r | |
345 | @param[in] Lba The starting Logical Block Address to read from.\r | |
346 | @param[in, out] Token A pointer to the token associated with the transaction.\r | |
347 | @param[in] BufferSize Size of Buffer, must be a multiple of device block size. \r | |
348 | @param[out] Buffer A pointer to the destination buffer for the data. The \r | |
349 | caller is responsible for either having implicit or \r | |
350 | explicit ownership of the buffer.\r | |
351 | \r | |
352 | @retval EFI_SUCCESS The read request was queued if Token->Event is\r | |
353 | not NULL.The data was read correctly from the\r | |
354 | device if the Token->Event is NULL.\r | |
355 | @retval EFI_DEVICE_ERROR The device reported an error while performing\r | |
356 | the read.\r | |
357 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
358 | @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r | |
359 | @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the\r | |
360 | intrinsic block size of the device.\r | |
361 | @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r | |
362 | or the buffer is not on proper alignment.\r | |
363 | @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r | |
364 | of resources.\r | |
d59326d3 | 365 | **/\r |
033d0e5f | 366 | EFI_STATUS\r |
367 | EmuBlockIoReadBlocks (\r | |
368 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
369 | IN UINT32 MediaId,\r | |
370 | IN EFI_LBA LBA,\r | |
371 | IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r | |
372 | IN UINTN BufferSize,\r | |
373 | OUT VOID *Buffer\r | |
374 | )\r | |
d59326d3 | 375 | {\r |
d59326d3 | 376 | EFI_STATUS Status;\r |
033d0e5f | 377 | EMU_BLOCK_IO_PRIVATE *Private;\r |
378 | ssize_t len;\r | |
d59326d3 | 379 | \r |
380 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r | |
381 | \r | |
033d0e5f | 382 | Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixReadBlocks");\r |
d59326d3 | 383 | if (EFI_ERROR (Status)) {\r |
384 | goto Done;\r | |
385 | }\r | |
386 | \r | |
033d0e5f | 387 | len = read (Private->fd, Buffer, BufferSize);\r |
d59326d3 | 388 | if (len != BufferSize) {\r |
389 | DEBUG ((EFI_D_INIT, "ReadBlocks: ReadFile failed.\n"));\r | |
033d0e5f | 390 | Status = EmuBlockIoError (Private);\r |
d59326d3 | 391 | goto Done;\r |
392 | }\r | |
393 | \r | |
394 | //\r | |
033d0e5f | 395 | // If we read then media is present.\r |
d59326d3 | 396 | //\r |
033d0e5f | 397 | Private->Media->MediaPresent = TRUE;\r |
d59326d3 | 398 | Status = EFI_SUCCESS;\r |
399 | \r | |
400 | Done:\r | |
033d0e5f | 401 | if (Token != NULL) {\r |
402 | if (Token->Event != NULL) {\r | |
403 | // Caller is responcible for signaling EFI Event\r | |
404 | Token->TransactionStatus = Status;\r | |
405 | return EFI_SUCCESS;\r | |
406 | }\r | |
407 | }\r | |
d59326d3 | 408 | return Status;\r |
409 | }\r | |
410 | \r | |
d59326d3 | 411 | \r |
033d0e5f | 412 | /**\r |
413 | Write BufferSize bytes from Lba into Buffer.\r | |
414 | \r | |
415 | This function writes the requested number of blocks to the device. All blocks\r | |
416 | are written, or an error is returned.If EFI_DEVICE_ERROR, EFI_NO_MEDIA,\r | |
417 | EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED is returned and non-blocking I/O is\r | |
418 | being used, the Event associated with this request will not be signaled.\r | |
419 | \r | |
420 | @param[in] This Indicates a pointer to the calling context.\r | |
421 | @param[in] MediaId The media ID that the write request is for.\r | |
422 | @param[in] Lba The starting logical block address to be written. The\r | |
423 | caller is responsible for writing to only legitimate\r | |
424 | locations.\r | |
425 | @param[in, out] Token A pointer to the token associated with the transaction.\r | |
426 | @param[in] BufferSize Size of Buffer, must be a multiple of device block size.\r | |
427 | @param[in] Buffer A pointer to the source buffer for the data.\r | |
428 | \r | |
429 | @retval EFI_SUCCESS The write request was queued if Event is not NULL.\r | |
430 | The data was written correctly to the device if\r | |
431 | the Event is NULL.\r | |
432 | @retval EFI_WRITE_PROTECTED The device can not be written to.\r | |
433 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
434 | @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r | |
435 | @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r | |
436 | @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r | |
437 | @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r | |
438 | or the buffer is not on proper alignment.\r | |
439 | @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r | |
440 | of resources.\r | |
d59326d3 | 441 | \r |
442 | **/\r | |
033d0e5f | 443 | EFI_STATUS\r |
444 | EmuBlockIoWriteBlocks (\r | |
445 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
446 | IN UINT32 MediaId,\r | |
447 | IN EFI_LBA LBA,\r | |
448 | IN OUT EFI_BLOCK_IO2_TOKEN *Token,\r | |
449 | IN UINTN BufferSize,\r | |
450 | IN VOID *Buffer\r | |
451 | )\r | |
d59326d3 | 452 | {\r |
033d0e5f | 453 | EMU_BLOCK_IO_PRIVATE *Private;\r |
d59326d3 | 454 | ssize_t len;\r |
455 | EFI_STATUS Status;\r | |
d59326d3 | 456 | \r |
d59326d3 | 457 | \r |
458 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r | |
459 | \r | |
033d0e5f | 460 | Status = EmuBlockIoReadWriteCommon (Private, MediaId, LBA, BufferSize, Buffer, "UnixWriteBlocks");\r |
d59326d3 | 461 | if (EFI_ERROR (Status)) {\r |
462 | goto Done;\r | |
463 | }\r | |
464 | \r | |
033d0e5f | 465 | len = write (Private->fd, Buffer, BufferSize);\r |
d59326d3 | 466 | if (len != BufferSize) {\r |
467 | DEBUG ((EFI_D_INIT, "ReadBlocks: WriteFile failed.\n"));\r | |
033d0e5f | 468 | Status = EmuBlockIoError (Private);\r |
d59326d3 | 469 | goto Done;\r |
470 | }\r | |
471 | \r | |
472 | //\r | |
473 | // If the write succeeded, we are not write protected and media is present.\r | |
474 | //\r | |
033d0e5f | 475 | Private->Media->MediaPresent = TRUE;\r |
476 | Private->Media->ReadOnly = FALSE;\r | |
d59326d3 | 477 | Status = EFI_SUCCESS;\r |
478 | \r | |
479 | Done:\r | |
033d0e5f | 480 | if (Token != NULL) {\r |
481 | if (Token->Event != NULL) {\r | |
482 | // Caller is responcible for signaling EFI Event\r | |
483 | Token->TransactionStatus = Status;\r | |
484 | return EFI_SUCCESS;\r | |
485 | }\r | |
486 | }\r | |
487 | \r | |
d59326d3 | 488 | return Status;\r |
489 | }\r | |
490 | \r | |
d59326d3 | 491 | \r |
033d0e5f | 492 | /**\r |
493 | Flush the Block Device.\r | |
494 | \r | |
495 | If EFI_DEVICE_ERROR, EFI_NO_MEDIA,_EFI_WRITE_PROTECTED or EFI_MEDIA_CHANGED\r | |
496 | is returned and non-blocking I/O is being used, the Event associated with\r | |
497 | this request will not be signaled. \r | |
498 | \r | |
499 | @param[in] This Indicates a pointer to the calling context.\r | |
500 | @param[in,out] Token A pointer to the token associated with the transaction\r | |
501 | \r | |
502 | @retval EFI_SUCCESS The flush request was queued if Event is not NULL.\r | |
503 | All outstanding data was written correctly to the\r | |
504 | device if the Event is NULL.\r | |
505 | @retval EFI_DEVICE_ERROR The device reported an error while writting back\r | |
506 | the data.\r | |
507 | @retval EFI_WRITE_PROTECTED The device cannot be written to.\r | |
508 | @retval EFI_NO_MEDIA There is no media in the device.\r | |
509 | @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.\r | |
510 | @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack\r | |
511 | of resources.\r | |
d59326d3 | 512 | \r |
513 | **/\r | |
033d0e5f | 514 | EFI_STATUS\r |
515 | EmuBlockIoFlushBlocks (\r | |
516 | IN EMU_BLOCK_IO_PROTOCOL *This,\r | |
517 | IN OUT EFI_BLOCK_IO2_TOKEN *Token\r | |
518 | )\r | |
d59326d3 | 519 | {\r |
033d0e5f | 520 | EMU_BLOCK_IO_PRIVATE *Private;\r |
63947cc4 | 521 | int Res;\r |
033d0e5f | 522 | \r |
523 | Private = EMU_BLOCK_IO_PRIVATE_DATA_FROM_THIS (This);\r | |
524 | \r | |
525 | if (Private->fd >= 0) {\r | |
63947cc4 | 526 | Res = fcntl (Private->fd, F_FULLFSYNC);\r |
033d0e5f | 527 | }\r |
528 | \r | |
63947cc4 | 529 | \r |
033d0e5f | 530 | if (Token != NULL) {\r |
531 | if (Token->Event != NULL) {\r | |
532 | // Caller is responcible for signaling EFI Event\r | |
533 | Token->TransactionStatus = EFI_SUCCESS;\r | |
534 | return EFI_SUCCESS;\r | |
535 | }\r | |
536 | }\r | |
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 | |
547 | exhausive verfication operation of the device\r | |
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 | |
582 | \r | |
583 | Size = StrLen (Str) + 1;\r | |
584 | Ascii = malloc (Size);\r | |
585 | if (Ascii == NULL) {\r | |
586 | return NULL;\r | |
587 | }\r | |
588 | \r | |
589 | for (Ptr = Ascii; *Str != '\0'; Ptr++, Str++) {\r | |
590 | *Ptr = *Str;\r | |
591 | }\r | |
592 | *Ptr = 0;\r | |
593 | \r | |
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 | |
613 | \r | |
614 | if (This->Private != NULL) {\r | |
615 | return EFI_ALREADY_STARTED;\r | |
d59326d3 | 616 | }\r |
033d0e5f | 617 | \r |
618 | if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {\r | |
619 | return EFI_UNSUPPORTED;\r | |
620 | }\r | |
621 | \r | |
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 | |
033d0e5f | 627 | \r |
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 | |
033d0e5f | 633 | \r |
634 | Private->Filename = StdDupUnicodeToAscii (This->ConfigString);\r | |
635 | if (Private->Filename == NULL) {\r | |
636 | return EFI_OUT_OF_RESOURCES;\r | |
637 | }\r | |
638 | \r | |
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 | |
657 | \r | |
033d0e5f | 658 | This->Interface = &Private->EmuBlockIo;\r |
659 | This->Private = Private;\r | |
660 | return EFI_SUCCESS;\r | |
d59326d3 | 661 | }\r |
662 | \r | |
663 | \r | |
d59326d3 | 664 | EFI_STATUS\r |
033d0e5f | 665 | EmuBlockIoThunkClose (\r |
666 | IN EMU_IO_THUNK_PROTOCOL *This\r | |
d59326d3 | 667 | )\r |
668 | {\r | |
033d0e5f | 669 | EMU_BLOCK_IO_PRIVATE *Private;\r |
d59326d3 | 670 | \r |
033d0e5f | 671 | if (!CompareGuid (This->Protocol, &gEmuBlockIoProtocolGuid)) {\r |
672 | return EFI_UNSUPPORTED;\r | |
d59326d3 | 673 | }\r |
033d0e5f | 674 | \r |
675 | Private = This->Private;\r | |
676 | \r | |
677 | if (This->Private != NULL) {\r | |
678 | if (Private->Filename != NULL) {\r | |
679 | free (Private->Filename);\r | |
680 | } \r | |
681 | free (This->Private);\r | |
21ce7a41 | 682 | This->Private = NULL;\r |
d59326d3 | 683 | }\r |
033d0e5f | 684 | \r |
685 | return EFI_SUCCESS;\r | |
d59326d3 | 686 | }\r |
033d0e5f | 687 | \r |
688 | \r | |
689 | \r | |
690 | EMU_IO_THUNK_PROTOCOL gBlockIoThunkIo = {\r | |
691 | &gEmuBlockIoProtocolGuid,\r | |
692 | NULL,\r | |
693 | NULL,\r | |
694 | 0,\r | |
695 | GasketBlockIoThunkOpen,\r | |
696 | GasketBlockIoThunkClose,\r | |
697 | NULL\r | |
698 | };\r | |
699 | \r | |
700 | \r |