aboutsummaryrefslogtreecommitdiffstats
path: root/Lessons/Lesson_14/README.md
diff options
context:
space:
mode:
authorKonstantin Aladyshev <aladyshev22@gmail.com>2021-07-10 00:04:40 +0300
committerKonstantin Aladyshev <aladyshev22@gmail.com>2021-07-10 00:04:40 +0300
commit6064c1e48b622f53538f4df9bdd402c607a87d51 (patch)
tree93d3c937b9568568307fd2ff7053a30c538ad72a /Lessons/Lesson_14/README.md
parenta9c375c80c3505be794ec2b5d5bb90de27ef0d42 (diff)
downloadUEFI-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_14/README.md')
-rw-r--r--Lessons/Lesson_14/README.md427
1 files changed, 427 insertions, 0 deletions
diff --git a/Lessons/Lesson_14/README.md b/Lessons/Lesson_14/README.md
new file mode 100644
index 0000000..abf8f44
--- /dev/null
+++ b/Lessons/Lesson_14/README.md
@@ -0,0 +1,427 @@
+In this lesson we'll try to print all the runtime variables available in our system.
+
+To do it, we need to use `GetNextVariableName()` API function from EFI Runtime Services:
+```
+GetNextVariableName()
+
+Summary:
+Enumerates the current variable names.
+
+Prototype:
+typedef
+EFI_STATUS
+GetNextVariableName (
+ IN OUT UINTN *VariableNameSize,
+ IN OUT CHAR16 *VariableName,
+ IN OUT EFI_GUID *VendorGuid
+ );
+
+Parameters:
+VariableNameSize The size of the VariableName buffer. The size must be large
+ enough to fit input string supplied in VariableName buffer.
+VariableName On input, supplies the last VariableName that was returned by
+ GetNextVariableName(). On output, returns the Nullterminated string
+ of the current variable.
+VendorGuid On input, supplies the last VendorGuid that was returned by
+ GetNextVariableName(). On output, returns the VendorGuid
+ of the current variable.
+
+Description
+GetNextVariableName() is called multiple times to retrieve the VariableName and VendorGuid of all
+variables currently available in the system. On each call to GetNextVariableName() the previous
+results are passed into the interface, and on output the interface returns the next variable name data.
+When the entire variable list has been returned, the error EFI_NOT_FOUND is returned.
+
+Note that if EFI_BUFFER_TOO_SMALL is returned, the VariableName buffer was too small for the next
+variable. When such an error occurs, the VariableNameSize is updated to reflect the size of buffer
+needed. In all cases when calling GetNextVariableName() the VariableNameSize must not exceed the
+actual buffer size that was allocated for VariableName. The VariableNameSize must not be smaller the size
+of the variable name string passed to GetNextVariableName() on input in the VariableName buffer.
+
+To start the search, a Null-terminated string is passed in VariableName; that is, VariableName is a pointer
+to a Null character. This is always done on the initial call to GetNextVariableName(). When
+VariableName is a pointer to a Null character, VendorGuid is ignored.
+
+
+Status Codes Returned:
+EFI_SUCCESS The function completed successfully.
+EFI_NOT_FOUND The next variable was not found.
+EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result.
+ VariableNameSize has been updated with the size needed to complete the request.
+...
+```
+
+
+Earlier we've included `#include <Library/UefiBootServicesTableLib.h>` in our file to get `gST`/`gBS`
+To get shortcut for the EFI Runtime Services Table we need to add similar include:
+```
+#include <Library/UefiRuntimeServicesTableLib.h>
+```
+You can look at this file (https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.c), but it simply adds `extern EFI_RUNTIME_SERVICES *gRT;` which is filled as `gRT = SystemTable->RuntimeServices;` in a library constructor call https://github.com/tianocore/edk2/blob/master/MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.c
+
+As spec says to start a search we need to create a string with 1 character that equals Null (=0).
+To create such a string we will use `AllocateZeroPool` function.
+```
+UINTN VariableNameSize = sizeof (CHAR16);
+CHAR16* VariableName = AllocateZeroPool(sizeof(CHAR16));
+```
+
+`AllocateZeroPool` is not a UEFI spec function but simply is a helper from the edk2 MemoryAllocationLib (https://github.com/tianocore/edk2/blob/master/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c):
+```
+/ **
+ Allocates and zeros a buffer of type EfiBootServicesData.
+ ...
+ @param AllocationSize The number of bytes to allocate and zero.
+
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+**/
+
+VOID *
+EFIAPI
+AllocateZeroPool (
+ IN UINTN AllocationSize
+ )
+```
+
+This string is obviously wouldn't be enough to store variable names, so we definitely would get `EFI_BUFFER_TOO_SMALL` at least on the first call.
+In this case we need to reallocate our buffer. We could do it with the help of `ReallocatePool` function.
+
+`RealocatePool` is another helper function from the edk2 MemoryAllocationLib (https://github.com/tianocore/edk2/blob/master/MdePkg/Library/PeiMemoryAllocationLib/MemoryAllocationLib.c):
+```
+/**
+ Reallocates a buffer of type EfiBootServicesData.
+ ...
+ @param OldSize The size, in bytes, of OldBuffer.
+ @param NewSize The size, in bytes, of the buffer to reallocate.
+ @param OldBuffer The buffer to copy to the allocated buffer. This is an optional
+ parameter that may be NULL.
+ @return A pointer to the allocated buffer or NULL if allocation fails.
+**/
+
+VOID *
+EFIAPI
+ReallocatePool (
+ IN UINTN OldSize,
+ IN UINTN NewSize,
+ IN VOID *OldBuffer OPTIONAL
+ )
+```
+
+Let's create `ListVariables` app and try to print first variable:
+```
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+ EFI_GUID VendorGuid;
+ UINTN VariableNameSize = sizeof (CHAR16);
+ CHAR16* VariableName = AllocateZeroPool(sizeof(CHAR16));
+ if (VariableName == NULL) {
+ Print(L"Error on AllocateZeroPool call\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UINTN VariableNameSizeOld = VariableNameSize;
+ EFI_STATUS Status = gRT->GetNextVariableName(&VariableNameSize, VariableName, &VendorGuid);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ VariableName = ReallocatePool(VariableNameSizeOld, VariableNameSize, VariableName);
+ if (VariableName == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = gRT->GetNextVariableName(&VariableNameSize, VariableName, &VendorGuid);
+ if (Status == EFI_SUCCESS) {
+ Print(L"%g: %s\n", VendorGuid, VariableName);
+ } else {
+ Print(L"Error on 'gRT->GetNextVariableName' call: %s\n", Status);
+ return Status;
+ }
+ } else {
+ Print(L"Error on 'gRT->GetNextVariableName' call: %s\n", Status);
+ return Status;
+ }
+ FreePool(VariableName);
+ return EFI_SUCCESS;
+}
+```
+
+If we try to execute it under OVMF we would get:
+```
+FS0:\> ListVariables.efi
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: OsIndicationsSupported
+```
+
+Now we need to create a loop to print all the available variables.
+```
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+ EFI_GUID VendorGuid;
+ UINTN VariableNameSize = sizeof (CHAR16);
+ CHAR16* VariableName = AllocateZeroPool(sizeof(CHAR16));
+ if (VariableName == NULL) {
+ rint(L"Error on AllocateZeroPool call\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ while (TRUE)
+ {
+ UINTN VariableNameSizeOld = VariableNameSize;
+ EFI_STATUS Status = gRT->GetNextVariableName(&VariableNameSize, VariableName, &VendorGuid);
+ if (Status == EFI_SUCCESS) {
+ Print(L"%g: %s\n", VendorGuid, VariableName);
+ } else if (Status == EFI_BUFFER_TOO_SMALL) {
+ VariableName = ReallocatePool(VariableNameSizeOld, VariableNameSize, VariableName);
+ if (VariableName == NULL) {
+ Print(L"Error on ReallocatePool call\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = gRT->GetNextVariableName(&VariableNameSize, VariableName, &VendorGuid);
+ if (Status == EFI_SUCCESS) {
+ Print(L"%g: %s\n", VendorGuid, VariableName);
+ } else {
+ Print(L"Error on 'gRT->GetNextVariableName' call: %s\n", Status);
+ return Status;
+ }
+ } else if (Status == EFI_NOT_FOUND) {
+ FreePool(VariableName);
+ return EFI_SUCCESS;
+ } else {
+ Print(L"Error on 'gRT->GetNextVariableName' call: %s\n", Status);
+ return Status;
+ }
+ }
+ return EFI_SUCCESS;
+}
+```
+
+Inside `while(TRUE)` loop we continiously run `gRT->GetNextVariableName` function and look for its returned `EFI_STATUS` code:
+- `EFI_SUCCESS` means variable is successfully acquired, so we simply print it,
+- `EFI_BUFFER_TOO_SMALL` means we need to grow our array with the `RealocatePool` API and call `gRT->GetNextVariableName` again,
+- `EFI_NOT_FOUND` means we've parsed all variables and need to stop,
+- on another status we simply return with error.
+
+
+If we now run our program under OVMF we would get something like this:
+```
+FS0:\> ListVariables.efi
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: OsIndicationsSupported
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: BootOptionSupport
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: LangCodes
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: PlatformLangCodes
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: PlatformRecovery0000
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: ConOutDev
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: ErrOutDev
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: ConInDev
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: BootCurrent
+158DEF5A-F656-419C-B027-7A3192C079D2: path
+158DEF5A-F656-419C-B027-7A3192C079D2: nonesting
+0053D9D6-2659-4599-A26B-EF4536E631A9: cat
+0053D9D6-2659-4599-A26B-EF4536E631A9: cd..
+0053D9D6-2659-4599-A26B-EF4536E631A9: cd\
+0053D9D6-2659-4599-A26B-EF4536E631A9: copy
+0053D9D6-2659-4599-A26B-EF4536E631A9: del
+0053D9D6-2659-4599-A26B-EF4536E631A9: dir
+0053D9D6-2659-4599-A26B-EF4536E631A9: md
+0053D9D6-2659-4599-A26B-EF4536E631A9: mem
+0053D9D6-2659-4599-A26B-EF4536E631A9: mount
+0053D9D6-2659-4599-A26B-EF4536E631A9: move
+0053D9D6-2659-4599-A26B-EF4536E631A9: ren
+158DEF5A-F656-419C-B027-7A3192C079D2: profiles
+158DEF5A-F656-419C-B027-7A3192C079D2: uefishellsupport
+158DEF5A-F656-419C-B027-7A3192C079D2: uefishellversion
+158DEF5A-F656-419C-B027-7A3192C079D2: uefiversion
+158DEF5A-F656-419C-B027-7A3192C079D2: cwd
+158DEF5A-F656-419C-B027-7A3192C079D2: debuglasterror
+158DEF5A-F656-419C-B027-7A3192C079D2: lasterror
+59324945-EC44-4C0D-B1CD-9DB139DF070C: Attempt 1
+59324945-EC44-4C0D-B1CD-9DB139DF070C: Attempt 2
+59324945-EC44-4C0D-B1CD-9DB139DF070C: Attempt 3
+59324945-EC44-4C0D-B1CD-9DB139DF070C: Attempt 4
+59324945-EC44-4C0D-B1CD-9DB139DF070C: Attempt 5
+59324945-EC44-4C0D-B1CD-9DB139DF070C: Attempt 6
+59324945-EC44-4C0D-B1CD-9DB139DF070C: Attempt 7
+4B47D616-A8D6-4552-9D44-CCAD2E0F4CF9: InitialAttemptOrder
+59324945-EC44-4C0D-B1CD-9DB139DF070C: Attempt 8
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: Boot0000
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: Timeout
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: PlatformLang
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: Lang
+04B37FE8-F6AE-480B-BDD5-37D98C5E89AA: VarErrorFlag
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: Key0000
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: Key0001
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: Boot0001
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: Boot0002
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: Boot0003
+4C19049F-4137-4DD3-9C10-8B97A83FFDFA: MemoryTypeInformation
+5B446ED1-E30B-4FAA-871A-3654ECA36080: 525400123456
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: BootOrder
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: Boot0004
+EB704011-1402-11D3-8E77-00A0C969723B: MTC
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: ConOut
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: ConIn
+8BE4DF61-93CA-11D2-AA0D-00E098032B8C: ErrOut
+```
+
+The most important group is `8BE4DF61-93CA-11D2-AA0D-00E098032B8C`. It stands for `EFI_GLOBAL_VARIABLE` and is defined in UEFI spec. In edk2 you can find it under https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Guid/GlobalVariable.h:
+```
+#define EFI_GLOBAL_VARIABLE \
+ { \
+ 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C } \
+ }
+
+extern EFI_GUID gEfiGlobalVariableGuid;
+```
+Options such as `Boot####` are defined by UEFI specification, therefore they have this predefined GUID = `EFI_GLOBAL_VARIABLE`. If you'll ever want to have your own options, you shouldn't use `EFI_GLOBAL_VARIABLE` for them, but instead create your own to eliminate a possibility of variable name conflicts.
+
+
+To look where GUID is defined in a edk2 codebase you could use something like this:
+```
+$ grep -i 4B37FE8 -r ./ --exclude-dir=Build
+```
+
+To sort variables by GUID you can simply save output of our program and perform `sort` on it in Linux shell:
+```
+$ cat guids.txt | sort
+```
+
+
+All the variables grouped by GUID with links to files with GUID definition:
+
+`8BE4DF61-93CA-11D2-AA0D-00E098032B8C` - `gEfiGlobalVariableGuid`
+
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Guid/GlobalVariable.h
+
+https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec
+```
+Boot0000
+Boot0001
+Boot0002
+Boot0003
+Boot0004
+BootCurrent
+BootOptionSupport
+BootOrder
+ConIn
+ConInDev
+ConOut
+ConOutDev
+ErrOut
+ErrOutDev
+Key0000
+Key0001
+Lang
+LangCodes
+OsIndicationsSupported
+PlatformLang
+PlatformLangCodes
+PlatformRecovery0000
+Timeout
+```
+
+`04B37FE8-F6AE-480B-BDD5-37D98C5E89AA` - `gEdkiiVarErrorFlagGuid`
+
+https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Include/Guid/VarErrorFlag.h
+
+https://github.com/tianocore/edk2/blob/master/MdeModulePkg/MdeModulePkg.dec
+```
+VarErrorFlag
+```
+
+`4C19049F-4137-4DD3-9C10-8B97A83FFDFA` - `gEfiMemoryTypeInformationGuid`
+
+https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Include/Guid/MemoryTypeInformation.h
+
+https://github.com/tianocore/edk2/blob/master/MdeModulePkg/MdeModulePkg.dec
+```
+MemoryTypeInformation
+```
+
+`5B446ED1-E30B-4FAA-871A-3654ECA36080` - `gEfiIp4Config2ProtocolGuid`
+
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/Ip4Config2.h
+
+https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec
+```
+525400123456
+```
+
+
+`EB704011-1402-11D3-8E77-00A0C969723B` - `gMtcVendorGuid`
+
+https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Include/Guid/MtcVendor.h
+
+https://github.com/tianocore/edk2/blob/master/MdeModulePkg/MdeModulePkg.dec
+```
+MTC
+```
+
+`59324945-EC44-4C0D-B1CD-9DB139DF070C` - `gEfiIScsiInitiatorNameProtocolGuid`
+
+https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Protocol/IScsiInitiatorName.h
+
+https://github.com/tianocore/edk2/blob/master/MdePkg/MdePkg.dec
+```
+Attempt 1
+Attempt 2
+Attempt 3
+Attempt 4
+Attempt 5
+Attempt 6
+Attempt 7
+Attempt 8
+```
+
+`158DEF5A-F656-419C-B027-7A3192C079D2` - `gShellVariableGuid`
+
+https://github.com/tianocore/edk2/blob/master/ShellPkg/Include/Guid/ShellVariableGuid.h
+
+https://github.com/tianocore/edk2/blob/master/ShellPkg/ShellPkg.dec
+```
+cwd
+debuglasterror
+lasterror
+nonesting
+path
+profiles
+uefishellsupport
+uefishellversion
+uefiversion
+```
+
+`4B47D616-A8D6-4552-9D44-CCAD2E0F4CF9` - `gIScsiConfigGuid`
+
+https://github.com/tianocore/edk2/blob/master/NetworkPkg/Include/Guid/IScsiConfigHii.h
+
+https://github.com/tianocore/edk2/blob/master/NetworkPkg/NetworkPkg.dec
+```
+InitialAttemptOrder
+```
+
+`0053D9D6-2659-4599-A26B-EF4536E631A9` - `gShellAliasGuid`
+
+https://github.com/tianocore/edk2/blob/master/ShellPkg/Include/Guid/ShellAliasGuid.h
+
+https://github.com/tianocore/edk2/blob/master/ShellPkg/ShellPkg.dec
+```
+cat
+cd..
+cd\
+copy
+del
+dir
+md
+mem
+mount
+move
+ren
+```
+