]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Filesystem/SemihostFs/Arm/SemihostFs.c
ArmPkg: Fixed unsigned type to be architecture independent
[mirror_edk2.git] / ArmPkg / Filesystem / SemihostFs / Arm / SemihostFs.c
1 /** @file
2 Support a Semi Host file system over a debuggers JTAG
3
4 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
5 Portions copyright (c) 2011, 2012, ARM Ltd. All rights reserved.<BR>
6
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include <Uefi.h>
18
19 #include <Guid/FileInfo.h>
20 #include <Guid/FileSystemInfo.h>
21
22 #include <Library/BaseLib.h>
23 #include <Library/BaseMemoryLib.h>
24 #include <Library/DebugLib.h>
25 #include <Library/MemoryAllocationLib.h>
26 #include <Library/SemihostLib.h>
27 #include <Library/UefiBootServicesTableLib.h>
28 #include <Library/UefiLib.h>
29
30 #include <Protocol/DevicePath.h>
31 #include <Protocol/SimpleFileSystem.h>
32
33 #include "SemihostFs.h"
34
35
36 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gSemihostFs = {
37 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION,
38 VolumeOpen
39 };
40
41 EFI_FILE gSemihostFsFile = {
42 EFI_FILE_PROTOCOL_REVISION,
43 FileOpen,
44 FileClose,
45 FileDelete,
46 FileRead,
47 FileWrite,
48 FileGetPosition,
49 FileSetPosition,
50 FileGetInfo,
51 FileSetInfo,
52 FileFlush
53 };
54
55 //
56 // Device path for SemiHosting. It contains our autogened Caller ID GUID.
57 //
58 typedef struct {
59 VENDOR_DEVICE_PATH Guid;
60 EFI_DEVICE_PATH_PROTOCOL End;
61 } SEMIHOST_DEVICE_PATH;
62
63 SEMIHOST_DEVICE_PATH gDevicePath = {
64 {
65 { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH), 0 },
66 EFI_CALLER_ID_GUID
67 },
68 { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, sizeof (EFI_DEVICE_PATH_PROTOCOL), 0}
69 };
70
71 typedef struct {
72 LIST_ENTRY Link;
73 UINT64 Signature;
74 EFI_FILE File;
75 CHAR8 *FileName;
76 UINT32 Position;
77 UINTN SemihostHandle;
78 BOOLEAN IsRoot;
79 } SEMIHOST_FCB;
80
81 #define SEMIHOST_FCB_SIGNATURE SIGNATURE_32( 'S', 'H', 'F', 'C' )
82 #define SEMIHOST_FCB_FROM_THIS(a) CR(a, SEMIHOST_FCB, File, SEMIHOST_FCB_SIGNATURE)
83 #define SEMIHOST_FCB_FROM_LINK(a) CR(a, SEMIHOST_FCB, Link, SEMIHOST_FCB_SIGNATURE);
84
85 EFI_HANDLE gInstallHandle = NULL;
86 LIST_ENTRY gFileList = INITIALIZE_LIST_HEAD_VARIABLE (gFileList);
87
88 SEMIHOST_FCB *
89 AllocateFCB (
90 VOID
91 )
92 {
93 SEMIHOST_FCB *Fcb = AllocateZeroPool (sizeof (SEMIHOST_FCB));
94
95 if (Fcb != NULL) {
96 CopyMem (&Fcb->File, &gSemihostFsFile, sizeof (gSemihostFsFile));
97 Fcb->Signature = SEMIHOST_FCB_SIGNATURE;
98 }
99
100 return Fcb;
101 }
102
103 VOID
104 FreeFCB (
105 IN SEMIHOST_FCB *Fcb
106 )
107 {
108 // Remove Fcb from gFileList.
109 RemoveEntryList (&Fcb->Link);
110
111 // To help debugging...
112 Fcb->Signature = 0;
113
114 FreePool (Fcb);
115 }
116
117
118
119 EFI_STATUS
120 VolumeOpen (
121 IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
122 OUT EFI_FILE **Root
123 )
124 {
125 SEMIHOST_FCB *RootFcb = NULL;
126
127 if (Root == NULL) {
128 return EFI_INVALID_PARAMETER;
129 }
130
131 RootFcb = AllocateFCB ();
132 if (RootFcb == NULL) {
133 return EFI_OUT_OF_RESOURCES;
134 }
135
136 RootFcb->IsRoot = TRUE;
137
138 InsertTailList (&gFileList, &RootFcb->Link);
139
140 *Root = &RootFcb->File;
141
142 return EFI_SUCCESS;
143 }
144
145 EFI_STATUS
146 FileOpen (
147 IN EFI_FILE *File,
148 OUT EFI_FILE **NewHandle,
149 IN CHAR16 *FileName,
150 IN UINT64 OpenMode,
151 IN UINT64 Attributes
152 )
153 {
154 SEMIHOST_FCB *FileFcb = NULL;
155 EFI_STATUS Status = EFI_SUCCESS;
156 UINTN SemihostHandle;
157 CHAR8 *AsciiFileName;
158 CHAR8 *AsciiPtr;
159 UINTN Length;
160 UINT32 SemihostMode;
161 BOOLEAN IsRoot;
162
163 if ((FileName == NULL) || (NewHandle == NULL)) {
164 return EFI_INVALID_PARAMETER;
165 }
166
167 // Semihost interface requires ASCII filesnames
168 Length = StrSize (FileName);
169
170 AsciiFileName = AllocatePool (Length);
171 if (AsciiFileName == NULL) {
172 return EFI_OUT_OF_RESOURCES;
173 }
174
175 AsciiPtr = AsciiFileName;
176
177 while (Length--) {
178 *AsciiPtr++ = *FileName++ & 0xFF;
179 }
180
181 if ((AsciiStrCmp (AsciiFileName, "\\") == 0) ||
182 (AsciiStrCmp (AsciiFileName, "/") == 0) ||
183 (AsciiStrCmp (AsciiFileName, "") == 0) ||
184 (AsciiStrCmp (AsciiFileName, ".") == 0)) {
185 // Opening '/', '\', '.', or the NULL pathname is trying to open the root directory
186 IsRoot = TRUE;
187
188 // Root directory node doesn't have a name.
189 FreePool (AsciiFileName);
190 AsciiFileName = NULL;
191 } else {
192 // Translate EFI_FILE_MODE into Semihosting mode
193 if (OpenMode & EFI_FILE_MODE_WRITE) {
194 SemihostMode = SEMIHOST_FILE_MODE_WRITE | SEMIHOST_FILE_MODE_BINARY;
195 } else if (OpenMode & EFI_FILE_MODE_READ) {
196 SemihostMode = SEMIHOST_FILE_MODE_READ | SEMIHOST_FILE_MODE_BINARY;
197 } else {
198 return EFI_UNSUPPORTED;
199 }
200
201 // Add the creation flag if necessary
202 if (OpenMode & EFI_FILE_MODE_CREATE) {
203 SemihostMode |= SEMIHOST_FILE_MODE_CREATE;
204 }
205
206 // Call the semihosting interface to open the file.
207 Status = SemihostFileOpen (AsciiFileName, SemihostMode, &SemihostHandle);
208 if (EFI_ERROR(Status)) {
209 return Status;
210 }
211
212 IsRoot = FALSE;
213 }
214
215 // Allocate a control block and fill it
216 FileFcb = AllocateFCB ();
217 if (FileFcb == NULL) {
218 return EFI_OUT_OF_RESOURCES;
219 }
220
221 FileFcb->FileName = AsciiFileName;
222 FileFcb->SemihostHandle = SemihostHandle;
223 FileFcb->Position = 0;
224 FileFcb->IsRoot = IsRoot;
225
226 InsertTailList (&gFileList, &FileFcb->Link);
227
228 *NewHandle = &FileFcb->File;
229
230 return Status;
231 }
232
233
234 EFI_STATUS
235 FileClose (
236 IN EFI_FILE *File
237 )
238 {
239 SEMIHOST_FCB *Fcb = NULL;
240 EFI_STATUS Status = EFI_SUCCESS;
241
242 Fcb = SEMIHOST_FCB_FROM_THIS(File);
243
244 if (Fcb->IsRoot == TRUE) {
245 FreeFCB (Fcb);
246 Status = EFI_SUCCESS;
247 } else {
248 Status = SemihostFileClose (Fcb->SemihostHandle);
249 if (!EFI_ERROR(Status)) {
250 FreePool (Fcb->FileName);
251 FreeFCB (Fcb);
252 }
253 }
254
255 return Status;
256 }
257
258 EFI_STATUS
259 FileDelete (
260 IN EFI_FILE *File
261 )
262 {
263 SEMIHOST_FCB *Fcb = NULL;
264 EFI_STATUS Status;
265 CHAR8 *FileName;
266 UINTN NameSize;
267
268 Fcb = SEMIHOST_FCB_FROM_THIS(File);
269
270 if (!Fcb->IsRoot) {
271 // Get the filename from the Fcb
272 NameSize = AsciiStrLen (Fcb->FileName);
273 FileName = AllocatePool (NameSize + 1);
274
275 AsciiStrCpy (FileName, Fcb->FileName);
276
277 // Close the file if it's open. Disregard return status,
278 // since it might give an error if the file isn't open.
279 File->Close (File);
280
281 // Call the semihost interface to delete the file.
282 Status = SemihostFileRemove (FileName);
283 } else {
284 Status = EFI_UNSUPPORTED;
285 }
286
287 return Status;
288 }
289
290 EFI_STATUS
291 FileRead (
292 IN EFI_FILE *File,
293 IN OUT UINTN *BufferSize,
294 OUT VOID *Buffer
295 )
296 {
297 SEMIHOST_FCB *Fcb = NULL;
298 EFI_STATUS Status;
299
300 Fcb = SEMIHOST_FCB_FROM_THIS(File);
301
302 if (Fcb->IsRoot == TRUE) {
303 Status = EFI_UNSUPPORTED;
304 } else {
305 Status = SemihostFileRead (Fcb->SemihostHandle, BufferSize, Buffer);
306 if (!EFI_ERROR (Status)) {
307 Fcb->Position += *BufferSize;
308 }
309 }
310
311 return Status;
312 }
313
314 EFI_STATUS
315 FileWrite (
316 IN EFI_FILE *File,
317 IN OUT UINTN *BufferSize,
318 IN VOID *Buffer
319 )
320 {
321 SEMIHOST_FCB *Fcb = NULL;
322 EFI_STATUS Status;
323 UINTN WriteSize = *BufferSize;
324
325 Fcb = SEMIHOST_FCB_FROM_THIS(File);
326
327 Status = SemihostFileWrite (Fcb->SemihostHandle, &WriteSize, Buffer);
328
329 if (!EFI_ERROR(Status)) {
330 // Semihost write return the number of bytes *NOT* written.
331 *BufferSize -= WriteSize;
332 Fcb->Position += *BufferSize;
333 }
334
335 return Status;
336 }
337
338 EFI_STATUS
339 FileGetPosition (
340 IN EFI_FILE *File,
341 OUT UINT64 *Position
342 )
343 {
344 SEMIHOST_FCB *Fcb = NULL;
345
346 if (Position == NULL) {
347 return EFI_INVALID_PARAMETER;
348 }
349
350 Fcb = SEMIHOST_FCB_FROM_THIS(File);
351
352 *Position = Fcb->Position;
353
354 return EFI_SUCCESS;
355 }
356
357 EFI_STATUS
358 FileSetPosition (
359 IN EFI_FILE *File,
360 IN UINT64 Position
361 )
362 {
363 SEMIHOST_FCB *Fcb = NULL;
364 UINTN Length;
365 EFI_STATUS Status;
366
367 Fcb = SEMIHOST_FCB_FROM_THIS(File);
368
369 if (!Fcb->IsRoot) {
370 Status = SemihostFileLength (Fcb->SemihostHandle, &Length);
371 if (!EFI_ERROR(Status) && (Length < Position)) {
372 Position = Length;
373 }
374
375 Status = SemihostFileSeek (Fcb->SemihostHandle, (UINT32)Position);
376 if (!EFI_ERROR(Status)) {
377 Fcb->Position = Position;
378 }
379 } else {
380 Fcb->Position = Position;
381 Status = EFI_SUCCESS;
382 }
383
384 return Status;
385 }
386
387 STATIC
388 EFI_STATUS
389 GetFileInfo (
390 IN SEMIHOST_FCB *Fcb,
391 IN OUT UINTN *BufferSize,
392 OUT VOID *Buffer
393 )
394 {
395 EFI_FILE_INFO *Info = NULL;
396 UINTN NameSize = 0;
397 UINTN ResultSize;
398 UINTN Index;
399 UINTN Length;
400 EFI_STATUS Status;
401
402 if (Fcb->IsRoot == TRUE) {
403 ResultSize = SIZE_OF_EFI_FILE_INFO + sizeof(CHAR16);
404 } else {
405 NameSize = AsciiStrLen (Fcb->FileName) + 1;
406 ResultSize = SIZE_OF_EFI_FILE_INFO + NameSize * sizeof (CHAR16);
407 }
408
409 if (*BufferSize < ResultSize) {
410 *BufferSize = ResultSize;
411 return EFI_BUFFER_TOO_SMALL;
412 }
413
414 Info = Buffer;
415
416 // Zero out the structure
417 ZeroMem (Info, SIZE_OF_EFI_FILE_INFO);
418
419 // Fill in the structure
420 Info->Size = ResultSize;
421
422 if (Fcb->IsRoot == TRUE) {
423 Info->Attribute = EFI_FILE_READ_ONLY | EFI_FILE_DIRECTORY;
424 Info->FileName[0] = L'\0';
425 } else {
426 Status = SemihostFileLength (Fcb->SemihostHandle, &Length);
427 if (EFI_ERROR(Status)) {
428 return Status;
429 }
430
431 Info->FileSize = Length;
432 Info->PhysicalSize = Length;
433
434 for (Index = 0; Index < NameSize; Index++) {
435 Info->FileName[Index] = Fcb->FileName[Index];
436 }
437 }
438
439
440 *BufferSize = ResultSize;
441
442 return EFI_SUCCESS;
443 }
444
445 STATIC
446 EFI_STATUS
447 GetFilesystemInfo (
448 IN SEMIHOST_FCB *Fcb,
449 IN OUT UINTN *BufferSize,
450 OUT VOID *Buffer
451 )
452 {
453 EFI_FILE_SYSTEM_INFO *Info = NULL;
454 EFI_STATUS Status;
455 STATIC CHAR16 Label[] = L"SemihostFs";
456 UINTN ResultSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize(Label);
457
458 if(*BufferSize >= ResultSize) {
459 ZeroMem (Buffer, ResultSize);
460 Status = EFI_SUCCESS;
461
462 Info = Buffer;
463
464 Info->Size = ResultSize;
465 Info->ReadOnly = FALSE;
466 Info->VolumeSize = 0;
467 Info->FreeSpace = 0;
468 Info->BlockSize = 0;
469
470 StrCpy (Info->VolumeLabel, Label);
471 } else {
472 Status = EFI_BUFFER_TOO_SMALL;
473 }
474
475 *BufferSize = ResultSize;
476 return Status;
477 }
478
479 EFI_STATUS
480 FileGetInfo (
481 IN EFI_FILE *File,
482 IN EFI_GUID *InformationType,
483 IN OUT UINTN *BufferSize,
484 OUT VOID *Buffer
485 )
486 {
487 SEMIHOST_FCB *Fcb = NULL;
488 EFI_STATUS Status = EFI_UNSUPPORTED;
489
490 Fcb = SEMIHOST_FCB_FROM_THIS(File);
491
492 if (CompareGuid(InformationType, &gEfiFileSystemInfoGuid) != 0) {
493 Status = GetFilesystemInfo(Fcb, BufferSize, Buffer);
494 } else if (CompareGuid(InformationType, &gEfiFileInfoGuid) != 0) {
495 Status = GetFileInfo(Fcb, BufferSize, Buffer);
496 }
497
498 return Status;
499 }
500
501 EFI_STATUS
502 FileSetInfo (
503 IN EFI_FILE *File,
504 IN EFI_GUID *InformationType,
505 IN UINTN BufferSize,
506 IN VOID *Buffer
507 )
508 {
509 return EFI_UNSUPPORTED;
510 }
511
512 EFI_STATUS
513 FileFlush (
514 IN EFI_FILE *File
515 )
516 {
517 return EFI_SUCCESS;
518 }
519
520 EFI_STATUS
521 SemihostFsEntryPoint (
522 IN EFI_HANDLE ImageHandle,
523 IN EFI_SYSTEM_TABLE *SystemTable
524 )
525 {
526 EFI_STATUS Status = EFI_NOT_FOUND;
527
528 if (SemihostConnectionSupported ()) {
529 Status = gBS->InstallMultipleProtocolInterfaces (
530 &gInstallHandle,
531 &gEfiSimpleFileSystemProtocolGuid, &gSemihostFs,
532 &gEfiDevicePathProtocolGuid, &gDevicePath,
533 NULL
534 );
535 }
536
537 return Status;
538 }
539