7

I'm a beginner in UEFI. I'm trying to open a file from my UEFI application. The path of file is

fs1:/myfolder/myfile.txt

The code (With the help of this answer) :

efiStatus = bs->LocateHandleBuffer(ByProtocol, 
                                   &sfspGuid, 
                                   NULL, 
                                   &handleCount, 
                                   &handles);

for (index = 0; index < (int)handleCount; ++ index)
{
    EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* fs = NULL;

    efiStatus = bs->HandleProtocol(
        handles[index],
        &sfspGuid,
        (void**)&fs);

    EFI_FILE_PROTOCOL* root = NULL;
    ...
    efiStatus = fs->OpenVolume(fs, &root);

    EFI_FILE_PROTOCOL* token = NULL;

    efiStatus = root->Open(
        root, 
        &token,
        L"myfolder\\myfile.txt",
        EFI_FILE_MODE_READ,
        EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM);
}

But using this method, I can only go through all the file system handles and open each volume and try opening my file.

But I want to give full path to my file and open it in it's volume.

How can I acheive this?


EDIT:

I tried using Shell APIs for opening the file as suggested by @Alex in comments. Below is the code. But it hangs in function OpenFileByName .

What is the mistake in this code? (argv[ 1 ] would be my file path fs1:\myfile.txt )

EFI_STATUS
EFIAPI
main (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{

    EFI_STATUS      status;
    UINTN           argc;
    CHAR16          **argv;
    SHELL_FILE_HANDLE Handle;

    status = get_args(&argc, &argv);
    if (EFI_ERROR(status)) {
       Print(L"ERROR: Parsing command line arguments: %d\n", status);
       return status;
    }

    if (argc <= 1){
        Print(L"No file name to open\n");
        return (EFI_UNSUPPORTED);  //need to have at least one parameter
    }

    Print(L"File to open is: %s\n", argv[1]);

    status = gEfiShellProtocol->OpenFileByName (argv[1], &Handle, 
        EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE);

    if (EFI_ERROR(status)) {
        Print(L"\nFile Open did not work %s\n", argv[1]);
        return (status);
    }else{
        Print(L"\nFile Open worked %s\n", argv[1]);
        gEfiShellProtocol->CloseFile(Handle);
    }

    return EFI_SUCCESS;
}

And the code hangs even if I try GetCurDir function.

Print(L"Dir: %s \n",gEfiShellProtocol->GetCurDir(NULL));

Any pointers would be helpful.

Community
  • 1
  • 1
Keshava GN
  • 4,195
  • 2
  • 36
  • 47
  • I can see another way of doing this. So, in UEFI everything is a handle thus file is no differ. You can try to create/construct a device path for that particular file and then open handle using that device path. Basically you can clone existing device path for a controller and then add specific nodes for your file. I think that might work. – Alex D Sep 27 '16 at 17:56
  • As a reference I would look into EDK Shell implementation! – Alex D Sep 27 '16 at 18:08
  • Look into EFI_SHELL_OPEN_FILE_BY_NAME of EFI_SHELL_PROTOCOL – Alex D Sep 27 '16 at 18:16
  • Thanks @Alex . Will look into this. – Keshava GN Sep 28 '16 at 03:17
  • @Alex , Can you please look into my edit to the question? I tried Shell APIs as suggested by you, but facing the mentioned issue. Please look into the edit. Thanks – Keshava GN Sep 29 '16 at 13:55
  • Usually EFI hangs in one case when you try to deference a NULL pointer. 1. First make sure you opened successfully EFI_SHELL_PROTOCOL and your gEfiShellProtocol is not NULL. 2. Second you have bugs in your code, you have wide strings but in Print you use %s which is for ASCII! In some cases that might be also the reason for crush. I believe you can use %ls but you have to check it with EFI doc. – Alex D Sep 30 '16 at 17:48
  • @Alex : Yes, It's true that gEfiShellProtocol is NULL in my case. I didn't suspected this first. But when I tried `gBS->OpenProtocol( ImageHandle, &gEfiShellProtocolGuid, (VOID **)&gEfiShellProtocol, ImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL );` it fails. What could be the issue? Thanks – Keshava GN Oct 01 '16 at 06:02
  • Look into the error code. Make sure that the shell protocol is there. How do run you app? If it's launched from boot option than you will not have shell protocol in the environment. If you run the shell first and then your app you should have the shell and opening it should work. – Alex D Oct 05 '16 at 00:15
  • @Alex I'm running the application from shell as `app arg1 arg2` – Keshava GN Oct 05 '16 at 03:58
  • First argument gBS->OpenProtocol( ImageHandle, - it's wrong! It has to be a handle to the protocol interface and not the handle to your binary image! – Alex D Oct 05 '16 at 16:58

1 Answers1

7

Answer to the comment how to get EFI_SHELL_PROTOCOL: The procedure is basically the same as for any Efi protocols. First, grab a handle to the interface:

UINTN BufferSize;
EFI_HANDLE* Buffer;
Status = bs->LocateHandle(ByProtocol, &gEfiShellProtocolGuid, NULL, &BufferSize, Buffer);

Than, allocate and recall with the buffer of the correct size:

    Status = bs->AllocatePool(EfiBootServicesData, BufferSize, &Buffer);

    Status = bs->LocateHandle(ByProtocol, &gEfiShellProtocolGuid, NULL, &BufferSize, Buffer);

Now, you can grab a handle to the protocol. Remember, it's EFI, there might be multiple protocols installed! That's why we have to iterate through all of them. But in this case most likely there will be just one instance of the SHELL protocol:

 UINTN HandleCounter;
 for (HandleCounter = 0 ; HandleCounter < (BufferSize/sizeof(EFI_HANDLE)) ; HandleCounter++)
 {
    Status = bs->OpenProtocol(Buffer[HandleCounter],
                              &gEfiShellProtocolGuid,
                              (VOID**)&gEfiShellProtocol,
                              imageHandle, 
                              NULL,
                              EFI_OPEN_PROTOCOL_GET_PROTOCOL);

And don't forget to check Status for every step!

And of course don't forget:

bs->FreePool(buffer);

As for the protocol itself you don't have to close it. EFI starting from 2.31 doesn't require it anymore.

Alex D
  • 942
  • 1
  • 6
  • 17