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