aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lesson_14/Conf/target.txt7
-rw-r--r--Lesson_14/README.md427
-rw-r--r--Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.c15
-rw-r--r--Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.inf18
-rw-r--r--Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.c105
-rw-r--r--Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.inf18
-rw-r--r--Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.c44
-rw-r--r--Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.inf22
-rw-r--r--Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.c46
-rw-r--r--Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.inf19
-rw-r--r--Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.c215
-rw-r--r--Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf21
-rw-r--r--Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c14
-rw-r--r--Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf19
-rw-r--r--Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.c10
-rw-r--r--Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.inf16
-rw-r--r--Lesson_14/UefiLessonsPkg/UefiLessonsPkg.dsc35
-rw-r--r--README.md2
18 files changed, 1053 insertions, 0 deletions
diff --git a/Lesson_14/Conf/target.txt b/Lesson_14/Conf/target.txt
new file mode 100644
index 0000000..c109dcf
--- /dev/null
+++ b/Lesson_14/Conf/target.txt
@@ -0,0 +1,7 @@
+ACTIVE_PLATFORM = UefiLessonsPkg/UefiLessonsPkg.dsc
+TARGET = RELEASE
+TARGET_ARCH = X64
+TOOL_CHAIN_CONF = Conf/tools_def.txt
+TOOL_CHAIN_TAG = GCC5
+BUILD_RULE_CONF = Conf/build_rule.txt
+
diff --git a/Lesson_14/README.md b/Lesson_14/README.md
new file mode 100644
index 0000000..abf8f44
--- /dev/null
+++ b/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
+```
+
diff --git a/Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.c b/Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.c
new file mode 100644
index 0000000..1f05899
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.c
@@ -0,0 +1,15 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
+ gST->ConOut->OutputString(gST->ConOut, L"Hello again!\n");
+ Print(L"Bye!\n");
+ return EFI_SUCCESS;
+}
diff --git a/Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.inf b/Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.inf
new file mode 100644
index 0000000..d65ca2e
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/HelloWorld/HelloWorld.inf
@@ -0,0 +1,18 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = HelloWorld
+ FILE_GUID = 2e55fa38-f148-42d3-af90-1be247323e30
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ HelloWorld.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
diff --git a/Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.c b/Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.c
new file mode 100644
index 0000000..32e9c43
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.c
@@ -0,0 +1,105 @@
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+typedef struct {
+ UINTN Signature;
+ /// All handles list of IHANDLE
+ LIST_ENTRY AllHandles;
+ /// List of PROTOCOL_INTERFACE's for this handle
+ LIST_ENTRY Protocols;
+ UINTN LocateRequest;
+ /// The Handle Database Key value when this handle was last created or modified
+ UINT64 Key;
+} IHANDLE;
+
+typedef struct {
+ UINTN Signature;
+ /// Link Entry inserted to mProtocolDatabase
+ LIST_ENTRY AllEntries;
+ /// ID of the protocol
+ EFI_GUID ProtocolID;
+ /// All protocol interfaces
+ LIST_ENTRY Protocols;
+ /// Registerd notification handlers
+ LIST_ENTRY Notify;
+} PROTOCOL_ENTRY;
+
+typedef struct {
+ UINTN Signature;
+ /// Link on IHANDLE.Protocols
+ LIST_ENTRY Link;
+ /// Back pointer
+ IHANDLE *Handle;
+ /// Link on PROTOCOL_ENTRY.Protocols
+ LIST_ENTRY ByProtocol;
+ /// The protocol ID
+ PROTOCOL_ENTRY *Protocol;
+ /// The interface value
+ VOID *Interface;
+ /// OPEN_PROTOCOL_DATA list
+ LIST_ENTRY OpenList;
+ UINTN OpenListCount;
+
+} PROTOCOL_INTERFACE;
+
+
+#define offsetof(a,b) ((INTN)(&(((a*)(0))->b)))
+
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ IHANDLE* MyHandle = ImageHandle;
+ Print(L"Signature: %c %c %c %c\n", (MyHandle->Signature >> 0) & 0xff,
+ (MyHandle->Signature >> 8) & 0xff,
+ (MyHandle->Signature >> 16) & 0xff,
+ (MyHandle->Signature >> 24) & 0xff);
+
+ Print(L"Back Protocol Interface Link: %p\n", MyHandle->Protocols.BackLink);
+ Print(L"Forward Protocol Interface Link: %p\n", MyHandle->Protocols.ForwardLink);
+
+ LIST_ENTRY *FirstLink = MyHandle->Protocols.ForwardLink;
+ LIST_ENTRY *CurrentLink = FirstLink;
+ do {
+ PROTOCOL_INTERFACE* MyProtocolInterface = container_of(CurrentLink, PROTOCOL_INTERFACE, Link);
+
+ Print(L"\n");
+ Print(L"Current Link: %p\n", CurrentLink);
+ Print(L"Signature: %x %x %x %x\n", (MyProtocolInterface->Signature >> 0) & 0xff,
+ (MyProtocolInterface->Signature >> 8) & 0xff,
+ (MyProtocolInterface->Signature >> 16) & 0xff,
+ (MyProtocolInterface->Signature >> 24) & 0xff);
+
+ Print(L"Back Link: %p\n", MyProtocolInterface->Link.BackLink);
+ Print(L"Forward Link: %p\n", MyProtocolInterface->Link.ForwardLink);
+ Print(L"GUID=%g\n", MyProtocolInterface->Protocol->ProtocolID);
+ CurrentLink = MyProtocolInterface->Link.ForwardLink;
+ } while (CurrentLink != FirstLink);
+
+ Print(L"________\n");
+ EFI_GUID **ProtocolGuidArray;
+ UINTN ArrayCount;
+ //EFI_STATUS Status = gBS->ProtocolsPerHandle(NULL, // Use this to test %r Print formatting option
+ EFI_STATUS Status = gBS->ProtocolsPerHandle(ImageHandle,
+ &ProtocolGuidArray,
+ &ArrayCount);
+
+ if (!EFI_ERROR(Status)) {
+ for (int i=0; i<ArrayCount; i++) {
+ Print(L"%g\n", ProtocolGuidArray[i]);
+ }
+ FreePool(ProtocolGuidArray);
+ } else {
+ Print(L"ProtocolsPerHandle error: %r\n", Status);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.inf b/Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.inf
new file mode 100644
index 0000000..34256ee
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/ImageHandle/ImageHandle.inf
@@ -0,0 +1,18 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ImageHandle
+ FILE_GUID = b68d3472-70c7-4928-841b-6566032e0a23
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ ImageHandle.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
diff --git a/Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.c b/Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.c
new file mode 100644
index 0000000..c45570e
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.c
@@ -0,0 +1,44 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/LoadedImage.h>
+#include <Library/DevicePathLib.h>
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;
+
+ Status = gBS->HandleProtocol(
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+
+ if (Status == EFI_SUCCESS) {
+ EFI_DEVICE_PATH_PROTOCOL* DevicePath;
+
+ Status = gBS->HandleProtocol(
+ ImageHandle,
+ &gEfiLoadedImageDevicePathProtocolGuid,
+ (VOID**) &DevicePath
+ );
+
+ if (Status == EFI_SUCCESS) {
+ Print(L"Image device: %s\n", ConvertDevicePathToText(DevicePath, FALSE, TRUE));
+ Print(L"Image file: %s\n", ConvertDevicePathToText(LoadedImage->FilePath, FALSE, TRUE)); // EFI_DEVICE_PATH_PROTOCOL *FilePath
+ Print(L"Image Base: %X\n", LoadedImage->ImageBase);
+ Print(L"Image Size: %X\n", LoadedImage->ImageSize);
+ } else {
+ Print(L"Can't get EFI_LOADED_IMAGE_PROTOCOL, Status=%r\n", Status);
+ }
+ } else {
+ Print(L"Can't get EFI_DEVICE_PATH_PROTOCOL, Status=%r\n", Status);
+ }
+ return EFI_SUCCESS;
+}
diff --git a/Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.inf b/Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.inf
new file mode 100644
index 0000000..0ce54a6
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/ImageInfo/ImageInfo.inf
@@ -0,0 +1,22 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ImageInfo
+ FILE_GUID = b68d3472-70c7-4928-841b-6566032e0a23
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ ImageInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
+[Protocols]
+ gEfiLoadedImageProtocolGuid
+ gEfiLoadedImageDevicePathProtocolGuid
+
diff --git a/Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.c b/Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.c
new file mode 100644
index 0000000..1f3ef4a
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.c
@@ -0,0 +1,46 @@
+#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;
+ }
+
+ 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;
+}
diff --git a/Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.inf b/Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.inf
new file mode 100644
index 0000000..14e9fa2
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/ListVariables/ListVariables.inf
@@ -0,0 +1,19 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = ListVariables
+ FILE_GUID = d66f68b2-3591-45af-bf5d-519152b9d877
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+[Sources]
+ ListVariables.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellCEntryLib
+
diff --git a/Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.c b/Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
new file mode 100644
index 0000000..8c3bcf2
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.c
@@ -0,0 +1,215 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+// for SetMem
+#include <Library/BaseMemoryLib.h>
+
+#include <Protocol/ShellParameters.h>
+
+const CHAR16 *memory_types[] = {
+ L"EfiReservedMemoryType",
+ L"EfiLoaderCode",
+ L"EfiLoaderData",
+ L"EfiBootServicesCode",
+ L"EfiBootServicesData",
+ L"EfiRuntimeServicesCode",
+ L"EfiRuntimeServicesData",
+ L"EfiConventionalMemory",
+ L"EfiUnusableMemory",
+ L"EfiACPIReclaimMemory",
+ L"EfiACPIMemoryNVS",
+ L"EfiMemoryMappedIO",
+ L"EfiMemoryMappedIOPortSpace",
+ L"EfiPalCode",
+ L"EfiPersistentMemory",
+ L"EfiMaxMemoryType"
+};
+
+
+const CHAR16 *memory_types_OS_view[] = {
+ L"reserved", // L"EfiReservedMemoryType",
+ L"usable", // L"EfiLoaderCode",
+ L"usable", // L"EfiLoaderData",
+ L"usable", // L"EfiBootServicesCode",
+ L"usable", // L"EfiBootServicesData",
+ L"reserved", // L"EfiRuntimeServicesCode",
+ L"reserved", // L"EfiRuntimeServicesData",
+ L"usable", // L"EfiConventionalMemory",
+ L"reserved", // L"EfiUnusableMemory",
+ L"ACPI data",// L"EfiACPIReclaimMemory",
+ L"ACPI NVS", // L"EfiACPIMemoryNVS",
+ L"reserved", // L"EfiMemoryMappedIO",
+ L"reserved", // L"EfiMemoryMappedIOPortSpace",
+ L"reserved", // L"EfiPalCode",
+ L"usable", // L"EfiPersistentMemory",
+ L"usable", // L"EfiMaxMemoryType"
+};
+
+
+const CHAR16 *
+memory_type_to_str(UINT32 type)
+{
+ if (type > sizeof(memory_types)/sizeof(CHAR16 *))
+ return L"Unknown";
+
+ return memory_types[type];
+}
+
+const CHAR16 *
+memory_type_to_str_OS_view(UINT32 type)
+{
+ if (type > sizeof(memory_types_OS_view)/sizeof(CHAR16 *))
+ return L"Unknown";
+
+ return memory_types_OS_view[type];
+}
+
+#define ATTRIBUTE_STR_SIZE 50
+
+#define CHECK_EFI_MEMORY_ATTRIBUTE(attr) if (attrs & EFI_MEMORY_##attr) { \
+ StrCpyS(&str[i], ATTRIBUTE_STR_SIZE, L" "#attr); \
+ i+=StrLen(L" "#attr); \
+ }
+
+const CHAR16 *
+memory_attrs_to_str(CHAR16* str, UINT64 attrs)
+{
+ int i=0;
+ SetMem((VOID *)str, sizeof(str), 0);
+
+ CHECK_EFI_MEMORY_ATTRIBUTE(UC)
+ CHECK_EFI_MEMORY_ATTRIBUTE(WC)
+ CHECK_EFI_MEMORY_ATTRIBUTE(WT)
+ CHECK_EFI_MEMORY_ATTRIBUTE(WB)
+ CHECK_EFI_MEMORY_ATTRIBUTE(UCE)
+ CHECK_EFI_MEMORY_ATTRIBUTE(WP)
+ CHECK_EFI_MEMORY_ATTRIBUTE(RP)
+ CHECK_EFI_MEMORY_ATTRIBUTE(XP)
+ CHECK_EFI_MEMORY_ATTRIBUTE(NV)
+ CHECK_EFI_MEMORY_ATTRIBUTE(MORE_RELIABLE)
+ CHECK_EFI_MEMORY_ATTRIBUTE(RO)
+ CHECK_EFI_MEMORY_ATTRIBUTE(SP)
+ CHECK_EFI_MEMORY_ATTRIBUTE(CPU_CRYPTO)
+ CHECK_EFI_MEMORY_ATTRIBUTE(RUNTIME)
+
+ return str;
+}
+
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ UINTN MemoryMapSize = 0;
+ EFI_MEMORY_DESCRIPTOR* MemoryMap = NULL;
+ UINTN MapKey;
+ UINTN DescriptorSize;
+ UINT32 DescriptorVersion;
+
+ EFI_STATUS Status;
+
+
+ EFI_SHELL_PARAMETERS_PROTOCOL* ShellParameters;
+
+ Status = gBS->HandleProtocol(
+ ImageHandle,
+ &gEfiShellParametersProtocolGuid,
+ (VOID **) &ShellParameters
+ );
+
+ BOOLEAN full=FALSE;
+ if (Status == EFI_SUCCESS) {
+ if (ShellParameters->Argc == 2) {
+ if (!StrCmp(ShellParameters->Argv[1], L"full")) {
+ full=TRUE;
+ }
+ }
+ }
+
+
+ Status = gBS->GetMemoryMap(
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Status = gBS->AllocatePool(
+ EfiBootServicesData,
+ MemoryMapSize,
+ (void**)&MemoryMap
+ );
+
+ if (EFI_ERROR(Status)) {
+ Print(L"AllocatePool error: %r\n", Status);
+ return Status;
+ }
+
+ Status = gBS->GetMemoryMap(
+ &MemoryMapSize,
+ MemoryMap,
+ &MapKey,
+ &DescriptorSize,
+ &DescriptorVersion
+ );
+
+ if (!EFI_ERROR(Status))
+ {
+ EFI_MEMORY_DESCRIPTOR* desc = MemoryMap;
+ EFI_MEMORY_DESCRIPTOR* next_desc;
+ int i = 0;
+ while ((UINT8 *)desc < (UINT8 *)MemoryMap + MemoryMapSize) {
+ UINTN PAGE_SIZE = 4096;
+ UINTN mapping_size =(UINTN) desc->NumberOfPages * PAGE_SIZE;
+
+ UINT64 Start = desc->PhysicalStart;
+
+ next_desc = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)desc + DescriptorSize);
+ if (!full) {
+ while ((UINT8 *)next_desc < (UINT8 *)MemoryMap + MemoryMapSize) {
+ mapping_size =(UINTN) desc->NumberOfPages * PAGE_SIZE;
+ if ((desc->PhysicalStart + mapping_size) == (next_desc->PhysicalStart)) {
+
+ if (desc->Type != next_desc->Type) {
+ if (StrCmp(memory_type_to_str_OS_view(desc->Type),
+ memory_type_to_str_OS_view(next_desc->Type)))
+ break;
+ }
+
+ desc=next_desc;
+ next_desc = (EFI_MEMORY_DESCRIPTOR *)((UINT8 *)next_desc + DescriptorSize);
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (full) {
+ CHAR16 str[ATTRIBUTE_STR_SIZE];
+ Print(L"[#%02d] Type: %s Attr: %s\n", i++,
+ memory_type_to_str(desc->Type), memory_attrs_to_str(str, desc->Attribute));
+ Print(L" Phys: %016llx-%016llx\n", Start, Start + mapping_size - 1);
+ }
+ else {
+ Print(L" [mem: %016llx-%016llx] %s\n", Start, desc->PhysicalStart + mapping_size - 1,
+ memory_type_to_str_OS_view(desc->Type) );
+ }
+
+ desc = next_desc;
+ }
+
+ gBS->FreePool(MemoryMap);
+ } else {
+ Print(L"GetMemoryMap with buffer error: %r\n", Status);
+ }
+ } else {
+ Print(L"GetMemoryMap without buffer error: %r\n", Status);
+ }
+
+ return Status;
+}
+
diff --git a/Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf b/Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
new file mode 100644
index 0000000..777010d
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
@@ -0,0 +1,21 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = MemoryInfo
+ FILE_GUID = d2ce1d65-603e-4b48-b3e1-fe65d5d0bca8
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ MemoryInfo.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+
+[Protocols]
+ gEfiShellParametersProtocolGuid
+
diff --git a/Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c b/Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c
new file mode 100644
index 0000000..b13aa6c
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.c
@@ -0,0 +1,14 @@
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+INTN EFIAPI ShellAppMain(IN UINTN Argc, IN CHAR16 **Argv)
+{
+// SystemTable->ConOut->OutputString(SystemTable->ConOut, L"Hello World!\n");
+ gST->ConOut->OutputString(gST->ConOut, L"Hello again!\n");
+ Print(L"Bye!\n");
+
+ for (UINTN i=Argc; i>0; i--) {
+ Print(L"Arg[%d]=%s\n", Argc-i, Argv[Argc-i]);
+ }
+ return 0;
+}
diff --git a/Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf b/Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
new file mode 100644
index 0000000..013bf4e
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
@@ -0,0 +1,19 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = SimpleShellApp
+ FILE_GUID = 2afd1202-545e-4f8d-b8fb-bc179e84ddc8
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = ShellCEntryLib
+
+[Sources]
+ SimpleShellApp.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
+ UefiLib
+ ShellCEntryLib
+
diff --git a/Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.c b/Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.c
new file mode 100644
index 0000000..8bdf500
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.c
@@ -0,0 +1,10 @@
+EFI_STATUS
+EFIAPI
+UefiMain (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EFI_SUCCESS;
+}
+
diff --git a/Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.inf b/Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.inf
new file mode 100644
index 0000000..7d4bae2
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/SimplestApp/SimplestApp.inf
@@ -0,0 +1,16 @@
+[Defines]
+ INF_VERSION = 1.25
+ BASE_NAME = SimplestApp
+ FILE_GUID = 4a298956-fbe0-47fb-ae3a-2d5a0a959a26
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ ENTRY_POINT = UefiMain
+
+[Sources]
+ SimplestApp.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ UefiApplicationEntryPoint
diff --git a/Lesson_14/UefiLessonsPkg/UefiLessonsPkg.dsc b/Lesson_14/UefiLessonsPkg/UefiLessonsPkg.dsc
new file mode 100644
index 0000000..dbe9b17
--- /dev/null
+++ b/Lesson_14/UefiLessonsPkg/UefiLessonsPkg.dsc
@@ -0,0 +1,35 @@
+[Defines]
+ DSC_SPECIFICATION = 0x0001001C
+ PLATFORM_GUID = 3db7270f-ffac-4139-90a4-0ae68f3f8167
+ PLATFORM_VERSION = 0.01
+ PLATFORM_NAME = UefiLessonsPkg
+ SKUID_IDENTIFIER = DEFAULT
+ SUPPORTED_ARCHITECTURES = X64
+ BUILD_TARGETS = RELEASE
+
+
+[LibraryClasses]
+ UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ ShellCEntryLib|ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.inf
+
+[Components]
+ UefiLessonsPkg/SimplestApp/SimplestApp.inf
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
+ UefiLessonsPkg/ImageHandle/ImageHandle.inf
+ UefiLessonsPkg/ImageInfo/ImageInfo.inf
+ UefiLessonsPkg/MemoryInfo/MemoryInfo.inf
+ UefiLessonsPkg/SimpleShellApp/SimpleShellApp.inf
+ UefiLessonsPkg/ListVariables/ListVariables.inf
+
diff --git a/README.md b/README.md
index f3c40b0..161d05b 100644
--- a/README.md
+++ b/README.md
@@ -16,3 +16,5 @@ Lessons description:
- Lesson 11: Get EFI memory map information
- Lesson 12: `EFI_SHELL_PARAMETERS_PROTOCOL`. Transform our EFI memory map to the Linux kernel style
- Lesson 13: `ShellAppMain` entry point
+- Lesson 14: Get all variable names and GUIDs with the `gRT->GetNextVariableName` API
+