| /* |
| * Copyright (C) 2013 David Decotigny <[email protected]> |
| * |
| * Sample EFI shell session, together with drv0_use.efi: |
| * |
| * # Loading first instance: |
| * |
| * fs0:\> load drv0.efi |
| * Driver instance loaded successfully. |
| * load: Image fs0:\drv0.efi loaded at 2FD7C000 - Success |
| * |
| * # Testing 1st instance: |
| * |
| * fs0:\> drv0_use.efi |
| * Playing with driver instance 0... |
| * Hello Sample UEFI Driver! |
| * Hello was called 1 time(s). |
| * |
| * fs0:\> drv0_use.efi |
| * Playing with driver instance 0... |
| * Hello Sample UEFI Driver! |
| * Hello was called 2 time(s). |
| * |
| * # Loading another instance: |
| * |
| * fs0:\> load drv0.efi |
| * Driver instance loaded successfully. |
| * load: Image fs0:\drv0.efi loaded at 2FD6D000 - Success |
| * |
| * # Using both instances: |
| * |
| * fs0:\> drv0_use.efi |
| * Playing with driver instance 0... |
| * Hello Sample UEFI Driver! |
| * Hello was called 3 time(s). |
| * Playing with driver instance 1... |
| * Hello Sample UEFI Driver! |
| * Hello was called 1 time(s). |
| * |
| * fs0:\> drv0_use.efi |
| * Playing with driver instance 0... |
| * Hello Sample UEFI Driver! |
| * Hello was called 4 time(s). |
| * Playing with driver instance 1... |
| * Hello Sample UEFI Driver! |
| * Hello was called 2 time(s). |
| * |
| * # Removing 1st instance: |
| * |
| * fs0:\> dh |
| * Handle dump |
| * 1: Image(DxeCore) |
| * [...] |
| * 79: Image(\/drv0.efi) ImageDevPath (..A,0x800,0x17F7DF)/\/drv0.efi) |
| * 7A: Image(\/drv0.efi) ImageDevPath (..A,0x800,0x17F7DF)/\/drv0.efi) |
| * |
| * fs0:\> unload 79 |
| * 79: Image(\/drv0.efi) ImageDevPath (..A,0x800,0x17F7DF)/\/drv0.efi) |
| * Unload driver image (y/n)? y |
| * Driver instance unloaded. |
| * unload: Success |
| * |
| * # Only 2nd instance remaining: |
| * |
| * fs0:\> drv0_use.efi |
| * Playing with driver instance 0... |
| * Hello Sample UEFI Driver! |
| * Hello was called 3 time(s). |
| * |
| * # Removing 2nd/last instance: |
| * |
| * fs0:\> dh |
| * Handle dump |
| * 1: Image(DxeCore) |
| * [...] |
| * 79: Image(\/drv0.efi) ImageDevPath (..A,0x800,0x17F7DF)/\/drv0.efi) |
| * |
| * fs0:\> unload 79 |
| * 79: Image(\/drv0.efi) ImageDevPath (..A,0x800,0x17F7DF)/\/drv0.efi) |
| * Unload driver image (y/n)? y |
| * Driver instance unloaded. |
| * unload: Success |
| * |
| * # Expect error: no other drv0 instance left |
| * |
| * fs0:\> drv0_use.efi |
| * Error looking up handles for proto: 14 |
| */ |
| |
| #include <efi.h> |
| #include <efilib.h> |
| #include "drv0.h" |
| |
| |
| static const EFI_GUID GnuEfiAppsDrv0ProtocolGuid |
| = GNU_EFI_APPS_DRV0_PROTOCOL_GUID; |
| |
| static struct { |
| GNU_EFI_APPS_DRV0_PROTOCOL Proto; |
| UINTN Counter; |
| } InternalGnuEfiAppsDrv0ProtocolData; |
| |
| |
| static |
| EFI_STATUS |
| EFI_FUNCTION |
| Drv0SayHello( |
| IN struct _GNU_EFI_APPS_DRV0_PROTOCOL *This, |
| IN const CHAR16 *HelloWho |
| ) |
| { |
| if (! HelloWho) |
| return EFI_INVALID_PARAMETER; |
| |
| Print(L"Hello %s!\n", HelloWho); |
| InternalGnuEfiAppsDrv0ProtocolData.Counter ++; |
| return EFI_SUCCESS; |
| } |
| |
| |
| static |
| EFI_STATUS |
| EFI_FUNCTION |
| Drv0GetNumberOfHello( |
| IN struct _GNU_EFI_APPS_DRV0_PROTOCOL *This, |
| OUT UINTN *NumberOfHello |
| ) |
| { |
| if (! NumberOfHello) |
| return EFI_INVALID_PARAMETER; |
| |
| *NumberOfHello = InternalGnuEfiAppsDrv0ProtocolData.Counter; |
| return EFI_SUCCESS; |
| } |
| |
| |
| static |
| EFI_STATUS |
| EFI_FUNCTION |
| Drv0Unload(IN EFI_HANDLE ImageHandle) |
| { |
| LibUninstallProtocolInterfaces(ImageHandle, |
| &GnuEfiAppsDrv0ProtocolGuid, |
| &InternalGnuEfiAppsDrv0ProtocolData.Proto, |
| NULL); |
| Print(L"Driver instance unloaded.\n", ImageHandle); |
| return EFI_SUCCESS; |
| } |
| |
| |
| EFI_STATUS |
| efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SysTab) |
| { |
| EFI_STATUS Status; |
| EFI_LOADED_IMAGE *LoadedImage = NULL; |
| |
| InitializeLib(ImageHandle, SysTab); |
| |
| /* Initialize global protocol definition + data */ |
| InternalGnuEfiAppsDrv0ProtocolData.Proto.SayHello |
| = (GNU_EFI_APPS_DRV0_SAY_HELLO) Drv0SayHello; |
| InternalGnuEfiAppsDrv0ProtocolData.Proto.GetNumberOfHello |
| = (GNU_EFI_APPS_DRV0_GET_NUMBER_OF_HELLO) Drv0GetNumberOfHello; |
| InternalGnuEfiAppsDrv0ProtocolData.Counter = 0; |
| |
| /* Grab handle to this image: we'll attach our proto instance to it */ |
| Status = uefi_call_wrapper(BS->OpenProtocol, 6, |
| ImageHandle, &LoadedImageProtocol, |
| &LoadedImage, ImageHandle, |
| NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); |
| if (EFI_ERROR(Status)) { |
| Print(L"Could not open loaded image protocol: %d\n", Status); |
| return Status; |
| } |
| |
| /* Attach our proto to the current driver image */ |
| Status = LibInstallProtocolInterfaces( |
| &ImageHandle, &GnuEfiAppsDrv0ProtocolGuid, |
| &InternalGnuEfiAppsDrv0ProtocolData.Proto, NULL); |
| if (EFI_ERROR(Status)) { |
| Print(L"Error registering driver instance: %d\n", Status); |
| return Status; |
| } |
| |
| /* Register Unload callback, used to unregister current protocol |
| * instance from system */ |
| LoadedImage->Unload = (EFI_IMAGE_UNLOAD)Drv0Unload; |
| |
| Print(L"Driver instance loaded successfully.\n"); |
| return EFI_SUCCESS; /* at this point, this instance stays resident |
| * until image is unloaded, eg. with shell's unload, |
| * ExitBootServices() */ |
| } |