diff options
| author | Konstantin Aladyshev <aladyshev22@gmail.com> | 2021-07-10 00:04:40 +0300 | 
|---|---|---|
| committer | Konstantin Aladyshev <aladyshev22@gmail.com> | 2021-07-10 00:04:40 +0300 | 
| commit | 6064c1e48b622f53538f4df9bdd402c607a87d51 (patch) | |
| tree | 93d3c937b9568568307fd2ff7053a30c538ad72a /Lessons/Lesson_34 | |
| parent | a9c375c80c3505be794ec2b5d5bb90de27ef0d42 (diff) | |
| download | UEFI-Lessons-6064c1e48b622f53538f4df9bdd402c607a87d51.tar.gz UEFI-Lessons-6064c1e48b622f53538f4df9bdd402c607a87d51.tar.bz2 UEFI-Lessons-6064c1e48b622f53538f4df9bdd402c607a87d51.zip | |
Move lessons to separate folder
Signed-off-by: Konstantin Aladyshev <aladyshev22@gmail.com>
Diffstat (limited to 'Lessons/Lesson_34')
| -rw-r--r-- | Lessons/Lesson_34/README.md | 352 | ||||
| -rw-r--r-- | Lessons/Lesson_34/UefiLessonsPkg/SimpleDriver/SimpleDriver.c | 26 | ||||
| -rw-r--r-- | Lessons/Lesson_34/UefiLessonsPkg/SimpleDriver/SimpleDriver.inf | 19 | 
3 files changed, 397 insertions, 0 deletions
| diff --git a/Lessons/Lesson_34/README.md b/Lessons/Lesson_34/README.md new file mode 100644 index 0000000..933237f --- /dev/null +++ b/Lessons/Lesson_34/README.md @@ -0,0 +1,352 @@ +Let's create a simple UEFI driver. + +Up until now we've created only UEFI applications. The main difference between application and a driver is a fact that application is unloaded from the memory after its execution. But the driver is a thing that stays in memory. And while it stays there it can provide usefull protocols for other applications to use. + + +Let's create a simplest driver UefiLessonsPkg/SimpleDriver/SimpleDriver.inf +``` +[Defines] +  INF_VERSION                    = 1.25 +  BASE_NAME                      = SimpleDriver +  FILE_GUID                      = 384aeb18-105d-4af1-bf17-5e349e8f4d4c +  MODULE_TYPE                    = UEFI_DRIVER +  VERSION_STRING                 = 1.0 +  ENTRY_POINT                    = SimpleDriverEntryPoint + +[Sources] +  SimpleDriver.c + +[Packages] +  MdePkg/MdePkg.dec + +[LibraryClasses] +  UefiDriverEntryPoint +  UefiLib +``` +Things that have changed from our usual INF file: +- The `MODULE_TYPE` is `UEFI_DRIVER` (earlier we've always used `UEFI_APPLICATION`), +- The `ENTRY_POINT` is `SimpleDriverEntryPoint` (earlier we've always used `UefiMain`, but the driver operates with Entry/Unload functions, so it is better to start to give them proper names), +- `UefiDriverEntryPoint` library class is used (earlier we've always used `UefiApplicationEntryPoint`). In case you wonder about `UefiDriverEntryPoint` library internals take a look into https://github.com/tianocore/edk2/tree/master/MdePkg/Library/UefiDriverEntryPoint + +Now let's write *.c source file UefiLessonsPkg/SimpleDriver/SimpleDriver.c + +The only function that we need to implement is our entry function `SimpleDriverEntryPoint` that we've declared: +``` +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> + +EFI_STATUS +EFIAPI +SimpleDriverEntryPoint ( +  IN EFI_HANDLE        ImageHandle, +  IN EFI_SYSTEM_TABLE  *SystemTable +  ) +{ +  Print(L"Hello from driver!\n"); + +  return EFI_SUCCESS; +} +``` + +Include this driver in the components section of our `UefiLessonsPkg/UefiLessonsPkg.dsc`: +``` +[Components] +  ... +  UefiLessonsPkg/SimpleDriver/SimpleDriver.inf +``` +If you try to build, the process would fail: +``` +build.py... +/home/aladyshev/tiano/edk2/UefiLessonsPkg/UefiLessonsPkg.dsc(...): error 4000: Instance of library class [UefiDriverEntryPoint] is not found +        in [/home/aladyshev/tiano/edk2/UefiLessonsPkg/SimpleDriver/SimpleDriver.inf] [X64] +        consumed by module [/home/aladyshev/tiano/edk2/UefiLessonsPkg/SimpleDriver/SimpleDriver.inf] +``` +As usually we need to find proper library implementation: +``` +$ grep UefiDriverEntryPoint -r ./ --exclude-dir=Build | grep LIBRARY_CLASS +./MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf:  LIBRARY_CLASS                  = UefiDriverEntryPoint|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER SMM_CORE DXE_SMM_DRIVER +``` +And place it in our DSC: +``` +[LibraryClasses] +  ... +  UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf +``` + +Build, copy file to our QEMU shared folder and run OVMF. + +First let's try to execute it as an app: +``` +FS0:\> SimpleDriver.efi +The image is not an application. +``` +As you see this action is not possible. + +To load driver we need to use `load` shell command: +``` +FS0:\> load -? -b +Loads a UEFI driver into memory. + +LOAD [-nc] file [file...] + +  -nc  - Loads the driver, but does not connect the driver. +  File - Specifies a file that contains the image of the UEFI driver (wildcards are +         permitted). + +NOTES: +  1. This command loads a driver into memory. It can load multiple files at +     one time. The file name supports wildcards. +  2. If the -nc flag is not specified, this command attempts to connect the +     driver to a proper device. It might also cause previously loaded drivers +     to be connected to their corresponding devices. +  3. Use the 'UNLOAD' command to unload a driver. + +EXAMPLES: +  * To load a driver: +    fs0:\> load Isabus.efi + +  * To load multiple drivers: +    fs0:\> load Isabus.efi IsaSerial.efi + +  * To load multiple drivers using file name wildcards: +    fs0:\> load Isa*.efi + +  * To load a driver without connecting it to a device: +    fs0:\> load -nc IsaBus.efi +``` + +Use this command to load our driver: +``` +FS0:\> load SimpleDriver.efi +Hello from driver! +Image 'FS0:\SimpleDriver.efi' loaded at 6646000 - Success +``` + +Now let's try to use `dh` command to look at our driver handle: +``` +FS0:\> dh -? -b +Displays the device handles in the UEFI environment. + +DH [-l <lang>] [handle | -p <prot_id>] [-d] [-v] + +  -p     - Dumps all handles of a protocol specified by the GUID. +  -d     - Dumps UEFI Driver Model-related information. +  -l     - Dumps information using the language codes (e.g. ISO 639-2). +  -sfo   - Displays information as described in Standard-Format Output. +  -v     - Dumps verbose information about a specific handle. +  handle - Specifies a handle to dump information about (a hexadecimal number). +           If not present, then all information will be dumped. + +NOTES: +  1. When neither 'handle' nor 'prot_id' is specified, a list of all the +     device handles in the UEFI environment is displayed. +  2. The '-d' option displays UEFI Driver Model related information including +     parent handles, child handles, all drivers installed on the handle, etc. +  3. The '-v' option displays verbose information for the specified handle +     including all the protocols on the handle and their details. +  4. If the '-p' option is specified, all handles containing the specified +     protocol will be displayed. Otherwise, the 'handle' parameter has to be +     specified for display. In this case, the '-d' option will be enabled +     automatically if the '-v' option is not specified. + +EXAMPLES: +  * To display all handles and display one screen at a time: +    Shell> dh -b + +  * To display the detailed information on handle 0x30: +    Shell> dh 30 + +  * To display all handles with 'diskio' protocol: +    Shell> dh -p diskio + +  * To display all handles with 'LoadedImage' protocol and break when the screen is +    full: +    Shell> dh -p LoadedImage -b +``` + +If you'll execute it without any parameters, you'll get all handles in the system. And our driver would be the last one: +``` +FS0:\> dh +... +C6: ImageDevicePath(..F,0xFBFC1)/\SimpleDriver.efi) LoadedImage(\SimpleDriver.efi) +``` +You can print more verbose output for our handle: +``` +FS0:\> dh -d -v c6 +C6: 664C998 +ImageDevicePath(664A018) +  PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/\SimpleDriver.efi +LoadedImage(664A440) +  Revision......: 0x00001000 +  ParentHandle..: 6EE5D18 +  SystemTable...: 79EE018 +  DeviceHandle..: 6E36798 +  FilePath......: \SimpleDriver.efi +  PdbFileName...: /home/aladyshev/tiano/edk2/Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/SimpleDriver/SimpleDriver/DEBUG/SimpleDriver.dll +  OptionsSize...: 0 +  LoadOptions...: 0 +  ImageBase.....: 6646000 +  ImageSize.....: 16C0 +  CodeType......: EfiBootServicesCode +  DataType......: EfiBootServicesData +  Unload........: 0 +``` + + +You can load more instanses of our driver, this is not a problem: +``` +FS0:\> load SimpleDriver.efi +Hello from driver! +Image 'FS0:\SimpleDriver.efi' loaded at 6619000 - Success +FS0:\> load SimpleDriver.efi +Hello from driver! +Image 'FS0:\SimpleDriver.efi' loaded at 6617000 - Success +FS0:\> load SimpleDriver.efi +Hello from driver! +Image 'FS0:\SimpleDriver.efi' loaded at 6613000 - Success +``` + +If you look at dh now, there would be multiple handles from our driver: +``` +FS0:\> dh +... +C6: ImageDevicePath(..F,0xFBFC1)/\SimpleDriver.efi) LoadedImage(\SimpleDriver.efi) +C7: ImageDevicePath(..F,0xFBFC1)/\SimpleDriver.efi) LoadedImage(\SimpleDriver.efi) +C8: ImageDevicePath(..F,0xFBFC1)/\SimpleDriver.efi) LoadedImage(\SimpleDriver.efi) +C9: ImageDevicePath(..F,0xFBFC1)/\SimpleDriver.efi) LoadedImage(\SimpleDriver.efi) +``` + +To unload driver from memory you can utilize `unload` command: +``` +FS0:\> unload -? +Unloads a driver image that was already loaded. + +UNLOAD [-n] [-v|-verbose] Handle + +  -n           - Skips all prompts during unloading, so that it can be used +                 in a script file. +  -v, -verbose - Dumps verbose status information before the image is unloaded. +  Handle       - Specifies the handle of driver to unload, always taken as hexadecimal number. + +NOTES: +  1. The '-n' option can be used to skip all prompts during unloading. +  2. If the '-v' option is specified, verbose image information will be +     displayed before the image is unloaded. +  3. Only drivers that support unloading can be successfully unloaded. +  4. Use the 'LOAD' command to load a driver. + +EXAMPLES: +  * To find the handle for the UEFI driver image to unload: +    Shell> dh -b + +  * To unload the UEFI driver image with handle 27: +    Shell> unload 27 +``` + +But it is now possible to use it now as our driver don't have an Unload function. If you'll look at the earlier output of `dh -d -v c6` command, you can see that `Unload........: 0`. + +Therefore if you'll try to unload our driver you'll get an error: +``` +FS0:\> unload c6 +Unload - Handle [664C998].  [y/n]? +y +Unload - Handle [664C998] Result Unsupported. +``` +If you'll execute `dh`, you would still see that our driver handle is still present in the system. + +# Add unload function + +Now let's try add unload function to our driver. Add it to the INF file UefiLessonsPkg/SimpleDriver/SimpleDriver.inf: +``` +[Defines] +  ... +  ENTRY_POINT                    = SimpleDriverEntryPoint ++ UNLOAD_IMAGE                   = SimpleDriverUnload +``` +And add some simple implementation to the *.c file UefiLessonsPkg/SimpleDriver/SimpleDriver.c: +``` +EFI_STATUS +EFIAPI +SimpleDriverUnload ( +  EFI_HANDLE ImageHandle +  ) +{ +  Print(L"Bye-bye from driver!\n"); + +  return EFI_SUCCESS; +} +``` + +If you try to execute `dh -d -v` on the handle from this driver you'll get something like: +``` +FS0:\> dh -d -v c6 +C6: 664CA98 +ImageDevicePath(664C618) +  PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)/\SimpleDriver.efi +LoadedImage(664A240) +  Revision......: 0x00001000 +  ParentHandle..: 6EE5D18 +  SystemTable...: 79EE018 +  DeviceHandle..: 6E36798 +  FilePath......: \SimpleDriver.efi +  PdbFileName...: /home/aladyshev/tiano/edk2/Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/SimpleDriver/SimpleDriver/DEBUG/SimpleDriver.dll +  OptionsSize...: 0 +  LoadOptions...: 0 +  ImageBase.....: 6646000 +  ImageSize.....: 1780 +  CodeType......: EfiBootServicesCode +  DataType......: EfiBootServicesData +  Unload........: 6647047 +``` +As you can see now `Unload` string is filled with a pointer to the driver unload function. + +Before preforming an unload take a look at the ImageBase address with `dmem`: +``` +FS0:\> dmem 6646000 A0 +Memory Address 0000000006646000 A0 Bytes +  06646000: 4D 5A 00 00 00 00 00 00-00 00 00 00 00 00 00 00  *MZ..............* +  06646010: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  *................* +  06646020: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  *................* +  06646030: 00 00 00 00 00 00 00 00-00 00 00 00 80 00 00 00  *................* +  06646040: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  *................* +  06646050: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  *................* +  06646060: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  *................* +  06646070: 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  *................* +  06646080: 50 45 00 00 64 86 02 00-00 00 00 00 00 00 00 00  *PE..d...........* +  06646090: 00 00 00 00 F0 00 2E 00-0B 02 00 00 40 14 00 00  *............@...* +``` +`MZ` signature signifies the header of a PE/COFF image (*.efi file). So our driver is actually there. + +Now perform unload: +``` +FS0:\> unload c6 +Unload - Handle [664CF18].  [y/n]? +y +Bye-bye from driver! +Unload - Handle [664CF18] Result Success. +``` + +Look at the memory again: +``` +FS0:\> dmem 6646000 A0 +Memory Address 0000000006646000 A0 Bytes +  06646000: AF AF AF AF AF AF AF AF-AF AF AF AF AF AF AF AF  *................* +  06646010: AF AF AF AF AF AF AF AF-AF AF AF AF AF AF AF AF  *................* +  06646020: AF AF AF AF AF AF AF AF-AF AF AF AF AF AF AF AF  *................* +  06646030: AF AF AF AF AF AF AF AF-AF AF AF AF AF AF AF AF  *................* +  06646040: AF AF AF AF AF AF AF AF-AF AF AF AF AF AF AF AF  *................* +  06646050: AF AF AF AF AF AF AF AF-AF AF AF AF AF AF AF AF  *................* +  06646060: AF AF AF AF AF AF AF AF-AF AF AF AF AF AF AF AF  *................* +  06646070: AF AF AF AF AF AF AF AF-AF AF AF AF AF AF AF AF  *................* +  06646080: AF AF AF AF AF AF AF AF-AF AF AF AF AF AF AF AF  *................* +  06646090: AF AF AF AF AF AF AF AF-AF AF AF AF AF AF AF AF  *................* +``` +As you can see in was automatically freed. + + +One more notice. If you'll load your image again, it would have a handle with C7 number. Number C6 would be skipped: +``` +C5: ... +C7: ImageDevicePath(..F,0xFBFC1)/\SimpleDriver.efi) LoadedImage(\SimpleDriver.efi) +``` + diff --git a/Lessons/Lesson_34/UefiLessonsPkg/SimpleDriver/SimpleDriver.c b/Lessons/Lesson_34/UefiLessonsPkg/SimpleDriver/SimpleDriver.c new file mode 100644 index 0000000..fd96d17 --- /dev/null +++ b/Lessons/Lesson_34/UefiLessonsPkg/SimpleDriver/SimpleDriver.c @@ -0,0 +1,26 @@ +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiLib.h> + + +EFI_STATUS +EFIAPI +SimpleDriverUnload ( +  EFI_HANDLE ImageHandle +  ) +{ +  Print(L"Bye-bye from driver!\n"); + +  return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SimpleDriverEntryPoint ( +  IN EFI_HANDLE        ImageHandle, +  IN EFI_SYSTEM_TABLE  *SystemTable +  ) +{ +  Print(L"Hello from driver!\n"); + +  return EFI_SUCCESS; +} diff --git a/Lessons/Lesson_34/UefiLessonsPkg/SimpleDriver/SimpleDriver.inf b/Lessons/Lesson_34/UefiLessonsPkg/SimpleDriver/SimpleDriver.inf new file mode 100644 index 0000000..a6008c2 --- /dev/null +++ b/Lessons/Lesson_34/UefiLessonsPkg/SimpleDriver/SimpleDriver.inf @@ -0,0 +1,19 @@ +[Defines] +  INF_VERSION                    = 1.25 +  BASE_NAME                      = SimpleDriver +  FILE_GUID                      = 384aeb18-105d-4af1-bf17-5e349e8f4d4c +  MODULE_TYPE                    = UEFI_DRIVER +  VERSION_STRING                 = 1.0 +  ENTRY_POINT                    = SimpleDriverEntryPoint +  UNLOAD_IMAGE                   = SimpleDriverUnload + +[Sources] +  SimpleDriver.c + +[Packages] +  MdePkg/MdePkg.dec + +[LibraryClasses] +  UefiDriverEntryPoint +  UefiLib + | 
