From b2a2a1fa80dd57be7d5445f1c2fbbe25feedd39d Mon Sep 17 00:00:00 2001 From: Nigel Croxon Date: Tue, 25 Jun 2013 08:53:58 -0400 Subject: [PATCH 3/3] Sample boot service driver. Signed-off-by: David Decotigny --- apps/Makefile | 11 +++- apps/drv0.c | 193 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ apps/drv0.h | 37 +++++++++++ apps/drv0_use.c | 79 +++++++++++++++++++++++ 4 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 apps/drv0.c create mode 100644 apps/drv0.h create mode 100644 apps/drv0_use.c diff --git a/apps/Makefile b/apps/Makefile index 6834e14..8643ba1 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -60,10 +60,19 @@ LOADLIBES += -T $(LDSCRIPT) FORMAT = efi-app-$(ARCH) -TARGETS = t.efi t2.efi t3.efi t4.efi t5.efi t6.efi printenv.efi t7.efi tcc.efi modelist.efi route80h.efi +TARGET_APPS = t.efi t2.efi t3.efi t4.efi t5.efi t6.efi \ + printenv.efi t7.efi tcc.efi modelist.efi \ + route80h.efi drv0_use.efi +TARGET_BSDRIVERS = drv0.efi +TARGET_RTDRIVERS = + +TARGETS = $(TARGET_APPS) $(TARGET_BSDRIVERS) $(TARGET_RTDRIVERS) all: $(TARGETS) +$(TARGET_BSDRIVERS): FORMAT=efi-bsdrv-$(ARCH) +$(TARGET_RTDRIVERS): FORMAT=efi-rtdrv-$(ARCH) + clean: rm -f $(TARGETS) *~ *.o *.so diff --git a/apps/drv0.c b/apps/drv0.c new file mode 100644 index 0000000..126e8e7 --- /dev/null +++ b/apps/drv0.c @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2013 David Decotigny + * + * 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 +#include +#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() */ +} diff --git a/apps/drv0.h b/apps/drv0.h new file mode 100644 index 0000000..26d2ffd --- /dev/null +++ b/apps/drv0.h @@ -0,0 +1,37 @@ +#ifndef _GNU_EFI_APPS_DRV0_H_ +#define _GNU_EFI_APPS_DRV0_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* UEFI naming conventions */ +#define GNU_EFI_APPS_DRV0_PROTOCOL_GUID \ +{ 0xe4dcafd0, 0x586c, 0x4b3d, {0x86, 0xe7, 0x28, 0xde, 0x7f, 0xcc, 0x04, 0xb8} } + +INTERFACE_DECL(_GNU_EFI_APPS_DRV0_PROTOCOL); + +typedef +EFI_STATUS +(EFIAPI *GNU_EFI_APPS_DRV0_SAY_HELLO) ( + IN struct _GNU_EFI_APPS_DRV0_PROTOCOL *This, + IN const CHAR16 *HelloWho + ); + +typedef +EFI_STATUS +(EFIAPI *GNU_EFI_APPS_DRV0_GET_NUMBER_OF_HELLO) ( + IN struct _GNU_EFI_APPS_DRV0_PROTOCOL *This, + OUT UINTN *NumberOfHello + ); + +typedef struct _GNU_EFI_APPS_DRV0_PROTOCOL { + GNU_EFI_APPS_DRV0_SAY_HELLO SayHello; + GNU_EFI_APPS_DRV0_GET_NUMBER_OF_HELLO GetNumberOfHello; +} GNU_EFI_APPS_DRV0_PROTOCOL; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/apps/drv0_use.c b/apps/drv0_use.c new file mode 100644 index 0000000..f7c5869 --- /dev/null +++ b/apps/drv0_use.c @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2013 David Decotigny + * + * See drv0.c for an example session. + */ + +#include +#include +#include "drv0.h" + + +static EFI_GUID GnuEfiAppsDrv0ProtocolGuid + = GNU_EFI_APPS_DRV0_PROTOCOL_GUID; + + +static +EFI_STATUS +PlayWithGnuEfiAppsDrv0Protocol(IN EFI_HANDLE DrvHandle) { + EFI_STATUS Status; + GNU_EFI_APPS_DRV0_PROTOCOL *drv = NULL; + UINTN NumberOfHello = 0; + + Status = uefi_call_wrapper(BS->OpenProtocol, 6, + DrvHandle, + &GnuEfiAppsDrv0ProtocolGuid, + &drv, + DrvHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (EFI_ERROR(Status)) { + Print(L"Cannot open proto: %d\n", Status); + return Status; + } + + Status = uefi_call_wrapper(drv->SayHello, 2, drv, L"Sample UEFI Driver"); + if (EFI_ERROR(Status)) { + Print(L"Cannot call SayHello: %d\n", Status); + } + + Status = uefi_call_wrapper(drv->GetNumberOfHello, 2, drv, &NumberOfHello); + if (EFI_ERROR(Status)) { + Print(L"Cannot call GetNumberOfHello: %d\n", Status); + } else { + Print(L"Hello was called %d time(s).\n", NumberOfHello); + } + + return EFI_SUCCESS; +} + + +EFI_STATUS +efi_main (EFI_HANDLE Image, EFI_SYSTEM_TABLE *SysTab) +{ + EFI_STATUS Status; + EFI_HANDLE *Handles = NULL; + UINTN i, NoHandles = 0; + + InitializeLib(Image, SysTab); + + Status = LibLocateHandle(ByProtocol, &GnuEfiAppsDrv0ProtocolGuid, + NULL, &NoHandles, &Handles); + if (EFI_ERROR(Status)) { + Print(L"Error looking up handles for proto: %d\n", Status); + return Status; + } + + for (i = 0 ; i < NoHandles ; ++i) + { + Print(L"Playing with driver instance %d...\n", i); + Status = PlayWithGnuEfiAppsDrv0Protocol(Handles[i]); + if (EFI_ERROR(Status)) + Print(L"Error playing with instance %d, skipping\n", i); + } + + if (Handles) + FreePool(Handles); + + return EFI_SUCCESS; +} -- 1.8.3.1